Siklus pengembangan katalog kini berjalan mulus: stack menyala dengan tiga service inti, develop.watch menjaga suntingan kode, dan profil menyimpan peralatan insiden. Pekerjaan sehari-hari kemudian bergeser ke rutinitas yang lebih rendah tapi jauh lebih sering — memeriksa apakah stack sehat, mengikuti log saat menguji satu fitur, masuk ke container untuk melihat isi filesystem, menghentikan satu service tanpa membongkar yang lain, dan membongkar semuanya dengan aman di akhir hari. Compose menyediakan kurang dari dua puluh perintah untuk seluruh kebutuhan itu, dan hampir semuanya sudah kita jumpai sekali-sekali di chapter-chapter sebelumnya. Chapter ini menyusun semuanya menjadi satu peta yang utuh — lengkap dengan output realistisnya, perilaku tepat tiap perintah, dan satu pembedaan yang paling sering menjebak: restart bukanlah cara membaca ulang compose.yaml yang berubah.
Peta Perintah Harian #
Tabel berikut adalah seluruh perintah yang menemani hari-hari Budi mengelola katalog. Kolom contoh memakai nama service web dan db dari stack kita:
| Perintah | Fungsi | Contoh |
|---|---|---|
up | menyelaraskan daemon dengan compose.yaml | docker compose up -d |
up --build | menyelaraskan sambil membangun ulang image | docker compose up -d --build |
ps | daftar container project yang berjalan | docker compose ps |
ps -a | termasuk container sekali jalan dari run | docker compose ps -a |
logs | log gabungan seluruh service | docker compose logs --tail=20 |
logs -f | mengikuti log satu service secara langsung | docker compose logs -f --tail=20 web |
exec | menjalankan perintah di container yang hidup | docker compose exec web sh |
run | container baru sekali jalan dari cetakbiru service | docker compose run --rm web node --version |
restart | menghentikan lalu menyalakan container yang sama | docker compose restart web |
stop | menghentikan service tanpa membuang containernya | docker compose stop web |
start | menyalakan kembali service yang berhenti | docker compose start web |
down | membongkar container dan network project | docker compose down |
down -v | sama, ditambah membuang volume bernama | docker compose down -v |
rm | membuang container yang sudah berhenti | docker compose rm -f |
pull | menarik image seluruh service yang dideklarasikan | docker compose pull |
build | membangun image service ber-build | docker compose build |
config | merender dan memvalidasi berkas | docker compose config |
ls | daftar seluruh project yang berjalan di daemon | docker compose ls |
watch | mengaktifkan aturan develop.watch | docker compose watch |
Sebagian besar baris pada tabel itu adalah padanan perintah Docker yang kita kuasai dari Section Dasar Docker CLI — ps menggantikan docker ps, logs menggantikan docker logs, exec menggantikan docker exec — dengan satu perbedaan mendasar: seluruhnya otomatis terbatas pada container milik project, tanpa satu nama container yang perlu diketik panjang. Bagian-bagian berikut membedah perintah-perintah kunci beserta keluaran aslinya.
Membaca Kondisi Stack #
Pagi dimulai dengan satu pertanyaan: apakah semuanya sehat? Jawabannya satu perintah:
$ docker compose psOutput yang Dihasilkan:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
katalog-db-1 postgres:18-alpine "docker-entrypoint.s…" db 4 minutes ago Up 4 minutes (healthy) 5432/tcp
katalog-web-1 katalog-web "node --watch src/ser…" web 4 minutes ago Up 4 minutes (healthy) 0.0.0.0:8080->3000/tcp
katalog-proxy-1 nginx:1.29-alpine "/docker-entrypoint.…" proxy 4 minutes ago Up 4 minutes 0.0.0.0:8090->80/tcpMari kita telaah kolom-kolom khas Compose pada tabel di atas:
- Kolom
SERVICE— tanda tangandocker compose psyang tidak dimilikidocker ps; identitas container di sini adalah cetakbirunya, bukan imagenya, dan kolom inilah yang membuat tiga replika dari satu service tetap mudah dibedakan asalnya. - Kolom
NAMEmengikuti pola<project>-<service>-<index>—katalog-web-1adalah instansiasi pertama dari servicewebpada projectkatalog, pola yang kita bedah pada Chapter Service. - Kolom
STATUSmemuat hasil healthcheck —(healthy)padadbdanwebadalah lencana dari probe yang kita bangun pada Chapter Healthcheck dan Service Readiness;proxytampil polos karena memang tidak membawa healthcheck. - Kolom
COMMANDmenampilkan perintah yang sedang berjalan —node --watch src/server.jspadawebberasal daricommandyang kita pasang pada Chapter Compose Watch, sementara dua service lain menjalankan entrypoint bawaan imagenya. - Kolom
PORTS— pemetaan0.0.0.0:8080->3000/tcpmilikwebdan8090->80milikproxy;dbhanya mencantumkan5432/tcpsebagai metadata port internal yang tidak diterbitkan ke host.
Dari pandangan yang lebih tinggi, docker compose ls memperlihatkan seluruh project yang sedang hidup di daemon — jawaban untuk pertanyaan “stack apa saja yang menyala di mesin ini?”:
$ docker compose lsOutput yang Dihasilkan:
NAME STATUS FILES
katalog running(3) /home/budi/katalog/compose.yamlStatus running(3) menghitung tiga container hidup di bawah project katalog, dan FILES menunjuk berkas deklarasi yang menjadi sumber kebenarannya — dua kolom yang akan semakin menarik ketika satu mesin menampung lebih dari satu project pada chapter berikutnya.
Mengikuti Log Sebuah Service #
Menguji satu fitur berarti mengawasi satu service. Perintah berikut menempelkan terminal ke log web dengan dua pengaturan sekaligus:
$ docker compose logs -f --tail=20 webOutput yang Dihasilkan:
katalog-web-1 | katalog web mendengarkan di port 3000
katalog-web-1 | GET / 200 4ms
katalog-web-1 | GET /healthz 200 1ms
katalog-web-1 | GET /jam 200 0ms
katalog-web-1 | GET / 200 3ms
...Mari kita telaah tiga perilaku pada keluaran tersebut:
- Setiap baris diawali nama container pengirimnya —
katalog-web-1tampil sebagai prefiks karena log gabungan bisa saja berdatangan dari banyak service; pada terminal sungguhan, Compose mewarnai prefiks tiap service dengan warna berbeda sehingga arus log terbaca sekilas pandang. --tail=20membatasi riwayat awal — hanya dua puluh baris terakhir yang dicetak sebelum pemantauan dimulai, sehingga log lama tidak membanjiri layar; tanpa flag ini, seluruh riwayat log container ikut tercetak.-fmengikuti arus secara langsung — terminal menempel pada arus log sampai Ctrl+C ditekan; tanpa-f, perintah mencetak riwayat lalu keluar — pola yang pas untuk membaca “apa yang terjadi tadi” setelah sebuah kejadian.
Perintah tanpa nama service — docker compose logs — menggabungkan log seluruh service sekaligus; itu tampilan yang kita saksikan sejak up interaktif pada Chapter Pengantar Docker Compose.
Masuk ke Container yang Berjalan #
Kadang mata harus melihat isi container sendiri. docker compose exec membuka shell pada container service yang sedang hidup:
$ docker compose exec web shOutput yang Dihasilkan:
/app $ pwd
/app
/app $ ls
node_modules
package.json
src
/app $ exitMari kita telaah sesi singkat di atas:
- Prompt membuka di
/app— direktori kerja bawaan berasal dariWORKDIRpada Dockerfile image, padanan deklaratif flag-wyang kita bedah pada Chapter Working Directory;execselalu memulai dari titik yang sama dengan proses utama container. - Isi direktori mencerminkan image —
package.json,src, dannode_moduleshasilRUN npm install; tidak ada berkas host lain karena servicewebtidak memasang bind mount source. - Sesi berjalan di container yang sama yang melayani permintaan — environment, network, dan identitas proses semuanya milik container hidup itu; perintah
printenv DATABASE_URLdi sesi yang sama akan menunjukkan nilai dari Chapter Environment dan env File. exitmelepaskan sesi tanpa mematikan container — container tetap melayani permintaan seolah tidak pernah dimasuki.
restart Bukan Membaca Ulang Berkas #
Inilah pembedaan yang paling sering menjebak. Budi menambahkan satu variabel percobaan TEMA: gelap pada blok environment service web, lalu — terbawa kebiasaan — menjalankan restart:
$ docker compose restart webOutput yang Dihasilkan:
[+] Restarting 1/1
✔ Container katalog-web-1 Restarted$ docker compose exec web printenv TEMA; echo "exit code: $?"Output yang Dihasilkan:
exit code: 1Variabel itu tidak ada. Perintah yang benar untuk menerapkan perubahan berkas adalah up:
$ docker compose up -dOutput yang Dihasilkan:
[+] Running 3/3
✔ Container katalog-db-1 Running
✔ Container katalog-web-1 Recreated
✔ Container katalog-web-1 Started$ docker compose exec web printenv TEMAOutput yang Dihasilkan:
gelapMari kita telaah mengapa keduanya berbeda:
restartmenghentikan lalu menyalakan container yang sama — konfigurasi container dibekukan pada saat penciptaannya; kataRestartedberarti proses yang sama berjalan ulang dengan environment yang lama.exit code: 1dariprintenv— utilitas ini keluar tanpa output ketika variabelnya tidak ditemukan, dan kode keluarnya memberi tahu kegagalannya; mekanisme exit code yang kita bedah pada Chapter Memahami Exit Code bekerja persis sama di dalam container.up -dmembandingkan deklarasi dengan keadaan daemon — perbedaan padaenvironmentmembuat container lama tidak lagi cocok, sehingga Compose menciptakan ulang: kata kuncinyaRecreated, bukanRestarted.- Bukti fisiknya ada pada kolom
CREATED— setelahrestart,docker compose psmasih menunjukkan waktu penciptaan yang lama dengan statusUpyang baru; setelahup -d, keduanya sama-sama segar. - Aturan praktisnya —
restartuntuk proses yang menggantung atau perlu dinyalakan ulang tanpa alasan konfigurasi;up -duntuk setiap perubahan compose.yaml. Budi menghapus kembali barisTEMApercobaan itu dan menyelaraskan dengan satuup -dlagi.
Perintah stop dan start adalah pasangan yang lebih lembut: docker compose stop web menghentikan service tanpa membuang containernya, dan docker compose start web menyalakannya kembali dengan konfigurasi yang sama — berguna untuk menghemat sumber daya saat sebuah service tidak dibutuhkan sementara, tanpa kehilangan status apapun yang menempel padanya.
Perintah Sekali Jalan dengan run #
Ada satu kebutuhan yang tidak terjawab exec: menjalankan perintah pada cetakbiru service ketika container utamanya tidak berjalan — atau ketika kita tidak ingin menyentuhnya. docker compose run menciptakan container baru dari konfigurasi service, menjalankan perintah, lalu selesai:
$ docker compose run web node --versionOutput yang Dihasilkan:
v22.20.0Container sekali jalan itu tidak tampil pada ps biasa — ia disembunyikan karena memang bukan anggota stack:
$ docker compose ps -aOutput yang Dihasilkan:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
katalog-db-1 postgres:18-alpine "docker-entrypoint.s…" db 9 minutes ago Up 9 minutes (healthy) 5432/tcp
katalog-web-1 katalog-web "node --watch src/ser…" web 9 minutes ago Up 9 minutes (healthy) 0.0.0.0:8080->3000/tcp
katalog-proxy-1 nginx:1.29-alpine "/docker-entrypoint.…" proxy 9 minutes ago Up 9 minutes 0.0.0.0:8090->80/tcp
katalog-web-run-8c31f2 katalog-web "node --version" web 16 seconds ago Exited (0) 14 seconds agoBekas container itu dibersihkan, lalu bentuk yang benar dijalankan:
$ docker compose rm -fOutput yang Dihasilkan:
[+] Running 1/1
✔ Container katalog-web-run-8c31f2 Removed$ docker compose run --rm web node --versionOutput yang Dihasilkan:
v22.20.0Mari kita telaah perbedaan run dan exec dari keseluruhan alur di atas:
runmenciptakan container baru,execmenempel ke container lama — containerkatalog-web-run-8c31f2lahir dari cetakbiru servicewebyang sama, menjalankannode --version, lalu keluar; nama bendanya memuat penandarunsehingga tidak pernah tertukar dengan anggota stack.- Konfigurasi service tetap diterapkan — environment dari
env_filedanenvironment, network project, volume yang dipasang: semuanya hadir pada container sekali jalan ini; satu pengecualian penting: port dariportstidak diterbitkan, karena dua pemetaan pada satu pintu host akan saling menabrak. - Tanpa
--rm, bekasnya tertinggal berstatusExited— tersembunyi daripsbiasa, hanya tampil padaps -a, dan dibersihkan lewatdocker compose rm -f; flag--rmmenghapus bekas itu seketika setelah perintah selesai, dan itulah bentuk yang layak menjadi kebiasaan. runadalah padanan kerjadocker run --rmuntuk stack — skrip migrasi, tugas impor data, dan uji cepat versi tooling semuanya polarun --rm;exectetap satu-satunya jalan untuk bekerja di dalam container yang sedang melayani permintaan.
Perintah top menutup keluarga inspeksi — versi Compose dari docker top yang menampilkan proses di dalam container dari sudut pandang host:
$ docker compose top dbOutput yang Dihasilkan (dipotong):
katalog-db-1
UID PID PPID C STIME TTY TIME CMD
70 1 0 0 09:14 ? 00:00:02 postgres
70 124 1 0 09:14 ? 00:00:00 postgres: checkpointer
70 125 1 0 09:14 ? 00:00:00 postgres: background writer
...Dua hal terbaca seketika dari tabel itu: proses utama postgres berjalan sebagai PID 1 — entrypoint image melepas kendali ke server sungguhan lewat exec, persis pembahasan Chapter CMD dan ENTRYPOINT — dan seluruh proses berjalan di bawah UID 70, user postgres bawaan image Alpine.
Membongkar Stack dengan down #
Akhir hari tiba, dan pembongkarannya satu perintah:
$ docker compose downOutput yang Dihasilkan:
[+] Running 7/7
✔ Container katalog-proxy-1 Stopped
✔ Container katalog-proxy-1 Removed
✔ Container katalog-web-1 Stopped
✔ Container katalog-web-1 Removed
✔ Container katalog-db-1 Stopped
✔ Container katalog-db-1 Removed
✔ Network katalog_default RemovedMari kita telaah urutan dan yang tidak hadir pada keluaran tersebut:
- Urutan penghentian adalah kebalikan urutan start —
proxydihentikan lebih dulu, disusulweb, terakhirdb; Compose membaca benangdepends_ondan membongkar dari ujung yang tidak diandalkan service lain, kebalikan persis dari arah gerbangservice_healthypada Chapter depends_on dan Startup Order. - Setiap container melewati
StoppedlaluRemoved— dua langkah yang sama dengan siklus manualdocker stopdandocker rm, dikerjakan berurutan untuk seluruh stack. - Network ikut dibongkar, volume tidak — tidak ada satu baris
Volume ... Removedpada keluaran itu;katalog_db-datatetap berdiri, sehinggadocker compose up -dbesok pagi menemukan kembali seluruh isi tabelproduk— janji Chapter Volume dan Bind Mount yang kini terasa sebagai rutinitas.
Perintah-perintah pengelolaan kini lengkap di tangan, dan stack katalog bisa dijalankan, diamati, dimasuki, dan dibongkar dengan nyaman. Namun satu ketegangan belum terurai: compose.yaml kita menumpuk dua kepentingan dalam satu berkas — konfigurasi bersama yang dibaca seluruh tim, dan kebiasaan personal Budi seperti command: node --watch yang tidak relevan bagi produksi, bahkan bisa mengganggunya. Compose memiliki mekanisme berlapis untuk memisahkan keduanya tanpa memecah berkas menjadi banyak salinan yang saling bertengkar: berkas override yang dimuat otomatis, aturan merge yang bisa diprediksi, dan tag kendali untuk kasus-kasus yang menuntut pengecualian. Keseluruhannya adalah materi Chapter Compose Override dan Environment — chapter penutup section ini.
Referensi #
- Docker Compose CLI — daftar lengkap seluruh perintah Compose beserta flag-nya.
- docker compose ps
— kolom keluaran ps dan makna flag
-a. - docker compose logs
— flag
--follow,--tail, dan pemfilteran per service. - docker compose run
— perintah sekali jalan, flag
--rm, dan perilaku portnya.