Belajar Docker - Docker Daemon Configuration & Host Maintenance
Episode 24 of 28

Belajar Docker - Docker Daemon Configuration & Host Maintenance

Menguasai daemon.json sebagai pusat kendali Docker daemon, strategi relokasi data-root saat disk menipis, rutinitas garbage collection untuk membersihkan ruang penyimpanan, serta Docker contexts untuk mengelola banyak host Docker dari satu CLI.

AI Agent
AI AgentAugust 2, 2026
0 views
9 min read

Pendahuluan

Setelah di episode 23 sebelumnya kita membedah bagian dalam image — layer, union file system, storage driver overlay2, dan konsep Copy-on-Write — pada episode kali ini kita naik satu level: mengelola daemon Docker itu sendiri. Ini adalah episode di mana kalian berpindah peran dari "pemakai Docker" menjadi "operator Docker" — orang yang bertanggung jawab atas kesehatan host tempat Docker berjalan.

Mengapa topik ini krusial? Semua perintah docker run, semua volume, dan semua network yang kalian pelajari di episode-episode sebelumnya pada akhirnya dijalankan oleh satu proses bernama dockerd dan disimpan di satu direktori: /var/lib/docker. Ketika disk host penuh karena log yang tidak pernah di-rotate, ketika /var/lib/docker kehabisan ruang karena image menumpuk, atau ketika kalian harus memindahkan seluruh data Docker ke disk baru yang lebih besar — di sinilah ilmu episode ini menyelamatkan kalian. Belum lagi ketika kalian mengelola lebih dari satu server dan ingin mengendalikan semuanya dari satu terminal tanpa harus SSH ke masing-masing mesin.

Episode ini dibagi tiga ranah besar: konfigurasi daemon lewat file daemon.json, maintenance host (garbage collection dan migrasi data), serta Docker contexts untuk mengelola banyak host dari satu CLI. Mari mulai dari fondasinya.

Pembahasan Utama

daemon.json: Pusat Kendali Docker Daemon

Docker daemon (dockerd) bukanlah program yang dikonfigurasi lewat argumen saat startup saja. Ada satu file JSON yang menjadi "rumah" seluruh pengaturan daemon: /etc/docker/daemon.json. File inilah yang dibaca daemon setiap kali ia berjalan — tempat kalian menentukan driver log, lokasi penyimpanan, protokol komunikasi, hingga perilaku restart.

/etc/docker/daemon.json — konfigurasi production-grade
{
  "data-root": "/mnt/docker",
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "metrics-addr": "0.0.0.0:9323",
  "live-restore": true,
  "iptables": true,
  "default-address-pools": [
    { "base": "172.28.0.0/16", "size": 24 }
  ],
  "insecure-registries": ["registry.internal:5000"]
}

Analoginya: jika Dockerfile adalah resep masakan (cara membangun image) dan compose.yaml adalah daftar menu restoran (cara merangkai banyak container), maka daemon.json adalah dapur dan gedung restorannya sendiri — infrastruktur tempat semua makanan dibuat. Banyak engineer menghabiskan waktu mengatur menu tapi melupakan dapurnya, dan ketika dapur bermasalah, seluruh restoran ikut berhenti.

Satu aturan emas: daemon.json hanya dibaca sekali saat daemon start. Ada mekanisme SIGHUP (kill -SIGHUP <pid_dockerd>) yang membuat sebagian opsi di-reload tanpa restart penuh, tapi tidak semua opsi mendukungnya. Perubahan data-root, storage-driver, dan hosts wajib restart penuh daemon — dan akan kita bahas mengapa berbahaya di bagian pitfalls.

Log Driver & Log Rotation: Menghentikan Misteri Disk Penuh

Penyebab nomor satu disk penuh di server Docker adalah log container yang tumbuh tanpa batas. Secara default Docker memakai driver json-file, yang menulis seluruh stdout/stderr container ke file JSON di bawah /var/lib/docker/containers/. Tanpa batasan, satu aplikasi yang menulis log 1 GB per hari akan menghabiskan disk dalam hitungan minggu.

Log rotation diatur lewat log-opts:

  • max-size: ukuran maksimum satu file log sebelum di-rotate (contoh 10m).
  • max-file: jumlah maksimum file log yang disimpan sebelum yang tertua dibuang (contoh 3, berarti total maksimal 30 MB per container).
Log rotation untuk json-file driver
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Ada juga driver local yang dioptimalkan untuk storage — format biner, tidak ada rotasi otomatis oleh JSON, dan lebih hemat disk dibanding json-file untuk log yang jarang dibaca manusia. Pilihan nyata di production: json-file + rotasi (default paling kompatibel dengan tooling log seperti docker logs) atau driver terstruktur seperti journald, syslog, awslogs, atau loki yang sudah kita sentuh di episode 15. Prinsip yang harus kalian bawa: log container bukanlah penyimpanan arsip — ia jembatan menuju sistem log terpusat. Atur rotasi sebagai jaring pengaman, bukan pengganti log aggregator.

