Penutup Chapter Memahami Image Tag sengaja menggantung satu janji: digest — identitas yang menjanjikan image yang sama, di mesin mana pun, untuk selamanya. Janji itu bukan basa-basi pemasaran, melainkan konsekuensi langsung dari cara Docker menghitung identitas sebuah image. Selama kita menyebut image dengan nama dan tag, kita sesungguhnya menyebut label yang bisa dipindahkan orang lain; selama kita menyebut digest, kita menyebut isi image itu sendiri. Chapter ini membuktikan janji tersebut: kita mulai dari skenario nyata bagaimana tag bergeser diam-diam, bedah mekanisme digest sebagai hash atas manifest, lalu latihan membaca dan memakai digest mulai dari pull, tabel docker images --digests, sampai mengunci image pada Dockerfile dan berkas compose.
Tag yang Bisa Dipindahkan Penerbitnya #
Kita sudah menetapkan pada Chapter Memahami Image Tag bahwa tag adalah penunjuk yang menempel pada repository, bukan bagian dari isi image. Konsekuensinya perlu kita rasakan sekali lagi dengan skenario nyata. Pada saat riset Course ini, tag nginx:latest menunjuk manifest dengan digest sha256:348334896a68... — image 187MB yang kini tersimpan di mesin latihan kita. Besok waktu penerbit nginx merilis versi baru, yang terjadi hanyalah satu tindakan kecil: penerbit memindahkan penunjuk latest ke manifest baru. Tidak ada pemberitahuan, tidak ada nomor versi yang berubah di nama image, tetapi docker pull nginx:latest pada mesin yang belum punya image lama akan membawa pulang image yang berbeda total dari yang kita unduh hari ini.
Diagram berikut memetakan pergeseran tersebut dari sudut pandang registry:
Mari kita telaah diagram di atas:
- Satu tag, dua nasib. Mesin yang menarik
nginx:latesthari ini dan mesin yang menariknya setelah rilis ulang memakai perintah yang sama, namun menerima image yang berbeda — inilah jebakan tag mutable yang sudah kita bahas tuntas pada Chapter Memahami Image Tag. - Manifest lama tidak musnah. Menggeser tag tidak menghapus apa pun; manifest lama tetap tinggal di registry dan tetap bisa ditarik dengan tepat satu cara: menyebut digest-nya secara langsung.
- Digest tidak ikut bergeser. Manifest lama dan manifest baru masing-masing punya digest yang berbeda dan tetap — digest menempel pada isi, bukan pada label.
Skenario ini menjadi masalah sungguhan begitu reproducibility ikut dipertaruhkan. Pipeline CI yang berjalan dua kali, dua server yang seharusnya identik, audit keamanan yang perlu memastikan image produksi persis sama dengan yang diuji — semuanya tidak bisa bersandar pada nama yang isinya bisa ditukar. Untuk kebutuhan itulah Docker menyediakan referensi berdasarkan digest.
Digest: Hash SHA-256 atas Manifest Image #
Setiap image di registry dibungkus sebuah berkas kecil bernama manifest — daftar seluruh layer penyusun image beserta digest masing-masing, ditambah rujukan ke berkas konfigurasi yang menyimpan ENV, CMD, dan metadata lain. Ketika image didorong ke registry, daemon menghitung hash SHA-256 atas seluruh byte manifest dan menjadikan hasilnya sebagai identitas image: sebuah string sha256: yang diikuti tepat 64 karakter heksadesimal. Bentuk referensinya adalah nama-repositori@digest, misalnya nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5.
Mekanisme ini adalah kelanjutan langsung dari konsep content-addressable yang kita bedah pada Chapter Konsep Image Layer: identitas sebuah objek ditentukan oleh isinya. Cukup satu berkas di satu layer berubah, digest layer tersebut berubah, manifest yang memuatnya berubah, dan digest image pun berubah — rantai hash menjadikan perubahan sekecil apa pun terlihat. Sebaliknya, dua image dengan susunan layer dan konfigurasi yang identik akan memiliki digest yang identik pula, di registry mana pun dan dibangun kapan pun. Karena hash dihitung sekali saat image didorong dan tidak pernah dihitung ulang, penerbit tidak bisa “menggeser” digest: manifest yang berbeda otomatis berdigest berbeda, dan manifest lama tetap mempertahankan digest lamanya selamanya.
Menarik Image dengan Digest #
Referensi digest dipakai persis seperti referensi tag pada docker pull. Mari kita tarik nginx yang sama persis dengan yang tersimpan di mesin latihan kita, kali ini tanpa melibatkan tag sama sekali:
$ docker pull nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5Output yang Dihasilkan:
docker.io/library/nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5: Pulling from library/nginx
Digest: sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5
Status: Image is up to date for nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5
docker.io/library/nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5Kita sudah menyaksikan output yang sama pada Chapter Menarik Image, tetapi sekarang setiap barisnya terbaca dengan makna baru:
- Baris pertama dan baris terakhir — Docker menggemakan referensi lengkap
docker.io/library/nginx@sha256:...; tanda@menggantikan posisi titik dua pada referensi tag, menandakan bahwa yang diminta adalah manifest tertentu, bukan penunjuk bernama. - Baris
Digest:— karakter demi karakter identik dengan digest yang kita ketik; registry menegaskan bahwa manifest yang tersimpan di balik referensi tersebut memang berisi persis seperti yang dijanjikan hash-nya. Status: Image is up to date— mesin kita sudah memiliki image dengan digest tersebut, sehingga nol layer diunduh. Status ini juga berarti identitas telah terverifikasi: mesin lokal dan registry sepakat bahwa keduanya menyimpan manifest yang sama.
Mengetik 64 karakter heksadesimal memang tidak menyenangkan, tetapi justru di situlah nilainya: referensi ini tidak mungkin diketik salah tanpa terdeteksi, tidak mungkin menunjuk image lain, dan tidak akan berubah makna besok pagi. Perintah ini bukan untuk diketik manual setiap hari — melainkan untuk ditempelkan pada berkas konfigurasi yang harus memberikan hasil identik selamanya, seperti yang kita lakukan di bagian akhir chapter ini.
Membaca Digest pada docker images –digests #
Tabel docker images bawaan tidak menampilkan digest, padahal setiap image yang pernah ditarik dari registry menyimpan satu. Flag --digests menambahkan kolom DIGEST ke dalam tabel. Berikut tampilannya pada mesin latihan kita, lengkap dengan tag nginx:1.29.4 yang kita tambahkan pada Chapter Memahami Image Tag:
$ docker images --digestsOutput yang Dihasilkan:
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
nginx latest sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5 613f27b0341a 3 days ago 187MB
nginx 1.29.4 sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5 613f27b0341a 3 days ago 187MB
alpine 3.20 sha256:6e2e0b7054981d48ff3027225d9fb8a6b98e30a32375bb0adc41c1759cf98180 2676beef0bef 2 weeks ago 7.8MB
hello-world latest sha256:6c15599d177bd6b1e977d6aa4e532bdf00dc5c22513503c9cc85c027b3ccab9c e6590340b2f4 2 years ago 13.3kBMari kita telaah kolom DIGEST yang baru tersebut:
- Dua baris nginx berdigest sama. Tag
latestdan tag1.29.4menunjuk satu image yang sama, sehingga kedua baris menampilkan digest dan IMAGE ID yang identik — bukti tabel bahwa keduanya bukan sekadar kebetulan bernilai sama, melainkan memang manifest yang sama. - Digest menyertainya ke mana-mana. Nilai digest hello-world sama persis dengan yang tercetak pada output
docker run hello-worlddi Chapter Menjalankan Container Pertama — digest dicatat saat pull dan tersimpan bersama image selama image itu tinggal di mesin. <none>untuk image buatan lokal. Image yang kita bangun sendiri belum punya digest dari registry mana pun, sehingga kolom DIGEST-nya<none>; nilai baru muncul setelah image didorong ke registry — materi Section Registry dan Distribusi.
Angka di kolom DIGEST adalah alat baca yang jujur: bila suatu hari dua baris yang kita kira sama ternyata berdigest berbeda, dua baris tersebut memang dua image berbeda, seberapa mirip pun nama dan ukurannya.
Digest versus IMAGE ID #
Dua hash panjang dalam tabel di atas — DIGEST dan IMAGE ID — mudah tertukar peran. Keduanya memang sama-sama sidik jari konten, tetapi dihitung dari objek yang berbeda dan dipakai pada saat yang berbeda. Tabel berikut memisahkan keduanya:
| Aspek | Digest | IMAGE ID |
|---|---|---|
| Hash dari apa | manifest image di registry — daftar layer terkompresi plus konfigurasi | berkas konfigurasi image lokal — metadata yang menyusun daftar layer |
| Bentuk tampil | sha256: + 64 karakter heksadesimal | 64 karakter heksadesimal; tabel menampilkan 12 karakter pertama |
| Berlaku | lintas mesin dan lintas registry — sama di mana pun image itu berada | lokal pada mesin tempat image tersimpan |
| Kapan dipakai | mengunci identitas: pull @digest, FROM, berkas compose | mengelola penyimpanan lokal: rmi, inspect, menjalankan image tanpa nama |
Satu tempat untuk melihat keduanya berdampingan adalah field RepoDigests pada hasil docker image inspect. Field tersebut menyimpan daftar referensi digest yang diketahui untuk image bersangkutan:
$ docker image inspect nginx --format '{{index .RepoDigests 0}}'Output yang Dihasilkan:
nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5Mari kita telaah perintah dan hasilnya:
--formatdengan{{index .RepoDigests 0}}— template mengambil elemen pertama dari field RepoDigests, yakni referensi digest yang dicatat ketika image nginx ditarik; indeks0dibutuhkan karena RepoDigests berupa daftar — satu image bisa dikenal lewat digest dari beberapa registry.- Isi referensi — bentuk
nginx@sha256:...siap ditempel langsung ke perintah pull tanpa perlu menyusun apa pun; nilai ini pula yang ditampilkandocker rmisebagai barisUntagged: nginx@sha256:...saat image dihapus — materi Chapter Menghapus Image. - Yang tidak terlihat — field
Idpada inspect yang sama berisi IMAGE ID penuh 64 karakter; dua identitas berbeda itu memang tetangga dalam satu berkas metadata, dan keduanya tidak pernah saling menggantikan.
Mengunci Image dengan Digest #
Kekuatan digest baru terasa penuh ketika dipindahkan dari terminal ke berkas konfigurasi. Dalam Dockerfile, baris FROM menerima referensi digest sebagai pengganti tag:
FROM nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5Berkas compose memakai bentuk yang sama pada kunci image:
services:
web:
image: nginx@sha256:348334896a6815a9c39de3ae8b7c3a37d64efbeac71edc6a2f83ee6e0f77a0d5Dengan referensi tersebut, build yang dijalankan bulan depan di laptop Budi dan build yang dijalankan tahun depan di server Siti akan memakai image basis yang identik byte-per-byte — bukan image yang “kemungkinan besar sama”. Praktik ini disebut pinning, dan seluruh strategi lockfile untuk image bekerja di atasnya.
Identitas image kini berada sepenuhnya di tangan kita: tag untuk kenyamanan manusia, digest untuk kepastian mesin, dan inspect sebagai jendela untuk keduanya. Pergeseran tag pada pembuka chapter juga menyisakan satu urusan rumah tangga: image lama yang kehilangan nama, image yang sudah tidak terpakai, dan berbagai sisa eksperimen yang menumpuk di penyimpanan lokal. Chapter Menghapus Image membereskannya satu per satu — mulai dari arti sesungguhnya baris Untagged, sampai alasan Docker menolak menghapus image yang masih dipakai container.
Referensi #
- docker image pull — CLI Reference — sintaks menarik image berdasarkan digest dan perilakunya.
- docker image ls — CLI Reference
— flag
--digestsuntuk menampilkan kolom digest. - nginx di Docker Hub — daftar tag beserta digest masing-masing pada tab Tags.