Docker Compose dan Aplikasi Multi-Container

Docker Compose dan Aplikasi Multi-Container

Bitnesia • Aug 27, 2026 90 •EN

Bab 26 ditutup dengan skenario yang cukup merepotkan bagi Sysadmin, yaitu menjalankan container web-test dan db-demo melalui dua perintah docker run terpisah, lalu menghubungkan keduanya secara manual melalui docker network create app-net. Cara ini masih bisa ditoleransi untuk dua container percobaan. Namun, Developer di lapangan jarang sekali membangun aplikasi hanya dari satu service. Aplikasi produksi yang realistis biasanya terdiri dari web server, database, dan tool bantu administrasi sekaligus, masing-masing dengan port, volume, dan environment variable yang berbeda. Menuliskan ulang seluruh flag docker run tersebut setiap kali server perlu dijalankan ulang bukan hanya melelahkan, melainkan juga rawan salah ketik yang berujung pada konfigurasi tidak konsisten antara satu deployment dan deployment berikutnya. Bab 27 menyelesaikan masalah ini melalui Docker Compose, yaitu tool resmi dari Docker untuk mendefinisikan seluruh aplikasi multi-container hanya dalam satu file YAML deklaratif. Bab ini dimulai dari konsep dan struktur file compose.yaml, membangun stack tiga service nyata berisi web server Nginx, database PostgreSQL 18, dan Adminer sebagai web UI administrasinya, mengelola environment variable melalui file .env, hingga menutup bab dengan restart policy dan scaling dasar agar service tetap hidup serta dapat digandakan sesuai kebutuhan beban.

27.1 Konsep Docker Compose dan Struktur File compose.yaml

Sebelum menulis file konfigurasi pertama, kita perlu memahami terlebih dahulu masalah yang sebenarnya diselesaikan oleh Docker Compose, serta tiga bagian utama yang menyusun sebuah file compose.

27.1.1 Dari Perintah docker run Berulang ke Satu File Deklaratif

Docker Compose adalah tool orkestrasi untuk lingkungan single-host yang membaca satu file YAML berisi definisi seluruh service, network, dan volume sebuah aplikasi, lalu menyamakan kondisi container yang benar-benar berjalan dengan definisi tersebut hanya melalui satu perintah. Alih-alih mengetik ulang flag -p, -v, -e, dan --network setiap kali container perlu dijalankan seperti pada Bagian 26.5.3, kita cukup menuliskannya sekali di dalam file, lalu memanggil docker compose up kapan pun dibutuhkan. Pendekatan ini disebut declarative, yaitu kita mendeskripsikan kondisi akhir yang diinginkan, bukan urutan perintah yang harus dijalankan satu per satu.

Docker Compose bukan aplikasi terpisah yang perlu dipasang sendiri di Ubuntu Server 26.04 LTS. Sejak Bagian 26.2.1, installer script resmi Docker sudah otomatis memasang paket docker-compose-plugin sebagai bagian dari instalasi Docker Engine, yang menghadirkan perintah docker compose (dua kata, tanpa tanda hubung) sebagai plugin bawaan CLI Docker. Hal ini berbeda dari docker-compose (satu kata dengan tanda hubung) generasi lama yang merupakan aplikasi Python terpisah dan sudah dinyatakan usang oleh Docker sejak Compose V2 dirilis.

Langkah Praktik

  • Konfirmasikan plugin Compose sudah aktif sebagai bagian dari Docker CLI yang terpasang sejak Bab 26.
    docker compose version

Verifikasi dan Troubleshooting

  • Output yang sehat diawali dengan Docker Compose version v2.x.x diikuti hash build, menandakan plugin terbaca sebagai bagian dari Docker CLI, bukan sebagai perintah terpisah.
  • Jika muncul error docker: 'compose' is not a docker command, paket docker-compose-plugin belum terpasang. Pasang manual melalui sudo apt install docker-compose-plugin, atau ulangi installer script resmi pada Bagian 26.2.1.

27.1.2 Anatomi compose.yaml: services, networks, dan volumes

Sebuah file compose pada dasarnya hanya tersusun dari tiga blok utama di level teratas.

