Antwa CodeAntwaCode Blog

Rekayasa2 menit baca

Docker untuk Developer PHP/Laravel: Panduan Lengkap

Panduan lengkap Docker untuk developer PHP/Laravel dari nol.

Baca dalam English

Pendahuluan

Halo, developer! Pernahkah kamu mengalami masalah ini: kode yang jalan di laptopmu nggak jalan di laptop temanmu? Atau frustasi karena harus install MySQL, Redis, Nginx, dan PHP versi tertentu secara manual? Tenang, kamu nggak sendirian. Masalah "it works on my machine" hampir semua developer pernah mengalaminya.

Di sinilah Docker hadir sebagai solusi. Docker memungkinkan kita mengemas aplikasi beserta dependensinya ke dalam container yang bisa dijalankan di mana saja secara konsisten. Gampangnya: kalau jalan di satu mesin, dijamin jalan di manapun.

Di tutorial ini, kita belajar Docker dari nol khusus untuk PHP/Laravel — dari pengertian dasar sampai setup production-ready. Siap? Gas!

Apa Itu Docker?

Docker adalah platform open-source untuk mengembangkan dan menjalankan aplikasi di dalam container. Container mirip virtual machine, tapi jauh lebih ringan karena berbagi kernel OS yang sama dengan host-nya.

Docker vs Virtual Machine

AspekVirtual MachineDocker Container
UkuranGB-anMB (ringan)
StartupMenit-anDetik-an
IsolasiFull OSAplikasi + dependencies
Resource UsageBorosEfisien

Konsep Penting

  1. Image — Blueprint/template berisi semua yang dibutuhkan untuk menjalankan aplikasi. Seperti resep masakan.
  2. Container — Instance dari image yang sudah berjalan.
  3. Dockerfile — File teks berisi instruksi untuk membangun image.
  4. Docker Compose — Tool untuk menjalankan aplikasi multi-container (app + MySQL + Redis sekaligus).
  5. Volume — Mekanisme penyimpanan data persisten di luar container.

Instalasi Docker

Linux (Ubuntu/Debian)

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
 
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
    sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
 
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
 
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
    docker-buildx-plugin docker-compose-plugin
 
sudo usermod -aG docker $USER

macOS / Windows

Download Docker Desktop dari docker.com/products/docker-desktop. Di Windows, pastikan WSL 2 sudah aktif.

Verifikasi

docker --version
docker run hello-world
docker compose version

Kalau muncul "Hello from Docker!" — selamat! Docker sudah siap. 🎉

Memahami Dockerfile

Dockerfile adalah resep untuk membangun Docker image. Berikut contoh untuk PHP:

FROM php:8.2-fpm
 
