Docker menempatkan seluruh mesin container pada satu proses: daemon dockerd yang berjalan sebagai root dan menerima perintah lewat socket. Arsitektur itu praktis, tetapi konsekuensinya besar — daemon mati berarti semua container kehilangan pengelolanya, dan siapa pun yang bisa bicara ke socket-nya memegang kekuasaan root di host. Podman membuang perantara itu sepenuhnya: perintah podman menjalankan container langsung sebagai proses anak, dan berjalan tanpa root sejak awal. Chapter ini membedah arsitektur daemonless, keunggulan rootless, konsep pod, dan ekosistem di sekitarnya — dan karena podman tidak terpasang di lingkungan latihan, pembuktiannya lewat fixture dan simulasi yang bisa diverifikasi.

Arsitektur Tanpa Daemon #

Dalam Docker, docker run sebenarnya tidak menjalankan container: perintah itu mengirim permintaan ke dockerd lewat /var/run/docker.sock, dan daemon-lah yang mem-fork container. Podman membuang perantara: podman run mem-fork container sebagai proses anaknya sendiri, dikawal proses kecil bernama conmon yang mencatat log dan melaporkan exit code. Konsekuensinya bertingkat:

AspekDockerPodman
Arsitekturclient–server lewat daemon dockerdlangsung fork–exec dari CLI
Daemonsatu proses untuk semua containertidak ada; tiap container mandiri
Daemon maticontainer kehilangan pengelolatidak ada yang berubah
Pemegang kuasaroot (atau anggota grup docker)user yang menjalankan perintah
Auto-restartfitur daemon --restartdiserahkan ke systemd

Baris terakhir bukan kelemahan melainkan pilihan sadar: alat yang tepat untuk proses yang harus selalu hidup adalah service manager, dan integrasinya kita praktikkan pada bagian penutup chapter.

Komando Kompatibel #

Podman sengaja memelihara kompatibilitas dengan CLI Docker — banyak skrip lama cukup mengganti kata pertamanya:

DockerPodman
docker run -d --name web nginxpodman run -d --name web nginx
docker ps -apodman ps -a
docker build -t app .podman build -t app .
docker exec -it web shpodman exec -it web sh

Bahkan alias docker=podman di ~/.bashrc sudah cukup untuk sebagian besar kasus. Nama berkas resepnya pun dibakukan ulang menjadi Containerfile — isinya sama persis dengan Dockerfile, dan podman membaca kedua nama itu. Berikut contoh tampilan podman ps pada mesin dengan dua container rootless:

text
CONTAINER ID  IMAGE                          COMMAND               STATUS         PORTS                 NAMES
3f9c2a1b8e74  docker.io/library/nginx:1.27   nginx -g daemon o...  Up 2 minutes   0.0.0.0:8080->80/tcp  web-toko
8d4e6f0a2c19  docker.io/library/postgres:17  postgres              Up 2 minutes                         db-toko

Rootless dan User Namespace #

Keunggulan keamanan terbesar podman ada pada satu kata: rootless — container berjalan tanpa user root di host. Mekanismenya adalah user namespace: kernel memetakan ulang UID. User budi di host memetakan dirinya sebagai UID 0 di dalam container (di sanalah asal root di dalam container), sementara 65.535 UID berikutnya diambil dari rentang bawahan yang terdaftar di /etc/subuid. Berikut isi tipikal berkas itu:

bash
# format subuid: nama:start:jumlah
printf 'budi:100000:65536\nsiti:265536:65536\n' > subuid
cat subuid
awk -F: '{printf "%s: UID %d s/d %d (%d UID bawahan)\n", $1, $2, $2+$3-1, $3}' subuid

Output yang Dihasilkan:

text
budi:100000:65536
siti:265536:65536
budi: UID 100000 s/d 165535 (65536 UID bawahan)
siti: UID 265536 s/d 331071 (65536 UID bawahan)

Mari kita bedah bloknya:

  1. printf ... > subuid: fixture dua baris — setiap user mendapat satu rentang; angka berapa pun sah asalkan antar user tidak tumpang tindih.
  2. awk -F: '{printf ...}': memisah kolom pada titik dua; UID terakhir rentang dihitung $2+$3-1, yaitu awal ditambah jumlah dikurangi satu.
  3. Makna pemetaan: UID 0 di dalam container budi sebenarnya adalah budi di host, dan UID 1 sampai 65535 di dalam container dipetakan ke rentang 100000 ke atas.

Hasilnya dua lapis keuntungan. Pertama, proses root di dalam container tidak pernah menjadi root di host — satu lubang sekalipun prosesnya lolos keluar, yang ditemukannya tetap akun budi. Kedua, file yang ditulis root di dalam container jelas dimiliki budi di host — data database bisa dibaca tanpa sudo. Bandingkan dengan mode rootful, tempat root container benar-benar root host: satu celah keluar langsung berakhir di akun paling kuat.

Pod: Beberapa Container Satu Rumah #

Pod adalah satu unit yang berisi beberapa container berbagi namespace — jaringan yang sama, alamat IP yang sama, bahkan localhost yang sama. Konsepnya diadopsi dari Kubernetes: satu pod membawa satu tugas logis yang terdiri dari beberapa proses. Pattern klasiknya sidecar: aplikasi utama dan container kecil pengirim log di sebelahnya saling bicara lewat localhost tanpa jaringan virtual apa pun.