services:
  nama_service_1:
    image: nama_image:tag
    ports:
      - "port_host:port_container"
  nama_service_2:
    image: nama_image_lain:tag

volumes:
  nama_volume:

Blok services adalah bagian wajib yang paling banyak diisi. Setiap key di bawahnya, misalnya nama_service_1 pada contoh di atas, menjadi satu container ketika dijalankan, lengkap dengan image, ports, volumes, environment, hingga restart policy-nya sendiri. Blok volumes di level teratas berfungsi mendeklarasikan named volume yang dikelola Docker, setara dengan perintah docker volume create yang sudah kita praktikkan secara manual pada Bagian 26.5.1, hanya saja kini cukup dideklarasikan sekali di dalam file.

Bagian ketiga, networks, justru sering tidak perlu dituliskan sama sekali. Saat docker compose up dijalankan, Compose otomatis membuatkan satu network bridge khusus untuk proyek tersebut, lalu menghubungkan seluruh service ke dalamnya tanpa perlu docker network create app-net secara manual seperti pada Bagian 26.5.3. Setiap service otomatis bisa saling menjangkau melalui nama service-nya sendiri sebagai hostname, didukung oleh embedded DNS server bawaan Docker yang sama seperti yang sudah kita bahas sebelumnya. Blok networks baru perlu dituliskan secara eksplisit jika kita membutuhkan lebih dari satu network terisolasi dalam satu aplikasi, misalnya memisahkan network frontend publik dari network backend database, sebuah pola yang akan lebih relevan saat kita membahas hardening jaringan pada Bagian VIII nanti.

Ada dua catatan penting soal penamaan sebelum kita mulai menulis file sungguhan. Pertama, field version yang dulu wajib dituliskan di baris paling atas file (misalnya version: "3.8") kini sudah usang sejak Docker mengadopsi penuh Compose Specification. Field ini boleh dihilangkan sepenuhnya karena Compose modern selalu memvalidasi file memakai skema terbaru, apa pun nilai version yang dituliskan. Kedua, mengenai nama file itu sendiri: Compose CLI mencari compose.yaml terlebih dahulu sebagai nama baku yang direkomendasikan, baru kemudian compose.yml, docker-compose.yaml, dan docker-compose.yml sebagai nama lama untuk kompatibilitas ke belakang. Series ini memakai compose.yaml sebagai nama file di seluruh contoh praktik, tetapi docker-compose.yml yang mungkin lebih akrab di banyak tutorial lama tetap didukung penuh dan bekerja secara identik.

27.2 Menjalankan Aplikasi Multi-Service: Web, Database, dan Adminer

Bagian ini mempraktikkan langsung sebuah stack tiga service: web server Nginx, database PostgreSQL 18 seperti yang sudah dibahas di Bab 18, dan Adminer sebagai web UI administrasi database bergaya container, sebagai pembanding dari pgAdmin 4 yang dipasang secara native di Bab 22.

27.2.1 Menyiapkan Struktur Proyek

Langkah Praktik

  1. Buat direktori proyek beserta folder konten web statis.
    mkdir -p ~/app-compose/html
    cd ~/app-compose
  2. Buat halaman HTML sederhana sebagai konten web.
    echo "<h1>Aplikasi contoh berjalan lewat Docker Compose</h1>" > html/index.html

27.2.2 Menulis compose.yaml Lengkap untuk Tiga Service