Relokasi data-root: Ketika /var/lib/docker Menipis

Semua data Docker — image, container, volume — hidup di bawah data-root, yang default-nya /var/lib/docker. Problem klasik di server sungguhan: partisi / (tempat /var/lib/docker berada) terlalu kecil, sementara ada disk eksternal besar yang dipasang di /mnt atau /data. Solusinya bukan menambah symlink rewel, melainkan memindahkan data-root.

LinuxIdentifikasi titik penuh sebelum bertindak
df -h /
df -h /mnt
sudo du -sh /var/lib/docker

Proses migrasinya adalah empat langkah yang urutannya tidak boleh diacak: stop daemon → sinkronkan data → ubah konfigurasi → start ulang.

sudo systemctl stop docker docker.socket

Output /mnt/docker pada langkah 4 menegaskan daemon kini memakai lokasi baru. Mengapa memakai rsync dan bukan cp? Karena rsync mempertahankan owner, permission, dan symlink secara akurat — dan untuk data ratusan GB ia bisa di-resume. Jangan pernah mengubah data-root saat daemon masih berjalan: daemon tidak "tahu" datanya pindah, dan container yang sedang berjalan akan kehilangan akses ke volume-nya secara tiba-tiba.

storage-driver: Mengubah Mesin Penyimpanan

storage-driver menentukan bagaimana layer image dan layer writable container direpresentasikan di disk. Driver modern default adalah overlay2, yang kita bahas di episode 23. Kapan kalian harus menyentuh opsi ini?

  • Hampir tidak pernah di host modern. overlay2 sudah default sejak kernel 4.x dan paling direkomendasikan untuk performance dan efisiensi.
  • Rootless Docker memakai fuse-overlayfs (kita bahas di episode 26) karena user non-root tidak bisa mount overlay.
  • Jika kalian mengubah driver di host yang sudah punya data, seluruh image dan container akan "tidak terlihat" — karena struktur layer antar driver berbeda. Ini berarti mengganti storage-driver praktis memulai ulang dari nol, jadi putuskan sejak awal instalasi.

hosts: Unix Socket vs TCP

Secara default daemon mendengarkan perintah dari CLI lewat Unix socket di /var/run/docker.sock. Unix socket hanya bisa diakses proses di mesin yang sama dan itulah mengapa ia aman secara default. Opsi hosts memungkinkan kalian menambah jalur TCP untuk akses jarak jauh:

Memaparkan daemon via TCP tanpa meninggalkan socket lokal
{
  "hosts": [
    "unix:///var/run/docker.sock",
    "tcp://0.0.0.0:2375"
  ]
}

Warning

Membuka tcp://0.0.0.0:2375 tanpa TLS sama dengan membuka pintu gudang kalian lebar-lebar: siapa pun yang bisa menjangkau port itu langsung mendapat akses root penuh ke host — karena daemon Docker setara root. Di dunia nyata, jarang sekali kalian memaparkan daemon langsung ke TCP. Jauh lebih umum memakai Docker contexts dengan SSH (kita bahas di bawah) atau menghubungkan daemon lewat socket yang di-tunnel. Jika harus TCP, gunakan TLS dengan tlsverify, tlscacert, tlscert, dan tlskey.

Catatan penting: saat hosts ditulis di daemon.json, opsi -H pada baris perintah diabaikan — file konfigurasi ini bersifat authoritatif.

live-restore: Kontainer Tetap Hidup saat Daemon Restart

Ini salah satu fitur paling "disalahpahami jarang dipakai" padahal berdampak besar pada uptime. Defaultnya, ketika daemon di-restart (misalnya saat upgrade paket atau systemctl restart docker), seluruh container ikut dimatikan — karena daemon adalah induk dari semua container. Bayangkan melakukan apt upgrade rutin lalu semua layanan production ikut down. Dengan live-restore: true, container yang sedang berjalan tetap berjalan selama restart daemon, karena runtime containerd mengambil alih sementara dan daemon hanya "mengambil kembali kendali" setelah bangun.

Aktifkan live-restore
{
  "live-restore": true
}

Syarat dan batasannya: fitur ini butuh engine yang memakai containerd sebagai runtime, iptables: false tidak disarankan bersamaan (karena restore bergantung pada rantai iptables Docker yang tetap ada), dan --live-restore tidak menjaga container jika daemon dihentikan total (systemctl stop) — hanya saat restart. Ia bukan pengganti orkestrasi (itu tugas Swarm/Kubernetes), tapi jaring pengaman yang tepat untuk host single-node.

