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
| Aspek | Virtual Machine | Docker Container |
|---|---|---|
| Ukuran | GB-an | MB (ringan) |
| Startup | Menit-an | Detik-an |
| Isolasi | Full OS | Aplikasi + dependencies |
| Resource Usage | Boros | Efisien |
Konsep Penting
- Image — Blueprint/template berisi semua yang dibutuhkan untuk menjalankan aplikasi. Seperti resep masakan.
- Container — Instance dari image yang sudah berjalan.
- Dockerfile — File teks berisi instruksi untuk membangun image.
- Docker Compose — Tool untuk menjalankan aplikasi multi-container (app + MySQL + Redis sekaligus).
- 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 $USERmacOS / 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 versionKalau 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"]| Perintah | Fungsi |
|---|---|
FROM | Base image |
RUN | Perintah shell saat build |
COPY | Salin file host ke container |
WORKDIR | Working directory |
EXPOSE | Deklarasi port |
CMD | Perintah default saat container jalan |
Build image:
docker build -t my-laravel-app:1.0 .
docker images | grep my-laravel-appDocker 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
└── .envdocker-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: bridgeNginx 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_ALLMenggunakan 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 -vAkses 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 -pSetup 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:8080Konfigurasi .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=6379Catatan 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:clearDatabase 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 -mcrScheduler
# 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 --buildTips dan Trik
.dockerignore
node_modules
.git
.env
storage/logs/*
vendor
*.md
.vscode
.ideaHealth Check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:9000/health || exit 1Backup 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.sqlDebugging
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 semuaTroubleshooting
| Masalah | Solusi |
|---|---|
| Port sudah dipakai | Ganti port: 8081:80 |
| Permission denied | docker compose exec app chown -R www-data:www-data storage bootstrap/cache |
| MySQL connection gagal | Pastikan DB_HOST=mysql (bukan localhost) |
| Image terlalu besar | Gunakan multi-stage build + .dockerignore |
| Container restart terus | Cek 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
- Docker Documentation
- Laravel Documentation
- Docker Compose
- Laravel Sail — Docker setup bawaan Laravel
- Docker Hub
Tulisan lain
CI/CD Pipeline dengan GitHub Actions: Tutorial Lengkap
· 7 menit baca
Database Design Patterns yang Wajib Diketahui Developer
· 7 menit baca
Microservices vs Monolith: Pilih yang Mana?
· 10 menit baca