Langkah Praktik

  1. Buat file .env berisi nilai kredensial database dan port yang akan dipakai. Detail lengkap mengenai file ini dibahas pada Bagian 27.3; untuk sekarang cukup pahami bahwa file ini menampung nilai yang tidak ditulis langsung di compose.yaml.
    nano .env
    POSTGRES_USER=notes_user
    POSTGRES_PASSWORD=ganti_password_ini
    POSTGRES_DB=notes_db
    WEB_PORT=8090
    ADMINER_PORT=8091
  2. Buat compose.yaml di direktori yang sama.
    nano compose.yaml
    services:
      web:
        image: nginx:stable
        restart: unless-stopped
        ports:
          - "${WEB_PORT}:80"
        volumes:
          - ./html:/usr/share/nginx/html:ro
    
      db:
        image: postgres:18
        restart: unless-stopped
        environment:
          POSTGRES_USER: ${POSTGRES_USER}
          POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
          POSTGRES_DB: ${POSTGRES_DB}
        volumes:
          - db-data:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U notes_user -d notes_db"]
          interval: 5s
          timeout: 5s
          retries: 5
    
      adminer:
        image: adminer
        restart: unless-stopped
        ports:
          - "${ADMINER_PORT}:8080"
        depends_on:
          db:
            condition: service_healthy
    
    volumes:
      db-data:
    Berikut adalah beberapa bagian penting untuk dipahami. Service web memakai volumes dengan bentuk bind mount seperti pada Bagian 26.5.2, memetakan folder ./html di host ke document root Nginx, dengan akhiran :ro (read-only) agar container tidak bisa menulis balik ke folder host. Service db memakai healthcheck berbasis pg_isready, yaitu utility bawaan PostgreSQL untuk memeriksa apakah server database sudah benar-benar siap menerima koneksi, bukan sekadar proses postgres yang sudah menyala. Service adminer memakai depends_on dengan condition: service_healthy, artinya container Adminer baru benar-benar dijalankan setelah healthcheck milik db melaporkan status sehat, bukan sekadar menunggu container db berstatus "running" yang bisa saja tercapai sebelum PostgreSQL selesai diinisialisasi.

27.2.3 Menjalankan Stack dengan docker compose up

Langkah Praktik

  1. Jalankan seluruh stack di latar belakang dari direktori proyek.
    docker compose up -d
    Compose membuat satu network bridge baru bernama app-compose_default (mengikuti nama direktori proyek sebagai project name), volume app-compose_db-data, lalu menjalankan ketiga container secara berurutan sesuai dependensi: db lebih dulu, disusul web yang tidak memiliki dependensi, dan adminer paling akhir setelah db berstatus sehat. Perhatikan bahwa container-nya sendiri dinamai dengan tanda hubung, misalnya app-compose-db-1, berbeda dari network dan volume yang memakai underscore seperti di atas. Bukan salah ketik, melainkan memang konvensi penamaan resource yang berbeda di internal Compose: container mengikuti format project-service-index, sedangkan network dan volume mengikuti format project_nama.

Verifikasi dan Troubleshooting

  • Lihat status ketiga container sekaligus, termasuk kolom health check.
    docker compose ps
  • Akses halaman web statis yang baru saja berjalan.
    curl http://localhost:8090
    Output seharusnya menampilkan baris <h1>Aplikasi contoh berjalan lewat Docker Compose</h1> yang telah kita buat pada Bagian 27.2.1.
  • Buka http://alamat-ip-server:8091 dari browser untuk login ke Adminer. Isi form login dengan System PostgreSQL, Server db (nama service, bukan localhost atau IP address, karena keduanya terhubung melalui embedded DNS pada network Compose yang sama), Username notes_user, Password sesuai isi .env, dan Database notes_db. Login yang berhasil akan menampilkan halaman administrasi Adminer dengan database notes_db yang masih kosong.
  • Jika port 8090 atau 8091 sudah dipakai proses lain, ganti nilainya di .env lalu jalankan ulang docker compose up -d. Jika UFW sudah aktif seperti yang nanti dibahas pada Bab 31, pastikan kedua port tersebut diizinkan terlebih dahulu sebelum diakses dari komputer lain.
  • Jika adminer pada docker compose ps tampak lama di kolom STATUS tanpa kunjung menjadi Started, periksa terlebih dahulu apakah db sudah healthy.
    docker compose logs db
    Baris log database system is ready to accept connections menandakan PostgreSQL sudah benar-benar siap. Jika baris ini belum muncul, healthcheck memang akan terus menahan adminer agar tidak dijalankan lebih dahulu, sesuai dengan desain depends_on pada Bagian 27.2.2.

27.2.4 Perintah Operasional Sehari-hari

Beberapa perintah berikut akan sering dipakai Sysadmin setelah stack berjalan, jauh lebih ringkas dibanding mengelola tiap container satu per satu seperti pada Bab 26.