RUN apt-get update && apt-get install -y \
    git curl libpng-dev libonig-dev libxml2-dev libzip-dev unzip \
    && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip \
    && apt-get clean && rm -rf /var/lib/apt/lists/*
 
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader
RUN chown -R www-data:www-data /var/www/html
 
EXPOSE 9000
CMD ["php-fpm"]
PerintahFungsi
FROMBase image
RUNPerintah shell saat build
COPYSalin file host ke container
WORKDIRWorking directory
EXPOSEDeklarasi port
CMDPerintah default saat container jalan

Build image:

docker build -t my-laravel-app:1.0 .
docker images | grep my-laravel-app

Docker Compose: Multi-Container Setup

Aplikasi Laravel butuh MySQL, Redis, dan Nginx. Docker Compose menjalankan semua sekaligus dalam satu file konfigurasi.

Struktur Folder

laravel-docker/
├── app/
├── docker/
│   ├── nginx/default.conf
│   ├── php/Dockerfile
│   └── node/Dockerfile
├── docker-compose.yml
└── .env

docker-compose.yml

services:
  app:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    container_name: laravel-app
    restart: unless-stopped
    working_dir: /var/www/html
    volumes:
      - .:/var/www/html
      - ./docker/php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - laravel-network
    depends_on:
      - mysql
      - redis
 
  nginx:
    image: nginx:alpine
    container_name: laravel-nginx
    ports:
      - "8080:80"
    volumes:
      - .:/var/www/html
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    networks:
      - laravel-network
    depends_on:
      - app
 
  mysql:
    image: mysql:8.0
    container_name: laravel-mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel_db
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_USER: laravel_user
      MYSQL_PASSWORD: secret
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - laravel-network
 
  redis:
    image: redis:alpine
    container_name: laravel-redis
    ports:
      - "6379:6379"
    networks:
      - laravel-network
 
  queue:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    container_name: laravel-queue
    working_dir: /var/www/html
    volumes:
      - .:/var/www/html
    networks:
      - laravel-network
    depends_on:
      - redis
      - mysql
    command: ["php", "artisan", "queue:work", "--sleep=3", "--tries=3"]
 
volumes:
  mysql-data:
 
networks:
  laravel-network:
    driver: bridge

Nginx Config

File docker/nginx/default.conf:

server {
    listen 80;
    server_name localhost;
    root /var/www/html/public;
    index index.php index.html;
 
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
 
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

PHP-FPM Dockerfile

File docker/php/Dockerfile:

FROM php:8.2-fpm
 
RUN apt-get update && apt-get install -y \
    git curl libpng-dev libonig-dev libxml2-dev libzip-dev unzip \
    && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip \
    && apt-get clean && rm -rf /var/lib/apt/lists/*
 
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 
RUN groupadd -g 1000 www && useradd -u 1000 -ms /bin/bash -g www www
 
WORKDIR /var/www/html
COPY --chown=www:www . /var/www/html
 
USER www
EXPOSE 9000
CMD ["php-fpm"]

PHP Custom Config

File docker/php/local.ini:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 60
display_errors = On
error_reporting = E_ALL

Menggunakan Docker Compose

Perintah Dasar

# Build dan jalankan semua container
docker compose up -d --build
 
# Lihat status
docker compose ps
 
# Lihat log
docker compose logs -f app
 
# Stop semua container
docker compose down
 
# Stop dan hapus data
docker compose down -v

Akses Container

# Masuk ke container PHP
docker compose exec app bash
 
# Jalankan artisan
docker compose exec app php artisan migrate
docker compose exec app php artisan cache:clear
docker compose exec app php artisan tinker
 
# Jalankan composer
docker compose exec app composer install
 
# Masuk ke MySQL
docker compose exec mysql mysql -u root -p

Setup Laravel Project Baru

composer create-project laravel/laravel laravel-docker
cd laravel-docker
 
mkdir -p docker/nginx docker/php docker/node docker/mysql
 
# Copy file konfigurasi Docker dari contoh di atas
 
docker compose up -d --build
# Akses: http://localhost:8080

Konfigurasi .env

APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8080
 
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=secret
 
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
 
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

Catatan penting: DB_HOST harus mysql (nama service), bukan localhost. Laravel berjalan di container terpisah yang terhubung via Docker network.

Development Workflow

Hot Reload dengan Bind Mount

Dengan bind mount (.:/var/www/html), perubahan kode di host langsung terlihat di container tanpa rebuild.

# Edit kode di host → langsung terlihat di browser
 
# Jika ada perubahan .env:
docker compose exec app php artisan config:clear

Database Management

docker compose exec app php artisan migrate
docker compose exec app php artisan migrate:fresh --seed
docker compose exec app php artisan make:migration create_posts_table
docker compose exec app php artisan make:model Post -mcr

Scheduler

# Tambahkan di docker-compose.yml:
  scheduler:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    container_name: laravel-scheduler
    working_dir: /var/www/html
    volumes:
      - .:/var/www/html
    networks:
      - laravel-network
    command: >
      sh -c "while true; do
        php /var/www/html/artisan schedule:run --verbose --no-interaction;
        sleep 60;
      done"

Production Setup

Multi-Stage Dockerfile

# Stage 1: Composer
FROM composer:latest AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-interaction --prefer-dist
COPY . .
RUN composer dump-autoload --optimize --no-dev
 
# Stage 2: Frontend
FROM node:20-alpine AS frontend
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
 
# Stage 3: Production
FROM php:8.2-fpm AS production
RUN apt-get update && apt-get install -y \
    libpng-dev libonig-dev libxml2-dev libzip-dev unzip \
    && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip \
    && apt-get clean && rm -rf /var/lib/apt/lists/*
 
COPY --from=vendor /app/vendor /var/www/html/vendor
COPY --from=frontend /app/public/build /var/www/html/public/build
COPY . /var/www/html
 
RUN chown -R www-data:www-data /var/www/html
WORKDIR /var/www/html
 
RUN php artisan config:cache && php artisan route:cache \
    && php artisan view:cache && php artisan event:cache
 
EXPOSE 9000
CMD ["php-fpm"]

Jalankan:

docker compose -f docker-compose.prod.yml up -d --build

Tips dan Trik

.dockerignore

node_modules
.git
.env
storage/logs/*
vendor
*.md
.vscode
.idea

Health Check

HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://localhost:9000/health || exit 1

Backup Database

docker compose exec -T mysql mysqldump -u root -p secret laravel_db > backup.sql
docker compose exec mysql mysql -u root -p secret laravel_db < backup.sql

Debugging

docker compose logs -f app          # Real-time logs
docker stats                        # Resource usage
docker compose exec app bash        # Masuk ke container
docker system prune -af --volumes   # Bersihkan semua

Troubleshooting

MasalahSolusi
Port sudah dipakaiGanti port: 8081:80
Permission denieddocker compose exec app chown -R www-data:www-data storage bootstrap/cache
MySQL connection gagalPastikan DB_HOST=mysql (bukan localhost)
Image terlalu besarGunakan multi-stage build + .dockerignore
Container restart terusCek log: docker compose logs -f <service>

Kesimpulan

Docker memang terasa ribet di awal, tapi investasi waktunya sangat worth it:

  • ✅ Tim satu setup environment-nya
  • ✅ Onboarding developer baru lebih cepat
  • ✅ Deploy ke production lebih konsisten
  • ✅ Problem "works on my machine" hilang selamanya

Mulai dari local development dengan Docker Compose, lalu perlahan pelajari production deployment. Ambil satu per satu — jangan overwhelming sekaligus!

Selamat coding! 🚀

Referensi

Tulisan lain