Penghapusan image pada chapter sebelumnya berlangsung berdasarkan apa yang tercetak di tabel docker images — nama, tag, ID, ukuran. Padahal tabel tersebut hanyalah ringkasan: di balik setiap barisnya tersimpan metadata lengkap yang menjelaskan bagaimana image dibangun, environment apa yang dibawanya, perintah apa yang dijalankannya saat container menyala, dan berapa sumbangan tiap layer terhadap total ukurannya. Dua perintah membuka lemari tersebut: docker image inspect untuk metadata saat ini, dan docker history untuk kronologi build dari instruksi pertama sampai terakhir. Chapter ini membedah keduanya pada image yang sudah kita kenal intim — nginx — lalu mengulanginya pada image buatan sendiri supaya setiap kolom terbaca dengan jelas.

Membedah Metadata dengan docker image inspect #

Perintah docker image inspect mengembalikan seluruh metadata image dalam format JSON. Tanpa argumen tambahan, hasilnya panjang dan bertingkat, jadi berikut kita tampilkan bagian yang paling sering dibaca — field lain dipotong dengan ...:

bash
$ docker image inspect nginx

Output yang Dihasilkan:

json
[
    {
        "Id": "sha256:613f27b0341a...",
        "RepoTags": [
            "nginx:latest"
        ],
        "RepoDigests": [
            "nginx@sha256:348334896a68..."
        ],
        "Parent": "",
        "Created": "2026-10-10T09:26:51Z",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            ...
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.29.4",
                "NJS_VERSION=0.8.9",
                "NJS_RELEASE=2~bookworm",
                "DYNPKG_RELEASE=1~bookworm"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            ...
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 186948352,
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:b97706ca828b...",
                ...
            ]
        }
    }
]

Nilai Id dan RepoDigests dipotong agar ringkas — bentuk lengkapnya adalah 64 karakter heksadesimal yang sudah kita kenal pada Chapter Image Digest. Mari kita telaah field-field pentingnya:

  1. Id — IMAGE ID penuh: hash atas berkas konfigurasi image, persis definisi yang kita tetapkan pada Chapter Melihat Image Lokal; dua belas karakter pertamanya adalah 613f27b0341a yang tampil di tabel docker images.
  2. RepoTags dan RepoDigests — dua jenis nama yang dimiliki image: tag untuk manusia, digest untuk kepastian mesin; tag nginx:1.29.4 yang kita hapus pada Chapter Menghapus Image tidak lagi tercantum, dan itulah bukti terbaru bahwa penghapusan tag memang hanya melepas nama.
  3. Created — waktu penerbit membangun image (10 Oktober 2026), bukan waktu kita menariknya; nilai inilah yang diringkas menjadi “3 days ago” pada tabel.
  4. Config.Cmd — perintah bawaan saat container dari image ini dijalankan: nginx -g daemon off; — perintah yang sama dengan baris CMD pada tabel Dockerfile ilustratif Chapter Konsep Image Layer, kini tampil sebagai metadata sungguhan.
  5. Config.Env — environment variable bawaan image; NGINX_VERSION=1.29.4 mencatat versi nginx yang terpasang, dan seluruh nilai ini diwarisi oleh setiap container dari image tersebut.
  6. Config.ExposedPorts — deklarasi port 80/tcp; deklarasi ini mendokumentasikan niat image, sedangkan penerbitan port ke host tetap urusan flag -p saat docker run.
  7. Architecture, Os, dan Size — platform image (amd64/linux) dan ukurannya dalam byte: 186948352 byte adalah angka yang dibulatkan menjadi 187MB pada tabel docker images; ditambah RootFS.Layers yang merinci daftar layer — dimulai dari sha256:b97706ca828b..., layer pertama yang kita lihat terunduh pada pull pertama.

Menyaring Field dengan –format #

JSON penuh berat dibaca mata dan tidak enak dipakai skrip. Flag --format menyaring field yang kita butuhkan dengan template Go — gaya yang sama dengan docker images --format pada Chapter Melihat Image Lokal:

bash
$ docker image inspect nginx --format '{{.Size}}'

Output yang Dihasilkan:

text
186948352
bash
$ docker image inspect nginx --format '{{.Config.Cmd}}'

Output yang Dihasilkan:

text
[nginx -g daemon off;]
bash
$ docker image inspect nginx --format '{{json .Config.Env}}'

Output yang Dihasilkan:

text
["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.29.4","NJS_VERSION=0.8.9","NJS_RELEASE=2~bookworm","DYNPKG_RELEASE=1~bookworm"]