PerintahFungsi
docker compose psMelihat status seluruh service dalam project
docker compose logs -f nama_serviceMengikuti log satu service tertentu secara real-time
docker compose stopMenghentikan seluruh container tanpa menghapusnya
docker compose startMenjalankan kembali container yang sudah dihentikan stop
docker compose restart nama_serviceMe-restart satu service tanpa mengganggu service lain
docker compose downMenghentikan lalu menghapus container dan network, volume tetap aman
docker compose down -vSama seperti di atas, tetapi ikut menghapus volume secara permanen

Verifikasi dan Troubleshooting

  • Ikuti log service db secara langsung, berguna saat debugging query atau koneksi yang gagal dari Adminer.
    docker compose logs -f db
    Tekan Ctrl+C untuk keluar dari mode follow tanpa menghentikan container itu sendiri.
  • Catatan jujur mengenai risiko: flag -v pada docker compose down -v menghapus volume db-data secara permanen beserta seluruh isi database di dalamnya. Jangan pernah menjalankan perintah ini di server produksi tanpa backup terlebih dahulu, mengikuti prinsip yang sama seperti strategi backup database pada Bab 23.

27.3 Environment Variable dan File .env

Bagian ini membedah dua cara berbeda Compose memanfaatkan file .env, sebuah perbedaan yang sering membingungkan karena keduanya sama-sama memakai file dengan nama yang sama, tetapi bekerja pada tahap yang sepenuhnya berbeda.

27.3.1 Interpolasi Nilai dari .env ke compose.yaml

Compose secara otomatis membaca file .env yang berada satu direktori dengan compose.yaml, lalu mengganti setiap penanda ${NAMA_VARIABLE} di dalam file itu dengan nilai aslinya. Proses ini disebut interpolation, dan terjadi murni di level Compose CLI saat file sedang dibaca, jauh sebelum satu pun container benar-benar dibuat. Pola inilah yang sudah kita pakai pada ${WEB_PORT}, ${ADMINER_PORT}, dan tiga variable PostgreSQL pada Bagian 27.2.2.

Langkah Praktik

  1. Lihat hasil akhir compose.yaml setelah seluruh proses interpolasi selesai, tanpa benar-benar menjalankan apa pun.
    docker compose config

Verifikasi dan Troubleshooting

  • Output docker compose config menampilkan file YAML lengkap dengan setiap ${...} sudah tergantikan nilai aslinya, termasuk password database dalam bentuk plaintext apa adanya. Perintah ini sangat berguna untuk debugging saat sebuah variable tidak terbaca sesuai harapan, karena kita bisa langsung melihat nilai final yang benar-benar dikirim ke Docker Engine.
  • Jika sebuah ${VARIABLE} muncul kosong di output docker compose config, kemungkinan besar nama variable di .env salah ketik, atau perintah dijalankan dari direktori yang berbeda dari lokasi file .env itu sendiri, karena Compose hanya mencarinya di direktori kerja saat ini.

27.3.2 env_file untuk Mengirim Variable Langsung ke Container

Cara kedua memiliki tujuan yang berbeda sepenuhnya. Alih-alih menyisipkan nilai ke dalam compose.yaml melalui interpolasi, directive env_file mengirimkan seluruh baris di dalam sebuah file langsung menjadi environment variable di dalam proses container, persis seperti flag -e pada docker run. Karena tiga variable POSTGRES_USER, POSTGRES_PASSWORD, dan POSTGRES_DB di .env kita kebetulan sudah memakai nama persis yang dikenali image resmi postgres, blok environment pada service db sebenarnya bisa disederhanakan.

Langkah Praktik

  1. Ubah service db di compose.yaml, ganti blok environment dengan env_file.
      db:
        image: postgres:18
        restart: unless-stopped
        env_file: .env
        volumes:
          - db-data:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U notes_user -d notes_db"]
          interval: 5s
          timeout: 5s
          retries: 5
  2. Terapkan perubahan. Compose otomatis mendeteksi hanya definisi db yang berubah, sehingga hanya container tersebut yang dibuat ulang, sementara web dan adminer tidak ikut terganggu.
    docker compose up -d

