Proyek ini adalah proyek pertama kita yang tidak menulis satu baris Dockerfile pun. Tiga proyek sebelumnya selalu bermuara pada berkas resep — situs statis dikemas ke image nginx, API Go dikompilasi lewat multi-stage build, service Rust dibangun bertingkat — sementara di sini kedua komponen sudah tersedia sebagai image resmi siap pakai: wordpress:6.8-apache untuk aplikasi lengkap dengan web server-nya, dan mysql:8.4 untuk database. Kecerdasan proyek justru pindah tempat, dari Dockerfile ke compose.yaml: bagaimana dua service dihubungkan, kredensial disuntikkan tanpa bocor ke repositori, data dipersist-kan pada dua volume terpisah, dan urutan penyalaan dijaga sebuah healthcheck. Peran kita berubah dari penulis resep menjadi perancang konfigurasi — keterampilan yang sama pentingnya di dunia nyata, karena mayoritas stack produksi memang dirangkai dari image jadi, bukan dibangun dari nol.

Apa yang Kita Bangun #

Kita berperan sebagai pengelola Toko Kopi Kita, kedai kopi yang ingin punya situs web berisi cerita dan menu tanpa harus memasang PHP, Apache, dan MySQL di mesin host. Stack yang kita bangun memiliki karakter berikut:

  • situs WordPress 6.8 yang berjalan utuh dalam container — aplikasi, PHP, dan Apache menyatu dalam satu image resmi, tanpa satu baris RUN pun kita tulis,
  • service db MySQL 8.4 (seri LTS) yang menyala lebih dulu dan dijaga healthcheck mysqladmin ping, sehingga WordPress tidak pernah menyala menghadapi database yang setengah siap,
  • dua volume terpisah: db-data untuk isi database dan wp-content untuk tema, plugin, serta unggahan — masing-masing dengan alat backup yang berbeda,
  • kredensial yang hidup di .env (disalin dari .env.example), dijaga interpolasi fail-fast ${VAR:?pesan} dan .gitignore, sehingga stack menolak menyala bila sandi belum disiapkan,
  • resep backup dan restore untuk kedua dunia data — mysqldump untuk tabel, tar untuk berkas — yang diuji lewat disaster drill: menghapus seluruh data dengan sadar lalu membangkitkannya kembali dari arsip.

Hasil Akhir dalam Dua Perintah #

Seluruh proyek bermuara pada dua perintah berikut, dijalankan dari dalam folder proyek setelah keempat bagian selesai — di antara keduanya cukup satu penyuntingan kecil untuk mengganti dua sandi di .env:

bash
$ cp .env.example .env
$ docker compose up -d

Output yang Dihasilkan:

text
[+] Pulling 2/2
 ✔ db Pulled                                           21.6s
 ✔ wordpress Pulled                                    13.1s
[+] Running 3/3
 ✔ Network wordpress-dan-mysql_default        Created                         0.2s
 ✔ Container wordpress-dan-mysql-db-1         Healthy                         11.4s
 ✔ Container wordpress-dan-mysql-wordpress-1  Started                         1.9s

Baris Healthy pada db adalah jantung stack ini: Compose menunggu database benar-benar siap — inisialisasi volume pertama memakan 11,4 detik — sebelum menghidupkan WordPress. Setelah kedua container menyala, browser tinggal diarahkan ke localhost:8090, dan wizard instalasi berjalan dalam empat langkah: pilih bahasa, isi judul situs Toko Kopi Kita beserta akun admin budi, klik pasang, lalu masuk ke dashboard. Tidak ada halaman pengisian koneksi database di wizard itu — wp-config.php sudah ditulis otomatis oleh entrypoint image dari variabel WORDPRESS_DB_*, mekanisme yang kita bedah tuntas di Bagian 1.

Tujuan Pembelajaran #

Setelah menyelesaikan proyek ini, kita mampu:

  • menyusun stack multi-service yang utuh dari image resmi, tanpa membangun image sendiri,
  • menjelaskan mekanisme entrypoint image WordPress yang menerjemahkan WORDPRESS_DB_* menjadi wp-config.php,
  • mengelola kredensial dengan pola .env.example → .env, interpolasi ${VAR:?pesan}, dan .gitignore,
  • merancang healthcheck dengan tanda dolar terpelihara ($$) serta gerbang depends_on bertipe service_healthy,
  • membedakan volume wp-content dan db-data, membuktikan persistensinya, lalu mencadangkan dan memulihkan keduanya lewat disaster drill.