Beda konsepnya dengan Compose penting dipahami: compose menyatukan container-container yang terpisah lewat jaringan dan DNS; pod menyatukan container yang berbagi rumah.

AspekPodDocker Compose
Hubungan antar containersatu network namespace, saling lewat localhostjaringan virtual, saling lewat nama DNS
Wujud deklarasimanifest Kubernetes-style YAMLdocker-compose.yml
Cocok untuksidecar — proses yang padu (app + log shipper)aplikasi multi-service utuh (web + db + cache)

Dua perintahnya: podman pod create --name toko --publish 8080:80 membuat pod kosong dengan port milik pod itu sendiri, lalu podman run --pod toko ... memasukkan container ke dalamnya. Port di-publish sekali di pod, bukan per container — karena memang seluruh pod berbagi satu stack jaringan.

Ekosistem dan Integrasi systemd #

Podman tidak berdiri sendiri; tiga alat satu keluarga membagi tugas yang di Docker dipegang satu daemon:

AlatTugas
podmanmenjalankan dan mengelola container
buildahmembangun image tanpa daemon, langkah demi langkah, dari script sekalipun
skopeomenyalin dan memeriksa image antar registry tanpa menjalankan container

Untuk compose file yang sudah ada, podman-compose membacanya dan menjalankan tiap service lewat podman. Kontinuitas Dockerfile juga terjaga — berkas Containerfile berikut tersedia di bundle materi ini:

bash
cat Containerfile
echo '== audit cepat =='
echo '-- FROM (versi dipin):'
head -1 Containerfile
echo '-- USER (non-root):'
grep '^USER' Containerfile
echo '-- CMD (bentuk exec, bukan shell):'
grep '^CMD' Containerfile

Output yang Dihasilkan:

text
FROM docker.io/library/debian:12-slim
RUN apt-get update \
 && apt-get install -y --no-install-recommends python3 \
 && rm -rf /var/lib/apt/lists/*
COPY server.py /app/server.py
USER 1000:1000
WORKDIR /app
CMD ["python3", "server.py"]
== audit cepat ==
-- FROM (versi dipin):
FROM docker.io/library/debian:12-slim
-- USER (non-root):
USER 1000:1000
-- CMD (bentuk exec, bukan shell):
CMD ["python3", "server.py"]

Mari kita bedah Containerfile baris demi baris:

  1. FROM docker.io/library/debian:12-slim: image dasar dipin ke versi spesifik; prefiks docker.io/library/ adalah nama registry lengkap yang selalu ditampilkan podman — tidak ada image “anonim”.
  2. RUN apt-get ... && rm -rf /var/lib/apt/lists/*: satu layer untuk pasang dan bersih-bersih — cache paket tidak ikut menggembungkan image.
  3. COPY server.py /app/server.py: hanya satu berkas yang disalin; WORKDIR /app menetapkan direktori kerja setelahnya.
  4. USER 1000:1000: proses berjalan sebagai UID 1000, bukan root — kebiasaan yang dibedah tuntas di Chapter Container Security .
  5. CMD ["python3", "server.py"]: bentuk exec form — proses berjalan sebagai PID 1 tanpa shell pembungkus.

Satu kekosongan arsitektur daemonless tetap harus diisi: pada Docker, daemon-lah yang membangkitkan ulang container mati lewat --restart. Tanpa daemon, tugas itu pulang ke alat yang memang ahlinya — systemd. Dua jalurnya: podman generate systemd membuat unit dari container yang sedang jalan, atau Quadlet — berkas .container kecil yang ditaruh di ~/.config/containers/systemd/. Berkas web-toko.container di bundle materi adalah Quadlet:

bash
cat web-toko.container

Output yang Dihasilkan:

text
[Unit]
Description=Web toko (nginx dalam container)

[Container]
Image=docker.io/library/nginx:1.27
PublishPort=8080:80

[Service]
Restart=always

[Install]
WantedBy=default.target

Isinya sebagai berikut:

  1. [Container]: Image dan PublishPort — padanan persis podman run -d --publish 8080:80 docker.io/library/nginx:1.27.
  2. [Service] Restart=always: kebangkitan ulang dipegang systemd, menggantikan --restart=always milik daemon.
  3. [Install] WantedBy=default.target: target user, bukan multi-user.target sistem — karena container ini rootless, unit-nya juga milik user.
  4. Cara pakainya: systemctl --user daemon-reload lalu systemctl --user start web-toko — container menjadi service biasa yang ikut di-boot bersama sesi user.

Podman menjawab dua keberatan lama terhadap container — daemon dan root — tanpa mengubah cara kita berpikir tentang image dan Containerfile. Arah berikutnya menyelam ke lapisan yang selama ini kita perlakukan sebagai kotak hitam: ketika web memanggil db dengan nama, siapa yang menjawab panggilan itu? Chapter Container Networking membedah bridge, NAT, dan DNS di balik layar.

Referensi lanjut: dokumentasi Podman untuk referensi lengkap perintah dan konfigurasi, serta situs Podman untuk pengantar arsitektur daemonless-nya.