Verifikasi dan Troubleshooting

  • Periksa environment variable yang benar-benar diterima container db.
    docker compose exec db env | grep POSTGRES
    Ketiga variable seharusnya tetap muncul dengan nilai yang sama seperti sebelumnya, meskipun sekarang dikirim melalui env_file, bukan melalui interpolasi ${...}.
  • Catatan dari lapangan: env_file mengirim seluruh baris di dalam file, termasuk WEB_PORT dan ADMINER_PORT yang sebenarnya sama sekali tidak relevan untuk container database. Hal ini sedikit mengotori environment container dibanding pendekatan environment eksplisit pada Bagian 27.2.2, yang hanya mengirim variable yang benar-benar dibutuhkan. Untuk aplikasi dengan banyak variable sensitif dan tidak sensitif tercampur, pertimbangkan memisahkan konfigurasi menjadi beberapa file .env khusus per service.
  • Jika kedua directive environment dan env_file dipakai bersamaan pada satu service dengan nama variable yang sama, nilai dari environment selalu diprioritaskan, sesuai urutan prioritas resmi Compose.

27.3.3 Mengamankan .env agar Tidak Ikut ke Git

File .env menyimpan password dalam bentuk plaintext, sehingga perlu diperlakukan sama hati-hatinya seperti file kredensial lain yang sudah kita jaga sepanjang series ini.

Langkah Praktik

  1. Batasi permission file .env agar hanya bisa dibaca oleh pemiliknya sendiri.
    chmod 600 .env
  2. Jika direktori proyek ini nantinya dikelola melalui Git, pastikan .env tidak pernah ikut ter-commit.
    echo ".env" >> .gitignore
  3. Sebagai gantinya, buat file .env.example berisi nama variable tanpa nilai asli, sebagai dokumentasi untuk Developer lain di tim yang perlu mengetahui variable apa saja yang dibutuhkan, tanpa membocorkan kredensial sungguhan.
    cat > .env.example << 'EOF'
    POSTGRES_USER=
    POSTGRES_PASSWORD=
    POSTGRES_DB=
    WEB_PORT=
    ADMINER_PORT=
    EOF
    File .env.example inilah yang aman untuk ikut di-commit ke Git, sementara file .env asli tetap tersimpan secara lokal di server masing-masing.

Verifikasi dan Troubleshooting

  • Catatan jujur mengenai keamanan: baik .env, environment, maupun env_file, ketiganya tetap menyimpan dan mengirim nilai dalam bentuk plaintext, yang terlihat jelas melalui docker compose config maupun docker inspect oleh siapa pun yang memiliki akses shell ke server. Untuk kebutuhan produksi yang benar-benar sensitif, seperti API key pihak ketiga atau password database produksi, pertimbangkan mekanisme secret management yang lebih matang, misalnya Docker secrets pada Docker Swarm atau tool eksternal seperti HashiCorp Vault, yang berada di luar cakupan bab ini.

27.4 Restart Policy dan Startup Order yang Aman

Server produksi cepat atau lambat akan mengalami restart, baik secara terjadwal maupun tidak terduga. Bagian ini memastikan ketiga service kita bangkit kembali secara otomatis dan dalam urutan yang benar setiap kali hal itu terjadi.

27.4.1 Empat Pilihan restart Policy

Directive restart pada level service menentukan perilaku Docker Engine ketika sebuah container berhenti, baik karena crash maupun alasan lain.

NilaiPerilaku
noDefault bawaan Docker. Container tidak pernah di-restart otomatis dalam kondisi apa pun
alwaysSelalu di-restart, termasuk setelah dihentikan manual lewat docker stop, sampai container benar-benar dihapus
on-failure[:max-retries]Hanya di-restart jika exit code menandakan error, dengan batas jumlah percobaan opsional
unless-stoppedSelalu di-restart apa pun exit code-nya, kecuali container memang dihentikan secara sengaja lewat stop