Prasyarat #

Proyek ini tidak memperkenalkan materi baru; ia merangkai yang lama dengan sudut yang berbeda. Tiga section menjadi bekal utama:

  • Docker Compose — struktur compose.yaml, environment, .env untuk interpolasi, depends_on, dan healthcheck service dari chapter Struktur compose.yaml, Environment dan env File, Variable Interpolation, depends_on dan Startup Order, serta Healthcheck dan Service Readiness,
  • Penyimpanan Data — konsep persistence dan perilaku volume bernama dari chapter Konsep Persistence dan Volume,
  • Docker dan Database — ritual image MySQL, inisialisasi, dan pola backup/restore dari chapter Menjalankan MySQL, Inisialisasi Database, Backup Database, dan Restore Database.

Pastikan juga Docker Engine 29.9.0 dengan plugin Compose v5.6.0 terpasang, koneksi cukup untuk menarik dua image resmi yang berukuran ratusan megabyte, dan tersedia browser — wizard instalasi serta halaman admin WordPress hanya bisa kita jalani lewat browser, bukan lewat curl.

Peta File Proyek #

Struktur lengkap proyek yang kita bangun:

text
wordpress-dan-mysql/
├── compose.yaml
├── .env.example
├── .gitignore
└── README.md

Peran setiap berkas dan bagian tempat ia lahir:

BerkasPeranBagian
compose.yamlService db (mysql:8.4) dan wordpress (wordpress:6.8-apache), healthcheck, dua volumeBagian 1
.env.exampleTemplate kredensial yang disalin menjadi .envBagian 1
.gitignoreMenahan .env agar tidak ter-commitBagian 1
README.mdRingkasan cara menjalankan, backup, restore, dan disaster drill—

Tahapan #

Proyek dikerjakan dalam empat bagian berurutan. Setiap bagian berdiri di atas konfigurasi bagian sebelumnya:

  1. Bagian 1: Menyiapkan Service — compose.yaml lengkap kedua service, mekanisme WORDPRESS_DB_* menuju wp-config.php, .env.example dengan gerbang fail-fast, hingga stack pertama menyala dan wizard empat langkah selesai.
  2. Bagian 2: Mengonfigurasi Database — bedah empat variabel MYSQL_*, healthcheck dengan $$ yang dijelaskan tuntas, dan pembuktian least privilege: akun root versus akun aplikasi wordpress.
  3. Bagian 3: Volume dan Persistence — dua volume dipisah, bukti ditanam di kedua dunia (post dan unggahan), diuji dengan siklus down dan up, lalu diperiksa dari luar lewat docker volume.
  4. Bagian 4: Backup dan Restore — mysqldump dan tar dijadikan ritual, otomasi cron dan rotasi arsip, lalu disaster drill yang menghapus segalanya dan membangkitkan situs dari dua berkas backup.

Mulailah dari Bagian 1 dan pertahankan urutannya: pembuktian volume di Bagian 3 hanya bermakna bila wizard di Bagian 1 sudah kita lalui, dan disaster drill di Bagian 4 menagih data yang ditanam di Bagian 3.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

compose.yaml

Unduh berkas
yaml
# WordPress + MySQL: dua service jadi, dua volume, tanpa Dockerfile.
# Nama proyek Compose otomatis diambil dari nama folder karena berkas
# ini sengaja tidak memakai kunci `name:`.

services:
  db:
    image: mysql:8.4
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD wajib diisi lewat .env}"
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: "${MYSQL_PASSWORD:?MYSQL_PASSWORD wajib diisi lewat .env}"
    volumes:
      - db-data:/var/lib/mysql
    healthcheck:
      # $$ membuat dolar lolos dari interpolasi Compose; shell di dalam
      # container yang mengekspansi $MYSQL_ROOT_PASSWORD saat test berjalan.
      test: ["CMD-SHELL", "mysqladmin ping -h localhost -p$$MYSQL_ROOT_PASSWORD"]
      interval: 3s
      timeout: 3s
      retries: 20
      start_period: 30s

  wordpress:
    image: wordpress:6.8-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8090:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: "${MYSQL_PASSWORD:?MYSQL_PASSWORD wajib diisi lewat .env}"
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp-content:/var/www/html/wp-content

volumes:
  db-data:
  wp-content: