Setelah bisa membuat image sendiri lewat Dockerfile, koleksi image di mesin kita akan bertambah cepat. Setiap eksperimen, setiap perubahan tag, dan setiap build ulang meninggalkan jejak berupa image baru atau layer lama yang menumpuk diam-diam. Bab ini membahas cara mengelola koleksi image tersebut: melihat daftar image yang tersimpan, memberi atau mengubah tag, menghapus image yang sudah tidak dipakai, membongkar isi sebuah image lewat inspect, sampai kebiasaan mengecilkan ukuran image supaya distribusi dan operasional jadi lebih ringan. Developer yang rutin bereksperimen dengan Dockerfile dan Sysadmin/DevOps Engineer yang menjaga disk usage server tetap sehat sama-sama butuh kebiasaan manajemen image yang rapi.
6.1 Melihat dan Listing Images
Perintah paling dasar untuk melihat image yang tersimpan di mesin kita adalah docker image ls. Alias docker images juga tersedia dan berfungsi identik; keduanya sama-sama menampilkan seluruh image lokal beserta repository, tag, ID, waktu pembuatan, dan ukurannya.
docker image lsContoh output dari perintah di atas:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-demo 1.0 a1b2c3d4e5f6 2 hours ago 142MB
nginx 1.27 f7e8d9c0b1a2 3 days ago 54.6MB
alpine 3.20 7144f7bab3d4 2 weeks ago 11.7MBKolom IMAGE ID adalah pengenal unik singkat untuk setiap image, sedangkan kombinasi REPOSITORY dan TAG adalah nama yang lebih mudah dibaca manusia. Kalau daftar image sudah panjang, kita bisa menyaring hasilnya lewat opsi --filter. Misalnya, untuk menampilkan hanya image yang namanya mengandung "alpine":
docker image ls --filter reference=alpineOpsi --filter juga menerima kriteria lain seperti label untuk menyaring berdasarkan metadata LABEL yang ditulis di Dockerfile.
docker image ls --filter "[email protected]"Untuk kebutuhan automasi atau skrip, opsi --format memungkinkan kita mengambil kolom tertentu saja lewat sintaks Go template. Placeholder yang tersedia antara lain .ID, .Repository, .Tag, .CreatedSince, dan .Size.
docker image ls --format "{{.Repository}}:{{.Tag}}\t{{.Size}}"Di lapangan, Sysadmin/DevOps Engineer sering memakai kombinasi --filter dan --format ini di dalam skrip cleanup otomatis, misalnya untuk mendaftar seluruh image dari satu proyek tertentu sebelum diputuskan mana yang masih layak disimpan.
6.2 Tagging Images
Tag adalah label yang menempel pada sebuah image untuk menandai versi atau variannya, seperti dibahas di bab tentang image naming dan tagging. Sub-bab ini fokus ke praktik mengelola tag pada image yang sudah ada di mesin kita, bukan saat proses build.
Perintah docker image tag (alias docker tag) menambahkan tag baru ke image yang sudah ada, tanpa menduplikasi layer-nya sama sekali. Tag baru hanya menambah satu pointer baru yang menunjuk ke layer yang sama.
docker pull alpine:3.20
docker image tag alpine:3.20 alpine:demoCek hasilnya lewat docker image ls; kedua tag alpine:3.20 dan alpine:demo akan tampil sebagai baris terpisah, tapi dengan IMAGE ID yang identik, tanda keduanya benar-benar merujuk pada layer yang sama persis.
docker image ls alpinePola ini paling sering dipakai untuk menyiapkan image sebelum dikirim ke registry, misalnya memberi tag sesuai nama repository tujuan.
docker image tag alpine:3.20 registry.contoh.internal/tim-backend/alpine:3.20Perhatikan format penulisan tag: hanya huruf kecil, angka, titik, garis bawah, dan tanda hubung yang diperbolehkan, dengan panjang maksimum 128 karakter. Menulis tag dengan huruf kapital atau spasi, misalnya alpine:Demo Baru, membuat Docker menolaknya lewat pesan error invalid reference format.
Untuk menghapus satu tag tanpa menghapus layer image-nya (selama masih ada tag lain yang menunjuk ke layer tersebut), pakai docker rmi dengan nama tag yang ingin dilepas.
docker rmi alpine:demoOutput Untagged: alpine:demo menandakan hanya referensi tag tersebut yang dihapus; layer image aslinya tetap tersimpan karena masih dirujuk oleh tag alpine:3.20. Bersihkan juga tag registry yang dibuat sebagai contoh di atas.
docker rmi registry.contoh.internal/tim-backend/alpine:3.206.3 Removing Images
Image yang menumpuk tanpa dibersihkan lama-lama menghabiskan banyak ruang disk, terutama di server CI/CD yang membangun image baru setiap hari. Perintah docker image rm (alias docker rmi) menghapus satu atau beberapa image berdasarkan nama atau ID-nya. Tarik dulu image contoh dan jalankan satu container darinya, supaya kita bisa melihat langsung bagaimana Docker memperlakukan image yang masih dipakai.
docker pull nginx:1.27
docker run -d --name demo-nginx nginx:1.27Coba hapus image tersebut selagi container demo-nginx masih berjalan.
docker image rm nginx:1.27Docker menolak penghapusan dan menampilkan pesan error conflict: unable to remove repository reference "nginx:1.27" (must force) - container <container_id> is using its referenced image <image_id>. Pesan yang sama juga muncul kalau container-nya sudah berhenti tapi belum dihapus; Docker tetap menganggap image itu masih "dipakai" selama container-nya ada. Ini adalah mekanisme pengaman supaya kita tidak sengaja menghapus image yang container-nya masih bisa dijalankan ulang.
Opsi -f pada docker image rm bisa memaksa penghapusan meski image masih dirujuk container, termasuk yang sedang berjalan seperti demo-nginx di atas.
docker image rm -f nginx:1.27Perintah ini berhasil dan menampilkan output Untagged serta Deleted, tapi ini bukan jalan pintas yang aman: container demo-nginx yang tadinya merujuk image itu tidak ikut terhapus, hanya ditinggalkan begitu saja dengan referensi image yang sudah tidak ada lagi. Kalau container tersebut nanti dihentikan dan dicoba dijalankan ulang lewat docker start, Docker tidak akan menemukan image aslinya lagi. Hindari memakai -f sebagai kebiasaan; cara yang lebih aman adalah menghapus dulu container terkait lewat docker rm, baru kemudian menghapus image-nya tanpa perlu opsi -f sama sekali.
docker rm -f demo-nginxUntuk membersihkan image yang sudah tidak dipakai secara massal, Docker menyediakan docker image prune. Tanpa opsi tambahan, perintah ini hanya menghapus dangling images, yaitu layer image yang tidak punya tag sama sekali (biasanya muncul setelah build ulang dengan tag yang sama, sehingga tag lama "terlepas" dari layer sebelumnya dan menyisakan layer tak bernama).
docker image pruneWARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]Untuk menghapus seluruh image yang tidak dipakai oleh container manapun (bukan cuma yang dangling), tambahkan opsi -a. Perintah ini jauh lebih agresif karena bisa menghapus image bertag yang memang belum pernah dipakai container mana pun di mesin tersebut.
docker image prune -aKarena sifatnya destruktif, selalu baca peringatan yang ditampilkan sebelum menekan y, dan pertimbangkan opsi --filter untuk membatasi cakupan penghapusan, misalnya hanya image yang lebih tua dari waktu tertentu.
docker image prune -a --filter "until=24h"Sysadmin/DevOps Engineer yang menjalankan docker image prune -a di server production tanpa mengecek dulu image apa saja yang akan terhapus berisiko ikut menghapus image yang sengaja disiapkan sebagai cadangan rollback, meski image itu belum dipakai container yang sedang berjalan. Jalankan dulu docker image ls atau tambahkan opsi --filter yang spesifik sebelum menjalankan prune tanpa pengawasan di lingkungan production.
6.4 Inspecting Images
Kadang kita perlu tahu detail sebuah image lebih dari sekadar nama dan ukurannya, misalnya environment variable bawaan, entrypoint default, atau OS dan arsitektur yang ditargetkan. Perintah docker image inspect menampilkan seluruh metadata ini dalam format JSON.
docker image inspect nginx:1.27Output-nya cukup panjang, mencakup field seperti Config (berisi Env, Cmd, Entrypoint, ExposedPorts), Architecture, Os, dan RootFS (daftar layer penyusun image). Untuk mengambil field tertentu saja tanpa perlu membaca seluruh JSON, pakai opsi --format dengan sintaks Go template.
docker image inspect --format '{{json .Config.Env}}' nginx:1.27docker image inspect --format '{{.Architecture}}/{{.Os}}' nginx:1.27Kalau nama image yang diberikan salah ketik atau memang belum pernah ditarik ke mesin lokal, docker image inspect menampilkan error Error: No such image: nama-image. Pastikan nama dan tag-nya sudah benar, atau jalankan docker image ls lebih dulu untuk memastikan image tersebut memang ada di mesin kita.
Selain inspect, perintah docker image history menampilkan daftar layer yang membentuk sebuah image, lengkap dengan instruksi Dockerfile yang menghasilkan masing-masing layer dan ukurannya.
docker image history nginx:1.27IMAGE CREATED CREATED BY SIZE
f7e8d9c0b1a2 3 days ago CMD ["nginx" "-g" "daemon off;"] 0B
<missing> 3 days ago STOPSIGNAL SIGQUIT 0B
<missing> 3 days ago EXPOSE 80 0B
<missing> 3 days ago RUN /bin/sh -c set -x && addgroup ... 9.7MB
<missing> 3 days ago ENV NGINX_VERSION=1.27.0 0BKolom CREATED BY pada docker image history memperlihatkan instruksi Dockerfile yang persis menghasilkan layer tersebut, dan kolom SIZE memperlihatkan berapa besar tambahan yang disumbang layer itu ke ukuran total image. Nilai <missing> pada kolom IMAGE bukan berarti data hilang atau korup; itu menandakan layer perantara yang tidak punya image ID tersendiri karena dibuat oleh proses build image dasarnya (base image), bukan oleh instruksi di Dockerfile kita sendiri.
Kombinasi docker image inspect dan docker image history ini sering jadi langkah pertama Sysadmin/DevOps Engineer saat menyelidiki mengapa sebuah image lebih besar dari perkiraan, sebelum mencari cara mengecilkannya lebih lanjut.
6.5 Image Optimization dan Size Reduction
Image yang berukuran besar memperlambat proses pull dan push ke registry, memperbesar permukaan serangan yang harus dipantau, dan memperlambat waktu startup di orchestrator yang perlu mengunduh image baru ke setiap node. Sub-bab ini merangkum kebiasaan mengecilkan ukuran image di luar teknik multi-stage build yang sudah dibahas di bab tentang membuat Dockerfile.
Untuk mempraktikkan langkah-langkah berikut, siapkan image contoh baru. Buat direktori kerja baru berisi Dockerfile yang sengaja ditulis kurang efisien: membuat satu file berukuran 50MB, lalu menghapusnya lagi di instruksi RUN yang terpisah.
mkdir optimize-demo && cd optimize-demoFROM alpine:3.20
RUN dd if=/dev/zero of=/tmp/dummy.bin bs=1M count=50
RUN rm -f /tmp/dummy.binBuild image ini seperti biasa.
docker build -t optimize-demo:1.0 .Langkah pertama sebelum mengoptimasi adalah mengukur, bukan menebak. Pakai docker image history untuk melihat layer mana yang paling banyak menyumbang ukuran, lalu fokuskan optimasi ke layer tersebut lebih dulu.
docker image history --no-trunc optimize-demo:1.0Opsi --no-trunc menampilkan instruksi lengkap tanpa dipotong, berguna untuk melihat perintah RUN panjang secara utuh saat mendiagnosis layer mana yang perlu disederhanakan. Perhatikan pada output-nya: layer dari instruksi dd tercatat berukuran sekitar 50MB, dan layer dari instruksi rm setelahnya tercatat 0B, padahal file yang dihapus sudah tidak ada lagi di filesystem final. Ini membuktikan langsung klaim di sub-bab tentang Dockerfile: menghapus file di instruksi RUN yang terpisah dari instruksi yang membuatnya tidak mengecilkan ukuran image sama sekali, karena layer sebelumnya (yang masih berisi file 50MB itu) tetap tersimpan permanen.
Gabungkan instruksi yang saling berkaitan dalam satu RUN. Perbaiki Dockerfile pada optimize-demo, satukan pembuatan dan penghapusan file dalam satu instruksi RUN yang sama, lalu build ulang dengan tag baru supaya bisa dibandingkan dengan versi sebelumnya.
FROM alpine:3.20
RUN dd if=/dev/zero of=/tmp/dummy.bin bs=1M count=50 && rm -f /tmp/dummy.bindocker build -t optimize-demo:2.0 .Cek ukuran image sebelum dan sesudah optimasi. Bandingkan hasilnya secara konkret, jangan hanya berasumsi sebuah perubahan pasti mengecilkan ukuran.
docker image ls --format "{{.Repository}}:{{.Tag}}\t{{.Size}}" optimize-demooptimize-demo:2.0 seharusnya sekitar 50MB lebih kecil dibanding optimize-demo:1.0, meski isi akhir kedua image (setelah file dihapus) sebenarnya identik. Perbedaan ini berasal murni dari cara instruksi RUN dikelompokkan, bukan dari perbedaan konten. Prinsip yang sama berlaku untuk kebiasaan lain yang sifatnya "buat lalu hapus" di dalam Dockerfile, misalnya download arsip, mengekstraknya, lalu menghapus arsip aslinya, atau menginstal package lewat apt/apk lalu membersihkan cache-nya; semua proses itu harus berada dalam satu instruksi RUN yang sama supaya benar-benar mengecilkan ukuran, bukan sekadar terlihat bersih di baris terakhir. Bersihkan image percobaan setelah selesai.
docker rmi optimize-demo:1.0 optimize-demo:2.0Pindah ke base image yang lebih kecil. Selisih ukuran antar base image bisa sangat signifikan; distro lengkap seperti ubuntu atau debian biasa berukuran puluhan hingga ratusan megabita, sementara varian alpine untuk base image yang sama seringkali hanya beberapa megabita. Bandingkan langsung ukurannya di mesin kita.
docker pull python:3.12
docker pull python:3.12-slim
docker pull python:3.12-alpine
docker image ls pythonPerlu diuji lebih dulu, karena varian alpine memakai musl libc bukan glibc yang dipakai distro Debian/Ubuntu, sehingga sebagian package Python dengan dependency native (misalnya yang butuh kompilasi ekstensi C) bisa gagal terinstal atau berjalan berbeda di atasnya. Varian slim jadi pilihan tengah yang lebih aman kalau kompatibilitas dengan glibc masih dibutuhkan tapi ukuran distro lengkap dianggap berlebihan.
Pertimbangkan alat analisis layer khusus untuk kasus yang lebih kompleks. Selain docker image history bawaan, ada tool pihak ketiga yang dirancang untuk membedah isi setiap layer image secara visual dan menyoroti file-file yang boros ruang, berguna saat penyebab ukuran besar tidak langsung terlihat dari daftar instruksi Dockerfile saja.
Terakhir, jaga kebiasaan membersihkan image lama secara rutin, bukan cuma mengandalkan image baru yang sudah dioptimasi. Jadwalkan docker image prune secara berkala (dengan filter yang aman) di server yang sering melakukan build, supaya ruang disk yang terpakai image lama tidak menumpuk tak terkendali.
| Teknik | Dampak Utama |
|---|---|
| Base image minimal (alpine/slim) | Mengurangi ukuran dasar sebelum instruksi lain ditambahkan |
| Gabung download-ekstrak-hapus dalam satu RUN | Mencegah file sementara tertinggal permanen di layer |
| Bersihkan cache package manager di RUN yang sama | Mencegah cache paket ikut membesarkan layer |
| docker image history untuk audit layer | Menemukan layer yang paling banyak menyumbang ukuran |
| docker image prune terjadwal (dengan filter) | Mencegah penumpukan image lama di disk |

