Container yang berhasil dibangun dan berjalan lancar di laptop developer belum tentu siap dilempar ke production begitu saja. Di production, pertanyaan yang muncul berbeda: kalau aplikasi crash tengah malam, ke mana log-nya bisa ditelusuri? Kalau resource membengkak diam-diam, siapa yang tahu sebelum user komplain? Kalau proses di dalam container macet tapi container itu sendiri masih "berjalan", bagaimana sistem tahu perlu bertindak? Dan kalau workload sudah tersebar di banyak host, siapa yang mengatur penjadwalan dan penyembuhan otomatis saat satu node mati? Bab ini membahas empat pilar yang menjawab pertanyaan-pertanyaan tersebut: strategi logging supaya jejak aplikasi tetap bisa ditelusuri, pemantauan dan observabilitas supaya kondisi sistem terlihat sebelum jadi insiden, health check supaya Docker tahu kapan container benar-benar sehat, dan gambaran umum orkestrasi container untuk mengelola workload lintas host.
25.1 Strategi Logging
Log adalah sumber informasi pertama yang dicari Sysadmin/DevOps Engineer saat troubleshooting insiden production, tapi log yang tidak dikelola dengan baik justru bisa jadi masalah baru: memenuhi disk host sampai penuh atau hilang begitu saja saat container-nya dihapus. Bagian ini membahas bagaimana Docker menangani log container dan cara mengelolanya supaya tetap berguna sekaligus tidak membebani sistem.
25.1.1 Logging Driver Docker
Docker tidak menyimpan log container dengan satu cara tetap; setiap container memakai logging driver yang menentukan format penyimpanan dan tujuan akhir output stdout/stderr proses di dalamnya. Menurut dokumentasi resmi Docker, driver json-file adalah default yang dipakai kalau tidak ada konfigurasi lain, menyimpan setiap baris log sebagai objek JSON di disk host. Selain json-file, Docker juga menyediakan driver local yang formatnya lebih ringkas dan otomatis melakukan rotasi, syslog dan journald untuk integrasi dengan sistem logging bawaan Linux, serta beberapa driver untuk platform logging eksternal seperti gelf, fluentd, awslogs, dan splunk. Cek driver yang sedang dipakai Docker Engine di host lewat perintah berikut.
docker info --format '{{.LoggingDriver}}'Driver logging bisa ditentukan per container lewat opsi --log-driver saat docker run, tanpa perlu mengubah konfigurasi daemon secara global.
docker run -d --log-driver=journald --name payment-api payment-service:1.4.2Driver journald di atas hanya berfungsi kalau host menjalankan systemd dengan journald aktif, karena driver ini meneruskan log container langsung ke journal sistem operasi. Untuk memeriksa log yang sudah masuk ke journald, gunakan perintah journalctl dengan filter identifier container.
sudo journalctl CONTAINER_NAME=payment-api25.1.2 Log Rotation dan Ukuran Log
Driver json-file yang jadi default Docker tidak melakukan rotasi log secara otomatis kecuali dikonfigurasi eksplisit, sehingga aplikasi yang mencetak log dalam volume besar bisa perlahan menghabiskan ruang disk host sampai penuh. Batasi ukuran dan jumlah file log per container lewat opsi --log-opt saat docker run.
docker run -d --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3 --name payment-api payment-service:1.4.2Konfigurasi di atas membatasi setiap file log maksimum 10 MB, dan Docker akan membuat file baru begitu batas tercapai lalu menghapus file log terlama begitu jumlah file melebihi max-file sebanyak 3. Supaya batasan ini berlaku otomatis untuk semua container baru tanpa perlu diulang di setiap docker run, atur nilai default lewat /etc/docker/daemon.json di level daemon.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}sudo systemctl restart dockerPerlu dicatat bahwa seluruh nilai di dalam log-opts harus ditulis sebagai string, termasuk max-file yang secara logika berupa angka. Sebagai alternatif yang lebih efisien dari json-file, dokumentasi resmi Docker merekomendasikan driver local yang memakai format penyimpanan lebih ringkas dan otomatis menjalankan rotasi meski tidak diberi log-opt sama sekali, cocok dipakai sebagai default baru di host production yang belum sempat dikonfigurasi rotasinya secara manual.
docker run -d --log-driver=local --name payment-api payment-service:1.4.2Di lapangan, insiden disk penuh akibat log container yang tidak dirotasi adalah salah satu penyebab downtime yang sebetulnya paling mudah dicegah tapi paling sering terlewat, karena gejalanya baru terasa setelah berbulan-bulan container berjalan tanpa masalah. Jadikan log-opts di daemon.json sebagai bagian dari provisioning standar setiap host Docker baru, bukan konfigurasi tambahan yang menyusul setelah insiden terjadi.
25.1.3 Centralized Logging
Log yang cuma tersimpan di disk host masing-masing jadi sulit ditelusuri begitu container berpindah host, dihapus, atau workload sudah tersebar di banyak node sekaligus. Centralized logging mengumpulkan log dari seluruh container ke satu tempat terpusat, sehingga Sysadmin/DevOps Engineer bisa mencari dan mengorelasikan log lintas container tanpa perlu login satu per satu ke tiap host. Salah satu cara paling langsung memakai driver syslog untuk mengirim log ke syslog server remote lewat jaringan.
docker run -d --log-driver=syslog --log-opt syslog-address=udp://logs.internal:514 --name payment-api payment-service:1.4.2Untuk ekosistem logging yang lebih terstruktur seperti Elasticsearch atau Graylog, driver gelf mengirim log dalam format Graylog Extended Log Format yang membawa metadata tambahan selain teks log itu sendiri.
docker run -d --log-driver=gelf --log-opt gelf-address=udp://logs.internal:12201 --name payment-api payment-service:1.4.2Pola lain yang umum dipakai di lapangan, terutama saat banyak container perlu mengirim log ke tujuan yang sama, adalah menjalankan agent logging seperti Fluentd sebagai container terpisah di host yang sama, lalu mengarahkan seluruh container aplikasi memakai driver fluentd supaya log diteruskan ke agent tersebut sebelum diproses dan dikirim ke backend penyimpanan akhir.
docker run -d --log-driver=fluentd --log-opt fluentd-address=127.0.0.1:24224 --log-opt tag=payment-api --name payment-api payment-service:1.4.2Sebelum mengganti driver logging default di seluruh host production, uji dulu di lingkungan staging, karena beberapa driver seperti gelf, fluentd, dan awslogs memblokir proses container saat tujuan pengiriman log tidak bisa dijangkau, berbeda dari json-file yang selalu berhasil menulis ke disk lokal. Verifikasi log tetap mengalir dengan benar setelah mengganti driver lewat docker logs untuk driver yang mendukungnya, atau langsung memeriksa dashboard di sisi backend logging terpusat untuk driver yang tidak mendukung docker logs.
25.2 Pemantauan dan Observabilitas
Logging memberi tahu apa yang terjadi setelah sebuah kejadian tercatat, sementara pemantauan (monitoring) dan observabilitas memberi gambaran kondisi sistem secara berkelanjutan, termasuk tren pemakaian resource yang bisa jadi tanda peringatan dini sebelum insiden benar-benar terjadi. Bagian ini membahas cara memantau container mulai dari perintah bawaan Docker sampai integrasi dengan Prometheus.
25.2.1 Docker Stats untuk Pemantauan Cepat
Perintah docker stats menampilkan pemakaian CPU, memori, jaringan, dan I/O disk seluruh container yang sedang berjalan secara real-time, cocok untuk pengecekan cepat tanpa perlu memasang tool tambahan apa pun.
docker statsUntuk kebutuhan otomatisasi seperti skrip pemantauan sederhana atau dicatat ke log terjadwal, opsi --no-stream membuat docker stats hanya mengambil satu snapshot lalu keluar, alih-alih terus memperbarui tampilan seperti mode interaktif bawaannya.
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"docker stats cukup untuk pengecekan manual atau debugging cepat, tapi tidak menyimpan riwayat data dan tidak bisa memicu alert otomatis saat resource melewati ambang batas tertentu, sehingga tidak cocok dijadikan satu-satunya andalan pemantauan di production.
25.2.2 Container Metrics dengan cAdvisor dan Prometheus
cAdvisor (Container Advisor) adalah tool open-source dari Google yang mengumpulkan metrics resource setiap container secara detail, lalu mengekspos metrics tersebut dalam format yang bisa dibaca Prometheus. cAdvisor sendiri dijalankan sebagai container, dengan beberapa direktori host di-mount sebagai read-only supaya bisa membaca informasi container lain di host yang sama.
docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
ghcr.io/google/cadvisor:v0.60.5Setelah berjalan, dashboard bawaan cAdvisor bisa diakses lewat browser di http://localhost:8080, dan endpoint metrics dalam format Prometheus tersedia di path /metrics pada port yang sama.
curl http://localhost:8080/metricsUntuk mengumpulkan metrics ini secara berkelanjutan, tambahkan target cAdvisor ke file konfigurasi Prometheus supaya di-scrape secara berkala.
scrape_configs:
- job_name: cadvisor
scrape_interval: 15s
static_configs:
- targets: ["cadvisor:8080"]Selain metrics per container lewat cAdvisor, Docker Engine sendiri juga bisa mengekspos metrics operasionalnya sendiri, seperti jumlah container yang berjalan atau durasi operasi daemon, lewat opsi metrics-addr di daemon.json. Menurut dokumentasi resmi Docker, fitur ini masih berstatus aktif dikembangkan dan nama-nama metrics-nya bisa berubah sewaktu-waktu, jadi endpoint ini lebih cocok untuk memantau kesehatan Docker daemon itu sendiri, bukan sebagai pengganti cAdvisor untuk metrics per container.
{
"metrics-addr": "127.0.0.1:9323"
}sudo systemctl restart docker
curl http://127.0.0.1:9323/metricsBatasi metrics-addr ke alamat loopback seperti 127.0.0.1 kecuali memang perlu diakses dari host lain, karena endpoint metrics ini tidak punya autentikasi bawaan; mengikatnya ke 0.0.0.0 berarti siapa pun yang bisa menjangkau port tersebut di jaringan bisa membaca informasi operasional Docker daemon di host tersebut.
25.2.3 Container Events untuk Observabilitas Real-Time
Selain metrics numerik, Docker juga mengirimkan event setiap kali ada perubahan state pada container, image, network, atau volume, misalnya saat container dibuat, dimulai, dihentikan, atau berubah status kesehatannya. Perintah docker events menampilkan stream event ini secara real-time, berguna untuk mendeteksi pola seperti container yang berulang kali restart dalam waktu singkat.
docker events --filter type=containerFilter lebih spesifik bisa diarahkan ke event tertentu, misalnya hanya menangkap perubahan status kesehatan container yang punya health check terpasang.
docker events --filter event=health_statusUntuk melihat event yang sudah lewat dalam rentang waktu tertentu, alih-alih hanya stream real-time, opsi --since dan --until membatasi jendela waktu yang ditampilkan.
docker events --since '2026-09-12T00:00:00' --until '2026-09-12T23:59:59'Di lapangan, docker events paling berguna dikombinasikan dengan tool eksternal yang mendengarkan stream ini lalu meneruskannya sebagai notifikasi ke Slack atau sistem alerting, sehingga Sysadmin/DevOps Engineer tahu ada container yang mati atau jadi unhealthy tanpa harus terus-menerus memantau terminal secara manual.
25.3 Health Checks
Status Up pada docker ps hanya berarti proses utama container masih berjalan, bukan berarti aplikasi di dalamnya benar-benar bisa melayani request. Web server yang stuck karena deadlock, misalnya, tetap terlihat Up meski sudah tidak merespons permintaan apa pun. Health check menutup celah ini dengan menjalankan perintah verifikasi dari dalam container secara berkala untuk memastikan aplikasi memang berfungsi, bukan cuma prosesnya masih hidup.
25.3.1 HEALTHCHECK di Dockerfile
Instruksi HEALTHCHECK di Dockerfile mendefinisikan perintah yang dijalankan Docker secara berkala dari dalam container untuk mengecek kesehatan aplikasi. Menurut dokumentasi resmi Docker, exit code dari perintah tersebut yang menentukan status: 0 berarti sehat, 1 berarti tidak sehat, dan 2 dicadangkan serta tidak boleh dipakai.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost/health || exit 1Keempat opsi pada contoh di atas punya nilai default masing-masing kalau tidak ditulis eksplisit: --interval 30 detik, --timeout 30 detik, --start-period 0 detik, dan --retries 3 kali. --start-period memberi waktu inisialisasi sebelum kegagalan health check mulai dihitung ke arah --retries, penting untuk aplikasi yang butuh waktu warm-up saat baru dimulai supaya tidak langsung ditandai unhealthy padahal sedang proses startup normal. Selama start period ini, Docker Engine 25.0 ke atas juga mendukung opsi --start-interval yang mengatur jeda antar pengecekan khusus selama masa inisialisasi, terpisah dari --interval yang berlaku setelah start period selesai.
Container yang punya HEALTHCHECK menampilkan status tambahan di kolom STATUS pada docker ps, mulai dari starting saat masih dalam start period, healthy setelah pengecekan berhasil, sampai unhealthy setelah kegagalan mencapai jumlah --retries.
docker ps --format "table {{.Names}}\t{{.Status}}"Detail riwayat hasil health check, termasuk output singkat dari perintah pengecekannya, bisa dilihat lewat docker inspect.
docker inspect --format '{{json .State.Health}}' payment-apiKalau base image yang dipakai sudah punya HEALTHCHECK bawaan tapi tidak relevan untuk aplikasi yang dibangun di atasnya, instruksi HEALTHCHECK NONE menonaktifkan health check yang diwariskan tersebut.
HEALTHCHECK NONE25.3.2 Health Check di Docker Compose
Selain lewat Dockerfile, health check juga bisa didefinisikan langsung di docker-compose.yml lewat kunci healthcheck per service, berguna saat perlu menyesuaikan pengecekan tanpa membangun ulang image.
services:
payment-api:
image: payment-service:1.4.2
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10sField test menerima bentuk list yang elemen pertamanya berupa CMD, CMD-SHELL, atau NONE. Bentuk CMD menjalankan perintah langsung tanpa shell, sementara CMD-SHELL menjalankan perintah lewat shell default container sehingga mendukung sintaks seperti pipe dan redirect.
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost/health || exit 1"]Kekuatan utama healthcheck di Compose muncul saat dikombinasikan dengan depends_on berbentuk panjang memakai kondisi service_healthy, yang membuat service lain menunggu sampai dependensinya benar-benar sehat, bukan cuma menunggu container-nya mulai berjalan.
services:
payment-api:
image: payment-service:1.4.2
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5Tanpa kondisi service_healthy seperti di atas, payment-api bisa saja mulai berjalan sesaat setelah container db dibuat, padahal proses PostgreSQL di dalamnya belum selesai inisialisasi dan belum siap menerima koneksi, sehingga payment-api gagal konek di percobaan pertama. Verifikasi urutan startup ini bekerja dengan benar lewat docker compose ps, yang menampilkan status healthy atau starting untuk tiap service yang punya health check.
docker compose ps25.3.3 Health Check dan Restart Otomatis
Satu kesalahpahaman yang sering ditemui di lapangan adalah anggapan bahwa container yang berstatus unhealthy otomatis di-restart oleh Docker. Faktanya, Docker Engine sendiri hanya mencatat dan melaporkan status kesehatan lewat health_status event; ia tidak mengambil tindakan apa pun terhadap container yang gagal health check kalau dijalankan sebagai container tunggal lewat docker run, sekalipun sudah dipasangi --restart, karena restart policy bereaksi terhadap exit code proses utama container, bukan terhadap status unhealthy.
Supaya container yang unhealthy benar-benar di-restart otomatis, dibutuhkan mekanisme tambahan yang memantau status kesehatan lalu bertindak berdasarkan itu. Salah satu opsi yang umum dipakai untuk container tunggal atau Compose adalah tool eksternal seperti autoheal, yang mendengarkan health_status event lewat Docker API dan menjalankan docker restart begitu sebuah container tercatat unhealthy.
docker run -d \
--name autoheal \
--restart=always \
-e AUTOHEAL_CONTAINER_LABEL=all \
-v /var/run/docker.sock:/var/run/docker.sock \
willfarrell/autohealOpsi AUTOHEAL_CONTAINER_LABEL=all di atas membuat autoheal memantau semua container yang punya HEALTHCHECK di host tersebut, bukan cuma container tertentu. Container autoheal perlu akses ke docker.sock karena ia memantau event dan menjalankan docker restart lewat Docker API host, jadi perlakukan mount ini sama hati-hatinya seperti memberi akses root ke Docker daemon; jangan pasang autoheal di host yang container-nya bisa diakses pihak yang tidak sepenuhnya dipercaya. Untuk workload yang sudah dikelola lewat orkestrasi seperti Swarm atau Kubernetes, penanganan ini otomatis jadi bagian dari mekanisme self-healing platform tersebut, di mana container atau pod yang unhealthy dijadwalkan ulang tanpa perlu tool tambahan terpisah.
25.4 Gambaran Umum Orkestrasi Container
Semua praktik pada bagian sebelumnya, mulai dari logging, monitoring, sampai health check, tetap harus dikerjakan manual satu per satu kalau container hanya dijalankan langsung lewat docker run di satu host. Orkestrasi container mengotomatiskan pengelolaan container di seluruh cluster: menjadwalkan container ke node yang tersedia, menjaga jumlah replika tetap sesuai target, mengganti container yang unhealthy tanpa campur tangan manual, dan mendistribusikan trafik ke instance yang sehat.
25.4.1 Kenapa Orkestrasi Dibutuhkan
Selama aplikasi cukup dijalankan di satu server, mengelola container manual masih terasa wajar. Masalah mulai muncul begitu kebutuhan bertambah: aplikasi perlu di-scale ke beberapa instance sekaligus untuk menampung trafik, instance-instance tersebut perlu tersebar di banyak host supaya matinya satu server tidak menjatuhkan seluruh layanan, dan setiap kali ada instance yang mati atau unhealthy, sesuatu harus segera menggantikannya tanpa menunggu Sysadmin/DevOps Engineer login manual dan menjalankan docker run ulang. Orkestrasi menjawab kebutuhan ini lewat beberapa kemampuan inti yang konsisten ditemukan di semua platform orkestrasi container: penjadwalan otomatis container ke node yang tersedia berdasarkan resource yang dibutuhkan, self-healing yang mengganti container unhealthy atau mati secara otomatis, load balancing yang mendistribusikan trafik ke instance yang sehat, service discovery yang membuat container saling menemukan satu sama lain meski lokasi fisiknya berpindah-pindah, serta rolling update yang mengganti versi aplikasi secara bertahap tanpa downtime.
25.4.2 Docker Swarm dan Kubernetes
Docker Swarm adalah mode orkestrasi yang sudah terintegrasi langsung di dalam Docker Engine, diaktifkan cukup lewat satu perintah tanpa perlu instalasi komponen tambahan.
docker swarm initKelebihan utama Swarm ada pada kesederhanaannya; siapa pun yang sudah terbiasa dengan perintah docker dan docker compose akan menemukan konsep dan sintaks Swarm terasa familiar, karena definisi service pada Swarm mode memakai format docker-compose.yml yang sama lewat docker stack deploy. Kubernetes di sisi lain adalah platform orkestrasi yang jauh lebih luas ekosistemnya, dikembangkan awalnya oleh Google dan sekarang dikelola oleh Cloud Native Computing Foundation (CNCF), dengan konsep sendiri seperti Pod, Deployment, dan Service yang berbeda dari terminologi Docker biasa, serta arsitektur kontrol yang lebih kompleks namun juga jauh lebih fleksibel untuk kebutuhan skala besar.
Tidak ada jawaban tunggal mana yang "lebih baik" di antara keduanya, karena keputusan ini bergantung pada kebutuhan tim dan skala infrastruktur yang dikelola. Tim kecil atau proyek yang sudah nyaman dengan ekosistem Docker biasanya lebih cepat mengadopsi Swarm karena kurva belajarnya rendah, sementara organisasi dengan kebutuhan skala besar, ekosistem tooling yang luas, atau yang sudah memakai layanan managed Kubernetes dari cloud provider cenderung memilih Kubernetes meski kurva belajarnya lebih terjal. Keduanya sama-sama menjalankan container berbasis image Docker biasa di baliknya, sehingga image dan Dockerfile yang sudah dibangun tetap bisa dipakai terlepas dari platform orkestrasi mana yang akhirnya dipilih untuk menjalankannya di production.