Mari kita telaah ketiga template tersebut:

  1. {{.Size}} — mengambil satu field angka apa adanya; cocok untuk skrip yang menghitung atau membandingkan ukuran image dalam byte presisi.
  2. {{.Config.Cmd}} — menulusuri field bertingkat; nilai berupa daftar dicetak dengan elemen dipisah spasi, sehingga [nginx -g daemon off;] adalah seluruh isi Config.Cmd dalam satu baris.
  3. {{json .Config.Env}} — kata kunci json mengubah field menjadi JSON valid; hasilnya bisa langsung diteruskan ke parser lain, dan pola {{json .Config}} untuk seluruh blok konfigurasi juga sah.

Image Inspect versus Container Inspect #

Dunia perintah inspect memiliki dua pintu yang sering tertukar: docker image inspect memeriksa image, sedangkan docker inspect (tanpa kata image) memeriksa container. Tabel berikut memisahkan keduanya:

Aspekdocker image inspect nginxdocker inspect web
Objek yang diperiksaimage — cetakbiru read-onlycontainer — instansi yang hidup atau berhenti
Pertanyaan yang dijawabimage ini dibangun dengan konfigurasi apacontainer ini berjalan dengan pengaturan runtime apa
Field khasConfig.Cmd, Config.Env, Size, RootFSState.Status, NetworkSettings, Mounts
Isi yang berubahtidak pernah — image immutableberubah mengikuti siklus hidup container

Konfigurasi pada container bisa menimpa image asalnya — docker run menerima flag untuk mengganti Cmd, menambah Env, hingga menerbitkan port — sehingga saat men-debug container yang berperilaku aneh, kedua inspect perlu dibaca berpasangan: image menyatakan niat awal, container menyatakan kenyataan runtime. Membedah metadata runtime tersebut kita kerjakan tuntas pada Chapter Docker Inspect di Section Observability dan Troubleshooting.

Membaca Riwayat Build dengan docker history #

Metadata menyimpan keadaan akhir image; docker history menyimpan perjalanannya. Setiap baris output mewakili satu instruksi build, tersusun dari yang terbaru di atas sampai yang pertama di bawah:

bash
$ docker history nginx

Output yang Dihasilkan:

text
IMAGE          CREATED      CREATED BY                                    SIZE     COMMENT
613f27b0341a   3 days ago   CMD ["nginx" "-g" "daemon off;"]              0B
<missing>      3 days ago   STOPSIGNAL SIGQUIT                            0B
<missing>      3 days ago   ENTRYPOINT ["/docker-entrypoint.sh"]          0B
<missing>      3 days ago   EXPOSE 80                                     0B
<missing>      3 days ago   COPY 30-tune-worker-processes.sh /docker-e…   6.62kB
<missing>      3 days ago   COPY 20-envsubst-on-templates.sh /docker-e…   24.4kB
...
<missing>      3 days ago   RUN /bin/sh -c set -x && groupadd --syste…    61.5MB
...
<missing>      3 days ago   ENV DYNPKG_RELEASE=1~bookworm                 0B
...
<missing>      3 days ago   ADD file:575fdc0b44c3e7c309642c3a9c2d5d1…     74.8MB

Beberapa baris di antaranya dipotong dengan ... — output aslinya memuat lebih dari sepuluh baris. Mari kita telaah cara membacanya:

  1. Tiap baris adalah satu langkah build. Baris CMD paling atas adalah instruksi terakhir Dockerfile nginx; makin ke bawah makin awal waktunya, sampai baris ADD paling bawah yang menaruh filesystem basis Debian.
  2. CREATED BY adalah instruksi pembentuk baris. Nilainya persis instruksi Dockerfile — COPY, RUN, ENV, sampai CMD — lengkap dengan argumennya yang dipotong oleh CLI agar muat di kolom.
  3. SIZE adalah delta layer, bukan ukuran total. Instruksi metadata seperti CMD, STOPSIGNAL, dan EXPOSE menulis 0B karena layer-nya kosong — persis pembedaan instruksi berisi dan instruksi metadata pada Chapter Konsep Image Layer; baris berisi berkas menuliskan besarnya sumbangan layer tersebut.
  4. Dua baris raksasa menjelaskan 187MB. Baris RUN set -x berukuran 61.5MB (instalasi paket nginx beserta dependensinya) dan baris ADD berukuran 74.8MB (filesystem Debian) — keduanya menyumbang mayoritas ukuran image, dan sisa baris lainnya kecil-kecil saja.
  5. <missing> di kolom IMAGE bukan kerusakan. Hanya baris teratas yang menampilkan IMAGE ID 613f27b0341a karena hanya layer teratas yang identitasnya terikat pada image final; layer-layer di bawahnya dibangun di infrastruktur penerbit di Docker Hub, dan mesin lokal hanya menyimpan kontennya — tidak menyimpan ID menengah dari langkah-langkah build tersebut. Penanda <missing> adalah cara Docker berkata jujur: baris itu ada isinya, identitas langkah buildnya tidak tersimpan.

