Foto arsip docker inspect pada Chapter Docker Inspect membeku keadaan pada satu momen: State.Running bernilai running, batas memori tercatat 268435456 byte — tetapi berapa banyak CPU dan memori yang benar-benar dipakai proses node di dalamnya saat ini, tidak pernah dijawab arsip itu. Siti sedang menjalankan ulang laporan rekap di backend setelah membetulkan bug yang kemarin kita baca jejaknya di log, dan pertanyaan “berapa berat toko-api bekerja sekarang” butuh jawaban yang berdenyut. Chapter ini membuka jendela angka hidup tersebut lewat docker stats — delapan kolom yang menyegar tiap detik, dibaca tanpa memasang satu alat pun ke dalam container.
Kamera yang Dipasang dari Luar #
Sistem monitoring klasik menuntut agen — program kecil yang dipasang di setiap mesin yang ingin dipantau. docker stats tidak memakai pola itu, dan alurnya layak dipahami sebelum kita membaca satu angka pun. Kernel Linux telah menghitung sendiri pemakaian setiap container lewat cgroups — penghitung CPU, memori, blok, dan jumlah proses tertulis di berkas-berkas cgroup milik masing-masing container, dan dialah yang menegakkan batas --memory yang kita pasang di Chapter CPU dan Memory Limit. Daemon Docker tinggal membaca berkas-berkas itu dari luar, ditambah penghitung antarmuka jaringan milik network namespace setiap container, lalu menyajikannya sebagai tabel. Konsekuensinya luas: image apa pun — alpine ramping, distroless, bahkan scratch — otomatis terpantau penuh tanpa satu paket monitoring di dalamnya, dan biaya pengukurannya nyaris nol karena kernel memang sudah menulis angka-angka itu untuk kepentingannya sendiri.
Aliran Langsung Delapan Kolom #
Perintah telanjang docker stats membuka aliran langsung — tabel yang disegarkan berkala selama terminal kita terbuka:
$ docker statsOutput yang Dihasilkan (baris toko-frontend-1, toko-cache-1, dan toko-db-1 dipotong agar tabel tetap muat):
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7389c56ce533 toko-proxy-1 0.07% 5.312MiB / 7.766GiB 0.07% 1.46MB / 2.31MB 12.6MB / 0B 3
20269502f039 toko-backend-1 152.40% 96.84MiB / 256MiB 37.83% 9.87MB / 11.2MB 3.14MB / 0B 11
...Mari kita bedah maknanya kolom demi kolom.
CONTAINER ID dan NAME #
Dua kolom pembuka adalah identitas baris: bentuk pendek ID 12 heksadesimal dan nama container, persis pasangan yang kita kenal dari docker ps. Tanpa argumen, docker stats memantau seluruh container yang sedang berjalan — sama seperti docker ps tanpa -a.
CPU % #
Persentase pemakaian CPU terhadap satu core penuh, dan di sinilah angka paling sering mengejutkan pendatang baru: 152.40% pada toko-backend-1 bukan galat tampilan. Node berjalan sebagai satu proses, tetapi event loop beserta thread pool-nya dijadwalkan lintas core; 152,40 persen berarti kira-kira satu setengah core bekerja penuh untuk rekap Siti. Mesin latihan kita punya 8 core, sehingga plafon teoretis kolom ini adalah 800% — angka di atas 100% adalah keadaan yang sepenuhnya sah pada mesin multi-core, dan makin dekat angka ke 800%, makin sibuk host kita secara keseluruhan.
MEM USAGE / LIMIT dan MEM % #
Pasangan kolom ini membandingkan pemakaian memori saat ini dengan langit-langitnya, lalu menyimpulkannya sebagai persen. Dua baris kita sengaja memperagakan dua wajah kolom LIMIT. Baris toko-proxy-1 menampilkan 7.766GiB — bukan karena nginx diberi batas sebesar itu, melainkan karena container tanpa --memory tidak punya pagar cgroup sama sekali, dan satu-satunya langit-langit yang tersisa adalah seluruh RAM host. Baris toko-backend-1 menampilkan 256MiB — pagar 256 MiB yang tim pasang pada service backend setelah kejadian rekap yang tumbang OOM di Chapter Debugging Container; pemakaian 96,84 MiB berarti proses laporan masih menyisakan ruang aman sekitar 62 persen.
Pagar cgroup juga bisa dipasang kilat untuk melihat wujudnya di tabel:
$ docker run -d --name uji-mem -m 256m alpine:3.20 sleep 600Output yang Dihasilkan:
4e843c9cd556a898b7b02786b81231f4a79fc900a7f608576da4bfb83f6d4bb8$ docker stats --no-stream uji-memOutput yang Dihasilkan:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
4e843c9cd556 uji-mem 0.00% 1.109MiB / 256MiB 0.43% 0B / 0B 0B / 0B 1Flag -m 256m menulis 268435456 byte ke cgroup — angka yang sama yang kita baca lewat {{.HostConfig.Memory}} di chapter sebelumnya — dan kolom LIMIT langsung menyajikannya sebagai 256MiB. Container tidur ini hanya memakai 1,109 MiB, cukup untuk hari ini; kita bereskan bekasnya:
$ docker rm -f uji-memOutput yang Dihasilkan:
uji-memNET I/O dan BLOCK I/O #
Dua kolom berpasangan ini memuat lalu lintas jaringan dan perangkat blok dalam format kumulatif sejak container menyala — angka total yang terus bertambah, bukan laju sesaat. Tanda pemisahnya adalah arah: NET I/O membaca terima / kirim, demikian pula BLOCK I/O untuk baca / tulis. Backend menunjukkan 9.87MB / 11.2MB — wajar untuk laporan rekap yang menarik ribuan baris dari db lalu menuliskan hasilnya; proxy menunjukkan 12.6MB / 0B — banyak membaca berkas statis frontend, nyaris tidak menulis apa pun ke disk. Konsekuensi kumulatifnya penting dicatat: angka yang besar tidak selalu berarti container sedang sibuk — ia bisa sekadar berumur panjang; penghitung baru kembali nol ketika container dinyalakan ulang.
PIDS #
Kolom terakhir menghitung jumlah proses — lebih tepatnya task, termasuk thread — yang hidup di dalam cgroup container. Proxy menampung 3: master nginx beserta dua worker-nya. Backend menampung 11: satu proses node beserta thread pool-nya. Kolom mungil ini adalah pintu menuju kelas kecelakaan yang khas: fork bomb di dalam container bisa meledakkan jumlah task hingga host tumbang, dan cgroups menyediakan pagarnya — pembatasan --pids-limit yang kita bedah nanti pada Chapter PIDs Limit dan Ulimit di Section Manajemen Resource.
Batas Aplikasi Bukan Batas Cgroup #
Satu kebingungan paling umum saat membaca kolom MEM layak diberikan panggung sendiri. Mari kita periksa cache yang kita kenal:
$ docker stats --no-stream toko-cache-1Output yang Dihasilkan:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
69bebb2487a6 toko-cache-1 0.19% 9.84MiB / 7.766GiB 0.13% 1.02MB / 0B 0B / 0B 4Padahal kita ingat betul konfigurasinya: service cache menjalankan redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru sejak Chapter Cache dan Queue. Mengapa LIMIT tetap menampilkan 7,766 GiB?
Potret Sekali dan Flag Lainnya #
Aliran langsung sempurna untuk mata manusia, tetapi skrip dan cron butuh potret sekejap yang selesai lalu keluar:
$ docker stats --no-streamFlag ini memotret satu bingkai lalu mengembalikan prompt — bentuk yang sama dengan yang kita pakai untuk uji-mem dan cache di atas. Seluruh flag pendukungnya dirangkum di tabel berikut:
| Flag | Fungsi |
|---|---|
--no-stream | memotret sekali lalu keluar, alih-alih mengalir terus |
--all / -a | sertakan juga container yang sedang tidak berjalan |
--format | susun sendiri kolom dan isinya lewat Go template |
| argumen nama container | pantau hanya container yang disebut |
Keluaran untuk Skrip dengan –format #
Ketika angka stats ingin diolah lebih lanjut — dicatat ke berkas, dikirim ke dashboard sederhana, atau dibandingkan antar waktu — Go template memangkas tabel menjadi persis yang kita butuhkan, memakai kosakata yang sama dengan --format milik docker inspect:
$ docker stats --no-stream --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}'Output yang Dihasilkan (dipotong):
NAME CPU % MEM USAGE / LIMIT
toko-proxy-1 0.07% 5.312MiB / 7.766GiB
toko-backend-1 152.40% 96.84MiB / 256MiB
...Kata table di depan template menginstruksikan CLI menyusun header secara otomatis, sementara \t memisahkan kolom. Tanpa kata itu, keluaran menjadi baris data polos — bentuk yang paling ramah bagi awk dan pipeline lain.
Satu Container dan Seluruh Project #
Dua pintu terakhir menyesuaikan cakupan pantauan. Pintu pertama: sebut nama containernya, dan aliran langsung menyempit pada satu baris:
$ docker stats toko-backend-1Output yang Dihasilkan:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
20269502f039 toko-backend-1 148.02% 97.11MiB / 256MiB 37.94% 10.1MB / 11.5MB 3.14MB / 0B 11Perhatikan bahwa angkanya tidak lagi persis sama dengan tabel sebelumnya: 148.02% berbanding 152.40% — itulah sifat angka yang berdenyut; setiap penyegaran adalah pengukuran jendela waktu yang baru. Pintu kedua memantau dari sisi Compose:
$ docker compose statsOutput yang Dihasilkan (dipotong):
NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
toko-proxy-1 0.07% 5.312MiB / 7.766GiB 0.07% 1.46MB / 2.31MB 12.6MB / 0B 3
toko-backend-1 152.40% 96.84MiB / 256MiB 37.83% 9.87MB / 11.2MB 3.14MB / 0B 11
...Dua bedah untuk keluaran Compose itu: kolom NAME hadir tanpa CONTAINER ID — Compose memang memanggil penghuninya dengan nama service, bukan ID mentah; dan yang tampil hanya service milik project aktif, sehingga mesin yang menampung banyak project dari banyak orang tetap terbaca rapi tanpa penyaringan manual.
Kolom-kolom tadi menjawab pertanyaan “berapa banyak” dengan sangat baik — CPU, memori, jaringan, blok, jumlah proses, semuanya terukur dan terbarui. Yang tidak pernah dijawab adalah pertanyaan “apa yang barusan terjadi”: kapan cache terakhir dibunuh, siapa yang memulai ulang worker tadi malam, dan kejadian apa persisnya yang mendahului lonjakan CPU itu. Jawaban atas kelas pertanyaan itu hidup di kronik daemon — aliran kejadian yang bertitel docker events, dan itulah chapter berikutnya.
Referensi #
- docker container stats
— referensi resmi delapan kolom beserta flag
--no-streamdan--format. - docker compose stats — tampilan statistik dalam kosakata service dan project.
- Runtime options with Memory, CPUs, and GPUs
— makna
--memory,--cpus, dan--pids-limitdi balik kolom-kolom stats.