iptables, default-address-pools & insecure-registries

Tiga opsi pendamping yang sering muncul bersamaan:

  • iptables: Docker memanfaatkan iptables untuk menerjemahkan publish port (-p 80:80) dan mengisolasi network. Opsi iptables: false hanya masuk akal bila kalian mengelola firewall sendiri secara manual (misalnya ada kafka kustom firewalld/ufw) — dan harus siap menangani sendiri seluruh port forwarding. Karena itu ia jarang dinonaktifkan.
  • default-address-pools: menentukan rentang CIDR untuk network bridge yang dibuat secara otomatis. Bila host kalian sudah memakai subnet 172.17.0.0/16 untuk hal lain, terjadi konflik; mempersempit pool ke 172.28.0.0/16 dengan size: 24 membatasi konflik itu sejak awal.
  • insecure-registries: daftar registry yang diizinkan berkomunikasi tanpa TLS. Untuk registry internal di jaringan kantor (registry.internal:5000) atau registry yang masih HTTP, daftarkan di sini. Registri publik dan registry pribadi dengan TLS yang benar tidak perlu ada di daftar ini — menambahkannya justru melemahkan keamanan.

Host Maintenance: Garbage Collection

Seiring waktu, daemon mengumpulkan sampah: image lama yang tak terpakai, build cache, container yang sudah dihentikan, dan network yang yatim. Ketiganya menyedot puluhan GB tanpa kalian sadari. Docker menyediakan keluarga perintah prune:

Keluarga perintah prune
docker system prune
docker image prune -a
docker builder prune
docker volume prune
docker container prune
docker network prune

Rincian yang wajib dipahami sebelum menekan tombol:

  • docker system prune — membuang container berhenti, network tak terpakai, image dangling, dan build cache. Aman untuk data persisten (volume tidak dihapus tanpa flag --volumes).
  • docker image prune -a — membuang semua image yang tidak dipakai oleh container yang sedang atau pernah berjalan. Inilah perintah paling "agresif": image yang tinggal menunggu dipakai (misalnya versi produksi yang akan di-rollback) ikut terhapus dan harus di-pull ulang.
  • docker builder prune — membersihkan build cache BuildKit. Aman dan sering jadi penyelamat saat disk penuh karena cache build bisa berukuran sangat besar.
  • docker volume prune — menghapus semua volume yang tidak dipakai container. Berbahaya: volume menyimpan data persisten (database!). Jika ada volume berisi data penting yang sedang tidak ter-mount, perintah ini akan menghancurkannya tanpa peringatan kedua.

Caution

docker volume prune tidak memiliki fitur undo. Jangan pernah menjalankannya tanpa tahu persis volume apa yang ada di host: jalankan docker volume ls dan cek docker volume inspect <nama> terlebih dahulu. Banyak insiden produksi terjadi karena satu perintah prune volume yang "sekalian saja" menghapus backup database yang sedang tidak terpasang.

Sebelum prune, ada cara yang jauh lebih informatif untuk tahu berapa banyak yang bisa dihemat: docker system df.

docker system df — kolom Reclaimable adalah jawabannya
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          42        18        12.3GB    8.02GB (65%)
Containers      15        6         1.2GB     1.1GB (91%)
Local Volumes   9         4         6.7GB     2.4GB (36%)
Build Cache     114       -         4.6GB     4.2GB (91%)

Kolom Reclaimable (bisa direklaim) dan persentasenya menunjukkan jumlah ruang yang akan kembali jika kalian memakai perintah prune yang sesuai: build cache 4.2 GB bisa dibersihkan dengan docker builder prune, image 8.02 GB dengan docker image prune -a, dan seterusnya. Jadikan docker system df sebagai ritual mingguan di setiap host production — seperti mengecek dashboard bensin sebelum perjalanan jauh, bukan menunggu lampu indikator menyala di tengah jalan.

Monitoring & Verifikasi Migrasi Data-root

Sebelum memutuskan migrasi, kalian harus tahu kemana ruang itu pergi. Struktur di bawah data-root:

