Penutup Chapter Config dan Secret meninggalkan satu pertanyaan yang belum terjawab: bagaimana menambahkan service yang hanya layak menyala pada momen tertentu — misalnya utilitas untuk mengintip isi tabel produk ketika insiden terjadi — tanpa membuatnya ikut menyala pada setiap docker compose up? Menambahkannya sebagai service biasa berarti membayar biaya terus-menerus: container ekstra menyala di mesin setiap anggota tim, memakan memori, dan memperpanjang daftar yang harus dibaca pada docker compose ps. Compose menjawab kebutuhan ini lewat kunci profiles: service yang membawa profil hanya diinstansiasi bila profilnya sedang aktif, sehingga satu berkas tetap menjadi sumber kebenaran sementara wajah stack yang menyala bisa dipilih per skenario. Chapter ini membedah mekanisme itu tuntas — aktivasi lewat flag, lewat variabel environment, dan lewat penyebutan langsung; aturan ATAU untuk service beranggota banyak profil; sampai perilaku Compose yang menyalakan service ber-profil secara otomatis mengikuti benang dependensi.
Service yang Tidak Ikut Menyala #
Insiden kemarin sore menjadi pendorongnya. Koneksi antara web dan db tiba-tiba tersendat, dan Budi ingin memeriksa resolusi DNS serta jangkauan antar container dari dalam network katalog_default — persis latihan diagnosis Chapter Troubleshooting Network di Section Jaringan Container. Masalahnya, image katalog-web yang ramping tidak membawa satu pun peralatan diagnosa: tidak ada dig, tidak ada mtr, tidak ada tcpdump. Memasang peralatan itu ke image aplikasi hanya demi sesi insiden sesekali jelas menyalahi prinsip image minimal yang kita bangun sepanjang Section Image Build dan Optimisasi. Jalan yang benar adalah service terpisah yang membawa seluruh kotak peralatan, tetapi hanya menyala bila dipanggil:
debug:
image: nicolaka/netshoot
command: sleep infinity
tty: true
profiles: ["debug"]Mari kita telaah empat kunci service di atas:
image: nicolaka/netshoot— image pihak ketiga yang mengemas puluhan peralatan diagnosa jaringan dalam satu bundle:dig,nslookup,curl,tcpdump,mtr, sampaiiperf. Dengan membawanya sebagai service, seluruh peralatan itu hadir di dalam network project tanpa satu byte pun menempel pada image aplikasi.command: sleep infinity— netshoot dirancang sebagai wadah perintah sekali jalan; tanpa perintah pengganjal, container-nya selesai seketika lalu keluar.sleep infinitymenahan container hidup tanpa batas waktu — padanan polasleep 1hyang kita pakai berulang kali di Section Jaringan Container, tanpa jadwal kedaluwarsa.tty: true— mengalokasikan pseudo-TTY pada container sehingga sesi shell interaktif lewatdocker compose execterasa seperti terminal biasa, lengkap dengan baris perintah yang rapi.profiles: ["debug"]— kunci inti chapter ini: daftar profil yang harus aktif agar service diinstansiasi. Selama profildebugtidak aktif, Compose memperlakukan service ini seperti tidak ada.
Budi menambahkan blok itu ke compose.yaml lalu menjalankan perintah yang sama seperti biasa:
$ docker compose up -dOutput yang Dihasilkan:
[+] Running 4/4
✔ Network katalog_default Running
✔ Container katalog-db-1 Running
✔ Container katalog-web-1 Running
✔ Container katalog-proxy-1 RunningTidak ada satu pun baris yang menyebut debug. Inventarisnya pun bersih:
$ 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 server.js" 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 dua bukti di atas: up melaporkan seluruh keadaan tidak berubah — tiga service inti tetap tiga service inti; dan ps tidak memuat baris katalog-debug-1 apa pun karena container itu memang tidak pernah diciptakan. Service ber-profil bukan service yang berhenti atau tersembunyi — ia service yang tidak dihitung sama sekali. Aktivasi membutuhkan satu flag:
$ docker compose --profile debug up -dOutput yang Dihasilkan:
[+] Running 1/1
✔ Container katalog-debug-1 StartedSatu flag --profile debug, dan Compose menambahkan wajah kedua stack tanpa menyentuh ketiga service lainnya. Kehadiran debug di dalam network bisa dibuktikan seketika:
$ docker compose exec debug nslookup dbOutput yang Dihasilkan:
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: db
Address: 172.18.0.2Jawaban itu datang dari embedded DNS di 127.0.0.11 — server DNS milik user-defined network yang kita bedah pada Chapter Container DNS. Service debug tidak mendeklarasikan networks apa pun, sehingga ia bergabung ke network bawaan project dan menyelesaikan nama db dengan cara yang persis sama seperti web atau proxy. Seluruh peralatan netshoot kini berdiri satu hop dari setiap service katalog.
Profil Ganda dan Aturan ATAU #
Satu service boleh menjadi anggota lebih dari satu profil, dan aturan keanggotaannya adalah ATAU: service menyala bila salah satu profilnya aktif. Kasusnya nyata di katalog — Budi ingin service pengisi data contoh yang berguna saat sesi debug dan saat pipeline pengujian berjalan. Ia menambahkan service seed:
seed:
image: postgres:18-alpine
profiles: ["debug", "ci"]
depends_on:
db:
condition: service_healthy
environment:
PGPASSWORD: ${POSTGRES_PASSWORD}
command:
- psql
- -h
- db
- -U
- katalog
- -d
- katalog
- -c
- "INSERT INTO produk SELECT 'Teh Hijau', 52000 WHERE NOT EXISTS (SELECT 1 FROM produk WHERE nama = 'Teh Hijau');"Mari kita telaah lima bagian service di atas:
profiles: ["debug", "ci"]— dua keanggotaan sekaligus; aktivasi profildebugsaja, profilcisaja, atau keduanya, sama-sama menjadikanseedkandidat untuk diinstansiasi.depends_ondengancondition: service_healthy— seed menunggudblulus healthcheck sebelum mengetuk pintunya, pola gerbang yang kita bangun pada Chapter depends_on dan Startup Order.environmentdenganPGPASSWORD: ${POSTGRES_PASSWORD}— klienpsqlmembaca password dari variabel itu; nilainya diambil dari.envlewat interpolasi — mekanisme${...}yang kita kenal sejak Chapter Environment dan env File dan yang akan kita bedah jauh lebih dalam pada chapter berikutnya.commandbentuk daftar — menimpa CMD image denganpsqlbeserta seluruh argumennya dalam exec form; entry point image postgres meloloskan perintah selainpostgreslangsung ke eksekusi, persis perilaku yang kita manfaatkan pada Chapter Command Override.WHERE NOT EXISTSpada perintah INSERT — seed dirancang idempoten: dijalankan berkali-kali pun, barisTeh Hijauhanya tercatat sekali. Service one-shot yang dipanggil ulang adalah kandidat sempurna untuk berulang, dan menulis ulang data ganda adalah jenis kecelakaan yang seharusnya mustahil.
Sekarang uji aturan ATAU-nya. Budi menghentikan debug lebih dulu agar hasil percobaan mudah dibaca — docker compose stop debug — lalu mengaktifkan profil ci saja:
$ docker compose --profile ci up -dOutput yang Dihasilkan:
[+] Running 2/2
✔ Container katalog-db-1 Running
✔ Container katalog-seed-1 Started$ docker compose exec db psql -U katalog -d katalog -c "SELECT * FROM produk;"Output yang Dihasilkan:
nama | harga
-------------------+-------
Kopi Arabika Gayo | 85000
Teh Melati | 45000
Teh Hijau | 52000
(3 rows)Mari kita telaah hasil percobaan tersebut:
seedmenyala karena profilciaktif — padahal flag--profile debugtidak ditulis; keanggotaan ganda berarti satu jalur saja sudah cukup.debugtetap berhenti — profilcibukan anggotadebug, sehingga service itu tidak tersentuh; inilah bukti bahwa aturan ATAU dievaluasi per service, bukan per berkas.dbdilaporkanRunning— Compose menampilkan benang dependensi dari service yang dinyalakan; gerbangservice_healthysudah terlewati karenadbmemang sedang sehat.- Baris
Teh Hijauhadir di tabel — seed selesai bekerja lalu keluar dengan exit code 0;docker compose psakan mencatat container itu sebagaiExited (0), status wajar bagi service sekali jalan. - Inilah utilitas mengintip isi tabel yang dijanjikan penutup chapter sebelumnya — query
SELECTdi atas dijalankan dari jalur seed, dan pola yang sama bisa dipakai untuk memeriksa data kapan pun insiden butuh bukti.
Daftar seluruh profil yang dikenal sebuah berkas bisa ditanya langsung:
$ docker compose config --profilesOutput yang Dihasilkan:
debug
ciCOMPOSE_PROFILES Tanpa Flag #
Flag --profile menempel pada satu pemanggilan perintah. Untuk sesi kerja panjang yang selalu membutuhkan profil tertentu, mengetik ulang flag pada setiap perintah jelas membosankan, dan Compose menyediakan pintu keduanya: variabel environment COMPOSE_PROFILES. Nilainya berupa daftar profil dipisah koma, dan ia boleh didefinisikan di shell maupun di dalam .env. Budi menghentikan debug dengan docker compose stop debug, menambahkan satu baris pada .env:
POSTGRES_PASSWORD=rahasia123
LOG_LEVEL=info
COMPOSE_PROFILES=debuglalu menjalankan perintah paling polos yang ada:
$ docker compose up -dOutput yang Dihasilkan:
[+] Running 1/1
✔ Container katalog-debug-1 StartedTanpa satu flag pun, profil debug aktif dan service-nya menyala. Nilai yang diekspor di shell bekerja dengan cara yang sama — COMPOSE_PROFILES=debug docker compose up -d — dan bila keduanya hadir bersamaan, nilai dari shell menimpa nilai .env, mengikuti urutan sumber yang sama dengan interpolasi yang kita bedah nanti. Setelah percobaan selesai Budi membuang baris itu dari .env: kalau dibiarkan, debug akan ikut menyala pada setiap up di mesinnya — dan profil yang selalu aktif memang sebaiknya tidak dibuat profil.
Service yang Menyala Sendiri #
Dua aturan pelengkap membuat profiles tidak menggantungkan diri pada flag. Aturan pertama: menyebut nama service ber-profil secara langsung mengaktifkan profilnya. Perintah docker compose up -d debug sama sahnya dengan --profile debug up -d — Compose melihat target eksplisit, mengaktifkan profil yang dibutuhkan target itu, lalu baru bekerja. Aturan kedua: service yang bergantung pada service ber-profil ikut menyalakan profil dependensinya. Ilustrasinya paling jelas lewat pola berikut:
laporan:
image: postgres:18-alpine
depends_on:
- db-arsip
db-arsip:
image: postgres:18-alpine
profiles: ["arsip"]Mari kita telaah interaksi kedua service di atas:
laporantidak memiliki profil — ia selalu dihitung sebagai kandidat service setiapup.db-arsipberprofilarsip— bila dibiarkan sendiri, ia hanya menyala saat profil itu aktif.depends_onmenyatukan keduanya — begitudocker compose up -d laporandijalankan, Compose menelusuri dependensilaporan, menemukandb-arsipber-profil, dan mengaktifkan profilarsipsecara otomatis; dependensi yang menggantung lebih berbahaya daripada profil yang ikut menyala.- Pola ini bukan tambahan baru pada katalog — blok di atas adalah ilustrasi pola untuk stack yang membutuhkan pasangan seperti aplikasi laporan dan arsip datanya; katalog kita tetap pada
debugdanseed.
Kapan Profiles Layak Dipakai #
Kebutuhan “service yang kadang perlu” ternyata punya banyak wujud. Tabel berikut memetakan skenario yang paling sering dijumpai bersama nama profil yang lazim dipakai komunitas:
| Skenario | Profil khas | Isi service-nya |
|---|---|---|
| Kotak peralatan saat insiden | debug | image netshoot dengan sleep infinity, siap dimasuki exec |
| Pengujian beban pra-rilis | loadtest | runner k6 beserta skrip ujinya, menyala hanya saat jendela uji |
| Tugas sekali jalan | ci, backup | pg_dump, seed data, atau migrasi yang bekerja lalu keluar |
| Versi database alternatif | uji | image postgres dengan tag major berbeda untuk latihan migrasi |
Pola umumnya sama pada keempat baris: service itu mahal, berisiko, atau tidak bermakna bila menyala terus-menerus, tetapi sangat berharga pada momen tertentu. Profiles memungkinkan service seperti itu hidup di dalam berkas yang sama dengan stack utama — terdokumentasi, ter-version-control, dan tetap satu perintah untuk dipanggil.
Profiles Bukan Lingkungan Terpisah #
Batas pemakaian yang paling sering disalahpahami perlu ditegaskan sebelum chapter ini ditutup. Profiles memilih service mana yang menyala; ia tidak menyetel nilai konfigurasi apa pun.
| Aspek | profiles | Berkas override |
|---|---|---|
| Yang dipilih | service mana yang diinstansiasi | nilai konfigurasi tiap service |
| Cara mengaktifkan | --profile, COMPOSE_PROFILES, atau target eksplisit | berkas dengan nama khusus dimuat otomatis, atau -f eksplisit |
| Cocok untuk | service opsional per skenario | selisih kebutuhan antar orang atau antar lingkungan |
| Dibedah tuntas di | chapter ini | Compose Override dan Environment |
Tutup chapter dengan siklus penuh. docker compose down membongkar seluruh container milik project tanpa peduli profil — container yang sedang berhenti pun ikut dijemput:
$ docker compose downOutput yang Dihasilkan:
[+] Running 9/9
✔ 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
✔ Container katalog-debug-1 Removed
✔ Container katalog-seed-1 Removed
✔ Network katalog_default Removed$ docker compose up -dOutput yang Dihasilkan:
[+] Running 4/4
✔ Network katalog_default Created
✔ Container katalog-db-1 Healthy
✔ Container katalog-web-1 Started
✔ Container katalog-proxy-1 StartedSiklus itu memperlihatkan janji profiles utuhnya: satu berkas, dua wajah — up biasa selalu kembali ke tiga service inti, sementara debug dan seed tidur nyenyak di dalam teks compose.yaml sampai dipanggil pada saat dibutuhkan. Namun perhatikan kembali satu baris kecil pada service seed: PGPASSWORD: ${POSTGRES_PASSWORD} — nilai yang dicari Compose dari luar berkas, dari .env atau dari shell. Tanda ${...} itu selama ini kita pakai tanpa membedah peta lengkapnya: dari mana saja nilai dicari, dalam urutan apa, bagaimana memberi nilai cadangan, dan bagaimana membuat Compose menolak bekerja dengan pesan yang jelas ketika nilai yang wajib ternyata tidak ada. Keseluruhan mekanisme itu adalah materi Chapter Variable Interpolation.
Referensi #
- Compose profiles — cara kerja profiles, tiga jalur aktivasi, dan aturan dependensi otomatis.
- services — Compose file reference
— definisi kunci
profilespada service. - docker compose CLI reference
— flag
--profiledan variabelCOMPOSE_PROFILES. - The Compose Specification — definisi formal atribut profiles dalam spesifikasi Compose.