Sejauh ini kita memvirtualisasi hardware: hypervisor membohongi guest bahwa ada prosesor dan disk tersendiri, lalu guest menjalankan kernelnya sendiri. Pendekatan kedua memotong jauh lebih dalam: kalau yang dibutuhkan aplikasi hanyalah lingkungan yang rapi, kenapa harus mem-boot komputer utuh? Container memvirtualisasi sistem operasi itu sendiri — ratusan aplikasi berbagi satu kernel host, dan masing-masing yakin bahwa ia sendirian di dalam sistem. Hasilnya adalah mesin yang menyala dalam hitungan detik serta image berukuran megabyte, bukan gigabyte. Chapter ini membedah mekanisme di balik klaim itu: proses terisolasi, image berlapis, dan garis batas yang tegas memisahkannya dari virtual machine.

Container Adalah Proses yang Diisolasi #

Dari sudut pandang kernel host, container hanyalah proses biasa — persis proses yang kita bedah di Chapter Process Concepts : punya PID, punya pemilik, tampak di ps. Yang membedakannya adalah dua fitur kernel yang menyulap proses itu seolah-olah berdiri sendiri. Namespace memotong pandangan proses terhadap sistem: namespace PID membuat proses pertama di container melihat dirinya sebagai PID 1, namespace mount memberinya pohon filesystem sendiri, namespace network memberinya interface dan tabel routing sendiri. cgroups memagari sumber dayanya: berapa memori, berapa CPU, berapa proses anak yang boleh lahir. Kedua mekanisme ini dibedah sampai ke detailnya di Chapter Namespaces dan cgroups dan Resource Control — untuk sekarang, satu kalimatnya cukup: container adalah proses biasa yang diberi kacamata dan pagar.

Karena tidak ada guest OS yang di-boot, tidak ada hypervisor yang menerjemahkan instruksi, dan tidak ada kernel kedua yang hidup di memori, container memulai dirinya secepat fork sebuah program. Inilah jawaban atas “kenapa container cepat”: ia tidak melakukan apa pun yang mahal — hanya memasang isolasi lalu menjalankan exec aplikasi.

Image Berlapis dan Copy-on-Write #

Program yang berjalan di container berasal dari image: paket berkas siap pakai yang berisi aplikasi beserta seluruh kebutuhannya. Bagian tersulit memahami image adalah strukturnya: image bukan satu berkas raksasa, melainkan tumpukan layer baca-saja yang disatukan oleh union filesystem — tiap layer berisi hasil selisih dari langkah sebelumnya, dan file dengan nama sama di layer atas menimpa layer bawah. Container yang berjalan hanya menambahkan satu lapisan tipis yang bisa ditulis di puncak tumpukan. Kita bisa merasakan seluruh mekanisme itu dengan direktori biasa:

bash
mkdir -p layer-base/usr/bin layer-app/usr/bin
printf '#!/bin/sh\necho "aplikasi v1"\n' > layer-base/usr/bin/aplikasi
printf '#!/bin/sh\necho "aplikasi v2"\n' > layer-app/usr/bin/aplikasi
printf '#!/bin/sh\necho "cek kesehatan"\n' > layer-app/usr/bin/healthcheck
rm -rf gabungan
cp -r layer-base gabungan
cp -r layer-app/. gabungan/
echo "file yang terlihat dari atas:"
ls gabungan/usr/bin
echo "versi yang berjalan:"
sh gabungan/usr/bin/aplikasi
printf '#!/bin/sh\necho "kustom budi"\n' > gabungan/usr/bin/aplikasi
echo "setelah container mengubah file (copy-on-write):"
sh gabungan/usr/bin/aplikasi
sh layer-base/usr/bin/aplikasi

Output yang Dihasilkan:

text
file yang terlihat dari atas:
aplikasi
healthcheck
versi yang berjalan:
aplikasi v2
setelah container mengubah file (copy-on-write):
kustom budi
aplikasi v1

Mari kita bedah baris demi baris:

  1. Baris 1–5 (mkdir dan printf): membangun dua layer baca-saja — layer dasar berisi aplikasi versi 1, layer aplikasi berisi aplikasi versi 2 plus healthcheck baru.
  2. Baris 6–9 (cp -r ...): mensimulasikan union filesystem — menumpuk layer dasar lalu layer aplikasi di atasnya, sehingga file bernama sama tertimpa versi teratas.
  3. Baris 10–12 (ls dan sh): dari dalam tumpukan, isi terlihat sebagai satu filesystem utuh, dan aplikasi yang berjalan adalah versi 2 — berasal dari layer teratas.
  4. Baris 13–16 (printf > gabungan/...): container mengubah aplikasi — penulisan hanya menimpa lapisan paling atas, dan layer dasar tetap memuat versi 1 yang tak tersentuh.

Dua sifat terakhir itulah copy-on-write: mengubah file di container tidak menyentuh imagenya, dan menghapus container membuang seluruh lapisan tulisnya sehingga image siap dipakai lagi bersih. Simulasi cp di atas tentu menyalin sungguhan, sedangkan union filesystem sungguhan (OverlayFS di Linux modern) menyembunyikan tumpukan itu tanpa menyalin — tapi aturan mainnya sama persis: atas menimpa bawah, tulis hanya di puncak.

Layer yang Dibagi-bagi #

Struktur berlapis bukan sekadar kerapian — ia adalah mesin penghemat. Karena setiap layer diidentifikasi oleh digest sha256 dari isinya, dua image yang memuat layer identik cukup menyimpannya sekali di disk dan mengunduhnya sekali dari registry. Kita bisa menghitung penghematannya dengan jq pada dua berkas image:

bash
cat > img-web.json <<'EOF'
{
  "image": "web:1.4",
  "layers": [
    {"digest": "sha256:deb12", "size": 74200000},
    {"digest": "sha256:py312", "size": 51000000},
    {"digest": "sha256:web14", "size": 3800000}
  ]
}
EOF
cat > img-db.json <<'EOF'
{
  "image": "db:16",
  "layers": [
    {"digest": "sha256:deb12", "size": 74200000},
    {"digest": "sha256:pg16", "size": 88000000}
  ]
}
EOF
echo "layer yang dipakai lebih dari satu image:"
jq -r '.layers[].digest' img-web.json img-db.json | sort | uniq -c \
  | awk '$1 > 1 {print "  " $2 " dipakai " $1 " image"}'
echo "total bila tiap image menyimpan salinan sendiri:"
jq -r '.layers[].size' img-web.json img-db.json \
  | awk '{s+=$1} END {printf "  %.1f MB\n", s/1000000}'
echo "total dengan layer unik saja:"
jq -r '.layers[] | "\(.digest) \(.size)"' img-web.json img-db.json | sort -u \
  | awk '{s+=$2} END {printf "  %.1f MB\n", s/1000000}'

Output yang Dihasilkan:

text
layer yang dipakai lebih dari satu image:
  sha256:deb12 dipakai 2 image
total bila tiap image menyimpan salinan sendiri:
  291.2 MB
total dengan layer unik saja:
  217.0 MB

Mari kita bedah baris demi baris:

  1. Baris 1–16 (cat > img-web.json, cat > img-db.json): dua berkas image dengan satu layer sama — sha256:deb12 adalah ibarat layer dasar “Debian 12” yang dipakai keduanya.
  2. Baris 17–19 (jq ... | sort | uniq -c): menghitung frekuensi tiap digest; layer yang muncul dua kali adalah layer yang cukup disimpan sekali di disk host.
  3. Baris 20–22 (jq -r '.layers[].size'): total ukuran versi naif — bila tiap image membawa salinan lengkapnya sendiri: 291.2 MB.
  4. Baris 23–25 (sort -u): membuang digest kembar — 217.0 MB inilah yang benar-benar dipakai disk, hemat 74 MB berkat satu layer yang sama.

Efek ini berskala besar di dunia nyata: satu host dengan 40 image yang semuanya berbasis Debian memakai satu salinan layer Debian saja, dan pembaruan kecil di puncak image hanya mengunduh beberapa megabyte, bukan ratusan.

Registry: Gudang Image di Internet #

Image disimpan dan didistribusikan lewat registry — layanan yang mengelola push dan pull image. Registry publik terbesar adalah Docker Hub, tempat image resmi seperti debian, postgres, dan nginx tinggal pakai; perusahaan besar biasanya menjalankan registry privat sendiri untuk image internal. Sebuah image diberi alamat lengkap registry/nama:tag: bagian tag biasanya versi (16, 1.4), dan nama tanpa registry berarti Docker Hub. Setiap layer di dalamnya dialamatkan menurut isi — digest sha256 dari bytes-nya — sehingga unduhan yang sama selalu menghasilkan berkas yang identik bit demi bit.

Container vs VM #

AspekContainerVirtual Machine
Yang divirtualisasisistem operasi (kernel dipinjam host)hardware
Kernelsatu kernel host dipakai bersamakernel sendiri per VM
Waktu startdetik, bahkan milidetikpuluhan detik sampai menit
Ukuran imagemegabytegigabyte — disk OS penuh
Kepadatan per hostratusan containerbelasan VM
Batas keamananantar-proses dalam satu kernelhardware — paling tebal

Dua baris pertama menjelaskan tiga baris sisanya: karena tidak ada kernel kedua yang harus boot, tidak ada disk OS penuh yang harus disalin, dan tidak ada memori ratusan megabyte yang dihabiskan kernel tamu. Bayangkan menjalankan postgres sebagai VM versus container: yang pertama menyalakan Linux utuh hanya untuk satu daemon database, yang kedua hanya menjalankan daemon itu sendiri.

Kernel Sharing: Kekuatan dan Batasnya #

Meminjam kernel host adalah alasan container ringan sekaligus batasnya yang paling tegas. Semua container dalam satu host berbagi kernel yang sama, sehingga kernel menjadi single point of trust: celah di kernel berpotensi membuka akses lintas container. Container juga terikat arsitektur dan sistem panggilan host — image Linux tidak berjalan di host Windows tanpa VM perantara, dan image untuk arsitektur ARM berjalan lambat di x86 karena harus diemulasikan.

Kabar baiknya, untuk kebutuhan normal — menjalankan aplikasi tepercaya secara efisien — berbagi kernel justru menyelesaikan masalah klasik pengembangan: “di komputernya jalan”. Image membawa aplikasi, pustaka, dan konfigurasi dalam satu paket yang identik dari laptop developer sampai server produksi, sehingga lingkungan tidak lagi menjadi variabel tersembunyi.

Fondasinya sudah lengkap: proses terisolasi, image berlapis, registry, dan posisinya relatif terhadap VM. Yang belum kita sentuh adalah alat yang membuat semua konsep ini bisa dipakai jutaan orang — Docker. Chapter berikutnya mempraktikkan seluruh siklusnya: menulis Dockerfile, menjalankan container, dan mengelola siklus hidupnya di Chapter Docker .

Referensi lanjut: gambaran umum Docker untuk posisi tiap komponen dalam arsitekturnya, serta konsep building images untuk detail layer yang dipakai build.