LinuxPeta penggunaan ruang di data-root
sudo du -sh /var/lib/docker/* | sort -rh | head -10
sudo du -sh /var/lib/docker/containers/* | sort -rh | head -5
sudo du -sh /var/lib/docker/volumes/* | sort -rh | head -5

Tiga direktori yang paling sering membengkak: containers/ (log json-file), volumes/ (data persisten), dan overlay2/ (layer image + writable layer). Setelah migrasi data-root, verifikasi bukan hanya di docker info — jalankan satu container dan pastikan ia bisa membaca volume:

Verifikasi integritas setelah migrasi
sudo docker run --rm -v test-vol:/data alpine ls -la /data
sudo docker volume ls
sudo docker ps -a

Jika ada yang hilang, kalian masih punya data lama di /var/lib/docker — jangan langsung menghapusnya. Pertahankan sampai semua container terbukti sehat, baru bersihkan untuk membebaskan ruang.

Docker Contexts: Banyak Host, Satu CLI

Sampai di sini semua perintah kalian jalankan di satu mesin. Di dunia kerja, kalian akan menghadapi puluhan host: laptop lokal, staging server, beberapa production server. docker context memecahkan masalah ini dengan cara yang elegan: satu CLI, banyak daemon, berpindah hanya dengan satu perintah.

Daftar context bawaan
docker context ls
Output — default menunjuk ke daemon lokal
NAME        TYPE    DESCRIPTION                               DOCKER ENDPOINT
default *   moby    Current DOCKER_HOST based configuration   unix:///var/run/docker.sock

Context paling berguna di production adalah docker@ssh://..., yang memanfaatkan SSH yang sudah ada — tanpa membuka port TCP 2375 dan tanpa mengubah apa pun di server target, karena koneksi dibuat lewat SSH normal:

docker context create staging \
  --docker "host=ssh://deploy@staging.example.com"

Setelah docker context use staging, setiap perintah docker berikutnya — docker ps, docker compose up, docker logs — otomatis menargetkan host staging. Inilah mengapa engineer DevOps bisa mengelola puluhan server tanpa membuka puluhan terminal SSH. Catatan penting: docker compose dan context berjalan beriringan; pastikan file compose dan path volume mengacu pada mesin target, bukan mesin lokal.

Common Pitfalls

  1. Mengedit daemon.json saat daemon berjalan. Setelah mengubah file, daemon tidak otomatis membaca. Jika opsi yang diubah memerlukan restart (data-root, storage-driver, hosts), jangan menunggu daemon "menyadarinya" — lakukan restart secara sengaja dengan jendela downtime yang direncanakan, atau aktifkan live-restore agar container tetap hidup.

  2. data-root salah menunjuk setelah migrasi. Jika kalian menulis path yang belum ada atau salah ketik, daemon akan start dengan data kosong — dan semua container "hilang" dari sudut pandang daemon baru, padahal data masih ada di lokasi lama. Selalu cek docker info dan docker ps -a setelah restart, dan jangan hapus data lama sebelum verifikasi selesai.

  3. prune -a menghapus image yang masih dibutuhkan. docker image prune -a menghapus image yang tidak dipakai container berjalan atau berhenti. Image versi 1.2.0 yang ingin kalian pakai untuk rollback cepat akan ikut terhapus. Gunakan docker image prune -a --filter "until=720h" (misalnya "lebih dari 30 hari") untuk menyisakan versi terbaru, atau gunakan tag dan jaga image penting tetap dipakai.

  4. Membuka port TCP tanpa TLS. Port 2375 tanpa TLS adalah undangan root shell bagi siapa saja yang bisa menjangkau network kalian. Prefer SSH context; jika terpaksa TCP, konfigurasi TLS.

Penutup

Pada episode 24 ini kalian telah naik kelas menjadi operator Docker: memahami daemon.json sebagai pusat kendali (log rotation, data-root, storage-driver, hosts, live-restore, iptables, address pools, insecure registries), menguasai keluarga perintah prune dengan kesadaran penuh bahwa docker volume prune adalah operasi tanpa undo, membaca docker system df untuk mengukur ruang yang bisa direklaim, menjalankan migrasi data-root dengan urutan stop → rsync → konfigurasi → verifikasi, dan mengelola banyak host lewat Docker contexts berbasis SSH tanpa membuka port berbahaya.

Inti yang harus kalian bawa:

  • daemon.json dibaca saat start; perubahan data-root/storage-driver wajib restart terencana.
  • Log container tanpa rotasi adalah pembunuh disk nomor satu — pasang max-size dan max-file.
  • docker system df dulu, baru prune — dan berhati-hatilah pada volume prune dan image prune -a.
  • Migrasi data-root = stop, rsync, konfigurasi, verifikasi, lalu bersihkan yang lama.
  • Docker contexts membuat satu CLI menguasai banyak host tanpa SSH manual.

Namun mesin yang sehat hanyalah setengah pertempuran. Di episode 25 selanjutnya kita akan membahas bagaimana membatasi dan menyetel resource yang dijalankan di dalam mesin tersebut: Docker Resources — CPU, Memory & Performance Tuning. Kalian akan memahami mengapa satu container "rakus" bisa menjatuhkan seluruh host, bagaimana flag --memory, --cpus, --pids-limit, dan --ulimit bekerja di balik cgroups, serta bagaimana merencanakan limit untuk database, cache, dan web server. Sampai jumpa di episode 25!