Sepanjang Section Dasar Docker CLI, kita sibuk di sisi konsumen: menjalankan container, menghidupkannya kembali, membaca log, dan puncaknya membedah exit code untuk mendiagnosis container yang mati mendadak. Semua perintah itu bekerja di atas satu benda yang selama ini kita perlakukan seperti kotak hitam — image. Padahal struktur internal image menjawab pertanyaan-pertanyaan yang sudah muncul diam-diam: mengapa container bisa menyala hampir seketika, mengapa docker rm tidak pernah merusak image asalnya, dan mengapa mesin yang menarik image serupa bisa menghemat unduhan begitu besar. Chapter ini membuka Section Docker Image dengan membedah struktur tersebut sampai ke fondasinya: layer.
Image sebagai Tumpukan Layer Read-Only #
Kita mulai dari definisi yang sudah dikenal pada Chapter Image, Container, dan Registry: image adalah template read-only yang berisi aplikasi, pustaka, runtime, dan berkas konfigurasi. Definisi itu menjelaskan apa yang disimpan image, tetapi belum menjelaskan bagaimana Docker menyimpannya. Jawabannya adalah struktur yang menjadi jantung seluruh ekosistem Docker: image adalah tumpukan layer yang tersusun dari bawah ke atas.
Ketika seorang developer membangun image sendiri, ia menulis berkas Dockerfile berisi daftar instruksi build. Setiap instruksi yang mengubah isi filesystem — RUN, COPY, dan ADD — menghasilkan tepat satu layer baru di puncak tumpukan. Instruksi yang hanya mencatat metadata — ENV, LABEL, EXPOSE, CMD, dan ENTRYPOINT — juga tercatat sebagai satu langkah build, tetapi layer yang dihasilkannya kosong: nol berkas, hanya konfigurasi yang tersimpan di metadata image. Susunan lengkap tumpukan ini kelak dapat kita baca kembali dengan docker history, materi Chapter Image Inspect dan History.
Sebagai ilustrasi, tabel berikut memetakan Dockerfile sederhana untuk nginx ke dalam layer yang dihasilkannya.
| Instruksi Dockerfile | Layer | Isi layer |
|---|---|---|
FROM debian:bookworm-slim | Layer 1 | filesystem dasar Debian |
RUN apt-get update && apt-get install -y nginx | Layer 2 | hasil instalasi paket nginx |
COPY index.html /var/www/html/ | Layer 3 | satu berkas index.html |
EXPOSE 80 | Layer 4 | kosong — metadata port |
CMD ["nginx", "-g", "daemon off;"] | Layer 5 | kosong — metadata perintah |
Hasil akhirnya adalah lima langkah build yang tersusun sebagai tumpukan: tiga layer berisi berkas dan dua layer kosong berisi metadata. Seluruh tumpukan bersifat read-only — setelah image dibangun, tidak ada satu layer pun yang boleh diubah. Perubahan apa pun terjadi selalu di luar image, dan di situlah writable layer masuk — kita bahas sebentar lagi.
Isi Sebuah Layer: Diff dan Whiteout #
Layer tidak berisi salinan lengkap filesystem, melainkan diff — hanya berkas yang ditambahkan atau berubah dibanding layer tepat di bawahnya. Layer 2 pada tabel di atas, misalnya, hanya menyimpan berkas-berkas yang dibuat oleh apt-get install: biner nginx, modulnya, dan konfigurasi bawaannya, tanpa mengulang isi filesystem Debian dari Layer 1. Format praktis ini membuat layer tetap kecil, mudah didistribusikan, dan mudah dibagikan antar image. Saat container berjalan, Docker menggabungkan seluruh layer dari bawah ke atas sehingga proses di dalamnya melihat satu filesystem yang utuh.
Apa yang terjadi bila sebuah instruksi justru menghapus berkas? Praktik umum di Dockerfile produksi adalah membersihkan dokumentasi dan cache paket setelah instalasi untuk mengecilkan image. Berkas yang hendak dihapus itu tetap utuh di layer bawah — layer bersifat read-only sehingga tidak bisa diubah — sehingga layer di atasnya menyimpan penanda khusus bernama whiteout: berkas kecil yang menyembunyikan berkas di bawahnya saat tumpukan digabungkan. Hasil akhirnya, proses di container tidak lagi melihat berkas itu, seolah-olah berkasnya benar-benar terhapus.
Layer Bersifat Content-Addressable #
Setiap layer diidentifikasi lewat digest — sidik jari sha256: yang dihitung langsung dari isi layernya. Dua layer dengan isi identik akan menghasilkan digest yang identik, di mesin mana pun dan pada waktu kapan pun dibangun. Sifat ini disebut content-addressable: identitas sebuah objek ditentukan oleh isinya, bukan oleh nama yang diberikan manusia. Penyimpanan lokal Docker memanfaatkannya untuk mendedupe layer yang sama, dan registry memanfaatkannya agar satu layer hanya perlu disimpan sekali meski dirujuk banyak image. Inilah mekanisme di balik baris Already exists yang akan sering kita lihat pada output docker pull di chapter-chapter berikutnya.
Writable Layer: Ruang Tulis Container #
Saat docker run dijalankan, Docker tidak menyalin image — daemon cukup menumpuk satu writable layer tipis di puncak tumpukan read-only milik image tersebut. Semua penulisan dari proses container mendarat di layer teratas ini: berkas baru yang dibuat aplikasi, log yang terus bertambah, berkas sementara, sampai perubahan konfigurasi. Kombinasi image plus writable layer plus proses inilah yang disebut container. Desain satu-lapisan-tulis ini sudah kita kenali sekilas pada Chapter Image, Container, dan Registry; sekarang kita bedah mekanismenya.
Mekanisme baca dan tulisnya bernama copy-on-write. Untuk membaca, Docker menggabungkan tumpukan dari atas ke bawah: bila berkas dengan nama yang sama ada di beberapa layer, versi pada layer paling atas yang terlihat oleh proses. Untuk menulis berkas yang berasal dari layer image, Docker menyalin berkas itu lebih dulu ke writable layer, kemudian menulis perubahan pada salinannya — berkas asli di layer image tidak pernah tersentuh. Untuk menghapus berkas milik image, Docker menulis penanda whiteout di writable layer, sama seperti mekanisme penghapusan saat build. Konsekuensinya elegan: ratusan container bisa berjalan dari satu image tanpa satu pun mengotori image tersebut.
Ketika container dihapus dengan docker rm, hanya writable layer yang ikut terbuang; seluruh layer image tetap utuh di penyimpanan lokal. Inilah alasan container kerap disebut sekali pakai: kita bisa bereksperimen sebebas-bebasnya, menghapus container, lalu menjalankan container baru yang bersih persis seperti kondisi pertama kali dijalankan. Data yang memang harus bertahan melewati penghapusan container tidak boleh diletakkan di writable layer — data semacam itu membutuhkan volume atau bind mount, materi Section Penyimpanan Data yang dibuka Chapter Writable Container Layer.
Satu Image untuk Banyak Container #
Karena writable layer adalah satu-satunya bagian yang dimiliki tiap container, menjalankan banyak container dari satu image menjadi sangat murah. Seratus container dari satu image tidak menyalin image itu seratus kali: yang ada adalah seratus writable layer tipis di atas tumpukan read-only yang sama, persis batas analogi class-instansi yang kita bahas pada Chapter Image, Container, dan Registry. Diagram berikut memperlihatkan dua container yang lahir dari satu image nginx:latest dengan enam layer.
Diagram di atas merangkum tiga fakta penting tentang tumpukan layer. Mari kita telaah satu per satu:
- Layer tersusun dari bawah ke atas. Layer 1 adalah basis Debian; setiap layer di atasnya hanya menyimpan diff terhadap layer tepat di bawahnya, dan penggabungan dari bawah ke atas membentuk filesystem utuh yang dilihat proses di dalam container.
- Dua container berbagi tumpukan read-only yang sama. Panah dari Layer 6 ke dua writable layer menunjukkan bahwa container web-1 dan web-2 masing-masing hanya membawa writable layer miliknya sendiri — keenam layer image tidak pernah disalin per container.
- Menghapus container hanya membuang writable layer. Perintah
docker rm web-1membuat writable layer milik web-1 terbuang; tumpukan image tetap utuh dan web-2 tidak terpengaruh sama sekali.
Layer yang Sama, Dibagikan Lintas Image dan Mesin #
Berbagi layer bukan cuma urusan container dengan imagenya — image lain pun saling berbagi layer. Karena layer diidentifikasi lewat digest isi, dua image yang dibangun di atas basis sama akan berbagi layer-layer bawahnya. Mesin latihan kita masih menyimpan nginx:latest — image yang ditarik otomatis ketika kita menjalankan container pertama pada Section Dasar Docker CLI. Sekarang kita tarik satu image kerabatnya, nginx:stable, tag yang menunjuk kanal rilis stabil dari proyek nginx:
$ docker pull nginx:stableOutput yang Dihasilkan:
stable: Pulling from library/nginx
b97706ca828b: Already exists
ca0385813dba: Already exists
d3c681d06bd2: Already exists
9a3f61c5e2b8: Already exists
f1a9e3c7b2d6: Pull complete
8b5d2f9c4a1e: Pull complete
Digest: sha256:a7f2c91e5b8d4c6a3f0e2d9b8c7a5f4e1d3b6c9a2f8e5d7c4b1a9e3f6d2c8b5a
Status: Downloaded newer image for nginx:stable
docker.io/library/nginx:stableMari kita telaah baris-baris output di atas:
stable: Pulling from library/nginx— Docker mengonfirmasi tag yang diminta beserta repositorinya di namespacelibrary/.- Empat baris
Already exists— layerb97706ca828b,ca0385813dba,d3c681d06bd2, dan9a3f61c5e2b8sudah tersimpan di penyimpanan lokal karena isinya identik byte-per-byte dengan empat layer terbawahnginx:latest: basis Debian, paket sistem, pustaka runtime, dan konfigurasi dasarnya. Digest layer yang identik membuat Docker mengenali layer yang sudah dimiliki. - Dua baris
Pull complete— hanya dua layer teratas yang benar-benar diunduh: layer yang berisi biner nginx versi stabil dan skrip entrypoint yang menyertainya, karena keduanya memang berbeda dari miliknginx:latest. Digest:— sidik jari manifest imagenginx:stable; nilainya berbeda dari digestnginx:latestkarena susunan dua layer teratasnya berbeda.Status:dan baris nama lengkap — image baru tersimpan sebagaidocker.io/library/nginx:stable, siap dijalankan tanpa mengunduh ulang keenam layer.
Penghematannya nyata: dari enam layer yang dibutuhkan, hanya dua yang menempuh jaringan. Semakin banyak image berbasis Debian yang kita tarik ke satu mesin — nginx, PostgreSQL, Redis — semakin besar peluang layer bawahnya sudah tersimpan, dan unduhan berikutnya makin ringkas. Bagi registry, penghematan yang sama terjadi di arah penyimpanan: layer yang sama hanya perlu disimpan sekali meski dirujuk oleh banyak image. Dan bagi dua mesin berbeda yang menarik image yang sama, keduanya menyimpan layer dengan digest yang identik — jaminan bahwa image di kedua mesin benar-benar sama byte-per-byte, fondasi reproducibility yang akan kita kunci permanen lewat digest pada Chapter Image Digest.
Struktur image kini bukan lagi kotak hitam: image adalah tumpukan layer read-only berciri content-addressable, container adalah tumpukan yang sama plus writable layer, dan layer yang sama dibagikan lintas image, container, bahkan mesin. Pertanyaan berikutnya muncul sama alaminya: dari mana kita mendapatkan image-image itu? Sebelum bisa menarik image dari registry, kita perlu tahu cara menemukan image yang layak dipakai — dan itu pekerjaan docker search pada Chapter Mencari Image.
Referensi #
- Docker Concepts — penjelasan resmi image berlapis dan relasinya dengan container.
- Container Storage — mekanisme penyimpanan image, copy-on-write, dan snapshotter containerd.
- Dockerfile Reference — perilaku tiap instruksi Dockerfile beserta layer yang dihasilkannya.