Ketiga service kita pada Bagian 27.2.2 memakai unless-stopped, yaitu pilihan yang paling umum untuk service jangka panjang seperti web server dan database. Kebijakan ini memastikan container ikut menyala lagi setelah dockerd atau bahkan seluruh host di-reboot, tetapi tetap menghormati keputusan Sysadmin ketika sebuah service memang sengaja dihentikan melalui docker compose stop untuk keperluan maintenance.

Langkah Praktik

  1. Simulasikan container db yang crash mendadak dengan mengirim sinyal paksa.
    docker kill app-compose-db-1
  2. Tunggu beberapa detik, lalu periksa statusnya kembali.
    docker compose ps
  3. Sebagai pembanding, hentikan db secara resmi melalui Compose, bukan melalui kill.
    docker compose stop db

Verifikasi dan Troubleshooting

  • Setelah langkah 2, db seharusnya kembali berstatus running tanpa perlu perintah docker compose up apa pun, karena dockerd sendiri yang memantau dan menerapkan restart policy begitu mendeteksi container berhenti secara tak terduga.
  • Setelah docker compose stop db pada langkah 3, jalankan lagi docker compose ps: kali ini db tetap berstatus berhenti dan tidak otomatis bangkit lagi, karena unless-stopped secara sengaja mengecualikan penghentian manual dari mekanisme restart otomatis. Nyalakan kembali melalui docker compose start db.
  • Catatan penting yang sering salah dipahami: baik always maupun unless-stopped sama sekali tidak mencegah docker compose down menghapus container. Kedua restart policy ini hanya mengatur perilaku setelah crash atau reboot host, bukan melindungi container dari perintah penghapusan eksplisit.

27.4.2 Startup Order Aman dengan Health Check dan depends_on

Bagian ini sebenarnya sudah kita praktikkan sejak Bagian 27.2.2 melalui kombinasi healthcheck pada db dan depends_on: condition: service_healthy pada adminer. Tanpa kombinasi ini, depends_on versi sederhana hanya menjamin urutan container dibuat, bukan urutan aplikasi di dalamnya benar-benar siap. Hal ini merupakan sebuah jebakan klasik yang membuat service dependent kadang gagal terhubung pada percobaan pertama karena database masih dalam proses inisialisasi.

Langkah Praktik

  1. Hapus seluruh stack lalu jalankan ulang dari kondisi bersih untuk mengamati urutan startup secara langsung.
    docker compose down
    docker compose up -d
  2. Segera setelah perintah di atas selesai, periksa status kesehatan db secara mentah.
    docker inspect --format='{{json .State.Health.Status}}' app-compose-db-1

Verifikasi dan Troubleshooting

  • Nilai yang dikembalikan berubah dari "starting" menjadi "healthy" dalam beberapa detik, sesuai dengan parameter interval dan retries yang telah ditentukan pada Bagian 27.2.2. Container adminer baru benar-benar masuk status running setelah nilai ini menjadi "healthy".
  • Untuk aplikasi dengan waktu startup yang jauh lebih lama dari PostgreSQL, misalnya aplikasi Java yang membutuhkan waktu puluhan detik untuk warm-up, tambahkan parameter start_period pada healthcheck agar kegagalan check di awal proses booting tidak langsung dihitung sebagai kegagalan sungguhan.

27.5 Scaling Dasar dengan docker compose up --scale

Bagian penutup ini mempraktikkan cara menjalankan banyak instance dari satu service sekaligus, yang merupakan kebutuhan umum ketika satu container Nginx saja tidak lagi cukup untuk menampung traffic.

27.5.1 Menjalankan Banyak Instance Service Sekaligus

Langkah Praktik

  1. Coba gandakan service web menjadi tiga instance memakai konfigurasi compose.yaml yang masih apa adanya dari Bagian 27.2.2.
    docker compose up -d --scale web=3
    Perintah ini gagal dengan error serupa Bind for 0.0.0.0:8090 failed: port is already allocated. Penyebabnya adalah ketiga instance sama-sama mencoba mengikat port host 8090 yang sama persis melalui ports: "${WEB_PORT}:80", padahal satu port host hanya bisa dipakai oleh satu proses.
  2. Ubah bagian ports pada service web di compose.yaml, hilangkan sisi port host dan sisakan port container saja.
      web:
        image: nginx:stable
        restart: unless-stopped
        ports:
          - "80"
        volumes:
          - ./html:/usr/share/nginx/html:ro
    Melalui penulisan port container saja, Docker Engine memilih port host secara otomatis dari ephemeral port range milik kernel (umumnya di rentang 32768 sampai 60999 pada Linux) untuk setiap instance, sehingga tidak ada lagi tabrakan port antar-replika.
  3. Ulangi scaling setelah perubahan diterapkan.
    docker compose up -d --scale web=3