Riwayat Image Buatan Sendiri #

History image tarikan penuh <missing> dan instruksi panjang milik orang lain. Untuk melihat sejarah yang sepenuhnya milik kita, Budi menyiapkan Dockerfile lima instruksi sebagai pratinjau kecil dari Section Dockerfile — detail tiap instruksinya akan dibedah di sana; saat ini yang penting hanya lima barisnya:

dockerfile
FROM alpine:3.20
RUN apk add --no-cache curl
WORKDIR /app
COPY app.sh /app/app.sh
CMD ["/app/app.sh"]

Build dijalankan dengan tag myapp:dev:

bash
$ docker build -t myapp:dev .

Output yang Dihasilkan:

text
[+] Building 9.8s (9/9) FINISHED
...
 => [internal] load metadata for docker.io/library/alpine:3.20
 => [1/4] FROM docker.io/library/alpine:3.20
 => [2/4] RUN apk add --no-cache curl
 => [3/4] WORKDIR /app
 => [4/4] COPY app.sh /app/app.sh
 => exporting layers
 => writing image sha256:f20517dd5a48...
 => naming to docker.io/library/myapp:dev

Nilai ID image pada baris writing image dipotong agar ringkas. Perhatikan bahwa CMD tidak muncul sebagai langkah bernomor — instruksi murni metadata tidak membentuk langkah build tersendiri, isinya melebur ke konfigurasi image final. Sekarang kita baca sejarahnya:

bash
$ docker history myapp:dev

Output yang Dihasilkan:

text
IMAGE          CREATED         CREATED BY                                 SIZE     COMMENT
f20517dd5a48   2 minutes ago   CMD ["/app/app.sh"]                        0B
<missing>      2 minutes ago   COPY app.sh /app/app.sh                    129B
<missing>      2 minutes ago   WORKDIR /app                               0B
<missing>      2 minutes ago   RUN /bin/sh -c apk add --no-cache curl     6.42MB
<missing>      2 weeks ago     ADD file:5c5272804ae4a94d3f176e7a5… in /   7.8MB

Mari kita telaah lima baris yang tertata rapi ini:

  1. Lima baris, lima instruksi. CMD, COPY, WORKDIR, dan RUN adalah empat instruksi milik Budi, dan baris paling bawah — ADD milik penerbit alpine — mewakili baris FROM; sejarah image memang berlantai dari sejarah image basisnya.
  2. CREATED baris terbawah berumur dua pekan. Waktu 2 weeks ago adalah saat tim Alpine membangun alpine:3.20, bukan saat Budi membangun myapp — kronologi tiap baris memang milik langkah aslinya.
  3. Ukuran terbaca sebagai resep. Basis alpine 7.8MB, instalasi curl 6.42MB, dan salinan app.sh 129B — akumulasi delta layer membentuk total 14.2MB; karena alpine:3.20 juga tersimpan di mesin, layer 7.8MB itu dibagikan dua image dan disk hanya menyimpannya sekali.
  4. Penanda lama (nop) sudah pensiun. Builder klasik zaman dahulu mencatat instruksi metadata sebagai /bin/sh -c #(nop) CMD ["/app/app.sh"] — penanda #(nop) menegaskan bahwa perintah shell tidak benar-benar dieksekusi; BuildKit, yang menjadi bawaan sejak Docker 23.0, mencatat instruksi apa adanya sehingga kolom CREATED BY tampil bersih seperti di atas.
  5. Image buatan sendiri pun berlaku aturan <missing>. BuildKit menyimpan identitas langkah hanya untuk image final, sehingga empat baris di bawah baris teratas tampil sebagai <missing> — sama dengan image tarikan, dan sekali lagi bukan tanda kerusakan.

Metadata dan sejarah kini terbaca dari dua arah: inspect menjawab “image ini apa dan bagaimana dikonfigurasi”, history menjawab “dari apa image ini tersusun”. Satu kebutuhan praktis masih tersisa pada perjalanan image: bagaimana membawanya ke mesin lain ketika registry tidak bisa dihubungi — server terisolasi jaringan, ruang uji laboratorium, atau transfer antar kantor yang hanya boleh lewat USB. Untuk itu Docker menyediakan pasangan docker save dan docker load, materi Chapter Menyimpan dan Memuat Image.

Referensi #