Verifikasi dan Troubleshooting

  • Lihat port host acak yang didapat masing-masing instance.
    docker compose ps
    Kolom PORTS menampilkan tiga baris web dengan port host yang berbeda-beda satu sama lain.
  • Ambil port spesifik salah satu replika secara terprogram, berguna untuk skenario otomasi atau script monitoring.
    docker compose port web 80
    docker compose port --index 2 web 80
    Perintah pertama mengembalikan port milik replika pertama (index 0, default jika --index tidak dituliskan), sedangkan perintah kedua mengembalikan port milik replika ketiga.
  • Akses salah satu replika melalui port yang baru saja didapat, misalnya jika hasilnya 32771.
    curl http://localhost:32771

27.5.2 Keterbatasan Load Balancing Bawaan Compose

Scaling melalui docker compose up --scale murni menggandakan jumlah container yang berjalan, tanpa menyediakan satu titik akses tunggal yang otomatis membagi traffic ke seluruh replika. Klien harus tahu persis port mana yang hendak dituju, seperti yang baru saja kita praktikkan melalui docker compose port. Hal ini jelas belum cukup untuk skenario produksi sungguhan, ketika Visitor cukup mengakses satu domain atau IP saja tanpa perlu tahu ada berapa banyak replika di baliknya.

Solusi yang paling umum di lapangan adalah menambahkan satu load balancer di depan seluruh replika ini, misalnya melalui konsep upstream Nginx yang sudah kita bahas pada Bagian 16.2, dengan setiap port acak hasil scaling didaftarkan sebagai salah satu backend. Namun, pendekatan ini tetap merepotkan karena port acak berubah setiap kali stack dijalankan ulang. Untuk kebutuhan scaling otomatis dengan service discovery bawaan, tanpa perlu mendaftarkan port secara manual satu per satu, orchestrator khusus seperti Docker Swarm atau Kubernetes jauh lebih tepat dibanding Docker Compose murni. Catatan jujur yang perlu dipahami sejak awal adalah bahwa Docker Compose dirancang untuk lingkungan single-host, seperti development, testing, atau aplikasi skala kecil hingga menengah, bukan sebagai pengganti orchestrator produksi skala besar.

Langkah Praktik

  1. Bersihkan seluruh stack sebelum melanjutkan ke Bab 28, termasuk volume database agar tidak menumpuk data percobaan.
    docker compose down -v

Verifikasi dan Troubleshooting

  • Konfirmasikan tidak ada lagi container maupun volume tersisa dari proyek ini.
    docker compose ps -a
    docker volume ls | grep app-compose
    Kedua perintah seharusnya tidak menampilkan hasil apa pun terkait proyek app-compose.

Sampai di sini, kita sudah bisa mendefinisikan aplikasi multi-container lengkap dalam satu file compose.yaml, mengelola kredensial melalui .env dengan aman, memastikan service bangkit kembali otomatis melalui restart policy yang tepat, serta menggandakan service melalui scaling dasar. Docker dan Docker Compose menyelesaikan masalah packaging dan orkestrasi container di satu host, tetapi container tetap berbagi kernel yang sama dengan host-nya seperti yang dibahas pada Bagian 26.1. Bab 28 beralih ke pendekatan isolasi yang sepenuhnya berbeda melalui virtualisasi penuh menggunakan KVM dan QEMU, di mana setiap virtual machine benar-benar menjalankan kernelnya sendiri, cocok untuk kebutuhan yang menuntut isolasi keamanan lebih ketat atau menjalankan sistem operasi yang berbeda dari host.