Ketika kita menjalankan sebuah container, di dalamnya tampak sebuah komputer kecil yang utuh: ada proses bernomor PID 1, ada hostname sendiri, ada antarmuka jaringan sendiri. Padahal di sisi host, container itu hanyalah satu proses biasa — tanpa mesin virtual, tanpa kernel kedua. Ilusi ajaib ini dibangun oleh satu fitur kernel bernama namespace: kemampuan memberi setiap proses kacamata tersendiri dalam melihat sistem. Kombinasi namespaces dengan cgroups dari chapter sebelumnya adalah seluruh rahasia teknis container. Pada chapter ini kita bedah jenis-jenisnya, mengamatinya lewat /proc, dan mencobanya langsung tanpa root lewat unshare.

Masalah: Satu Tampilan Sistem untuk Semua Proses #

Pada sistem Linux biasa, seluruh proses melihat dunia yang sama: mereka sepakat bahwa proses systemd adalah PID 1, bahwa hostname mesin ini adalah server-kantor, dan bahwa user ber-UID 1000 adalah budi. Kesepakatan bersama itu menjadi masalah begitu satu mesin dipakai banyak pihak — server hosting tidak boleh membiarkan proses pelanggan A melihat proses pelanggan B, apalagi mengubah hostname bersama. Virtual machine menyelesaikannya dengan cara mahal: menduplikasi seluruh mesin. Namespace menyelesaikannya dengan cara murah: membuat salinan tampilan untuk sekelompok proses tertentu, sementara kernel yang berjalan tetap satu.

Konsep dan Delapan Jenis Namespace #

Satu namespace membungkus satu kategori resource sistem dan menentukan siapa yang melihat versi mana. Proses menandai keanggotaan namespace-nya pada saat lahir — dari flag clone() atau lewat perintah unshare — dan sejak saat itu setiap akses terhadap kategori tersebut diterjemahkan ke tampilan milik kelompoknya. Linux dewasa ini mengenal delapan jenis:

NamespaceYang diisolasiFlag
pidpenomoran PID; proses pertama terlihat sebagai PID 1CLONE_NEWPID
netinterface, tabel routing, aturan firewall, portCLONE_NEWNET
mntdaftar mount point yang terlihatCLONE_NEWNS
utshostname dan domain nameCLONE_NEWUTS
userpemetaan UID/GID — root di dalam bisa jadi user biasa di luarCLONE_NEWUSER
ipcobjek System V IPC dan POSIX message queueCLONE_NEWIPC
cgrouptampilan direktori /sys/fs/cgroupCLONE_NEWCGROUP
timejam monotonic dan boottime per namespaceCLONE_NEWTIME

Rincian tiap jenis beserta syscall pembuatnya terdokumentasi di halaman manual namespaces(7) . Daftar ini tumbuh seiring usia kernel — user hadir di 3.8 dan time baru menyusul di 5.6 — dan inilah alasan versi kernel menentukan fitur container yang tersedia.

Mengamati Namespace Sebuah Proses #

Keanggotaan namespace setiap proses bisa dilihat langsung di procfs, tepatnya di direktori /proc/<pid>/ns/ — satu symlink per jenis namespace. Menggunakan trik /proc/self dari chapter procfs dan sysfs , kita bisa mengintip milik proses pembacanya sendiri:

bash
ls /proc/self/ns/

Output yang Dihasilkan:

text
cgroup
ipc
mnt
net
pid
pid_for_children
time
time_for_children
user
uts

Sepuluh nama pada output di atas adalah jenis-jenis namespace yang kita bahas plus dua varian *_for_children — penanda namespace yang akan diwarisi proses anak yang diciptakan nanti. Setiap symlink menunjuk ke nama berformat uts:[4026532242]: angka dalam kurung adalah identitas objek namespace di kernel. Dua proses berada di namespace yang sama persis bila symlink mereka menunjuk angka yang sama — itulah cara alat monitoring mengecek siapa-menggunakan-namespace-siapa. Angka identitas berbeda di setiap boot, jadi bandingkan dua nilai dengan test, jangan hafalkan angkanya.

User Namespace: unshare Tanpa Root #

Perintah unshare(1) menjalankan program di namespace baru; nsenter adalah kebalikannya — masuk ke namespace proses yang sudah ada. Umumnya membuat namespace butuh privilege root, kecuali satu: user namespace. Di dalamnya, kernel memetakan ulang UID: proses kita yang biasa dianggap UID 0 (root) di dalam namespace, tanpa kehilangan status user biasa di luar. Flag -U meminta user namespace dan -r memetakan diri kita sebagai root:

bash
unshare -Ur bash -c 'id -un'

Output yang Dihasilkan:

text
root

Mari kita bedah perintah tadi:

  1. unshare -Ur: unshare membuat user namespace baru, flag -U memintanya dan -r memetakan UID/GID kita ke 0 di dalam.
  2. bash -c '...': shell baru lahir sepenuhnya di dalam namespace tersebut.
  3. id -un: mencetak nama user efektif — hasilnya root, meski di luar namespace kita tetap user biasa tanpa hak administratif apa pun.

Inilah “kacamata ajaib” container: proses merasa menjadi root, tetapi privilege-nya cuma berlaku di dalam kaca. Fitur ini jugalah yang membuat demo-demo di bawah bisa kita jalankan tanpa root di lingkungan latihan.

PID Namespace: Dunia dengan PID 1 Sendiri #

Namespace PID memberi kelompok proses sistem penomoran sendiri yang dimulai dari 1. Flag -f membuat unshare mem-fork dulu, dan -p meminta PID namespace; kombinasi -Urfp berarti: buat user namespace agar tak butuh root, fork, lalu pid namespace:

bash
unshare -Urfp bash -c 'echo "bash ini berjalan sebagai PID $$"'

Output yang Dihasilkan:

text
bash ini berjalan sebagai PID 1

Variabel $$ dievaluasi bash di dalam namespace, dan hasilnya 1 — bash tersebut adalah proses pertama dunianya sendiri. Dengan --mount-proc, /proc bisa dipasang ulang di dalamnya sehingga ps hanya menampilkan penghuni namespace itu; memang begitulah container menjalankan nginx sebagai PID 1, padahal di host ia mungkin PID 30217. Penomoran ganda ini murni urusan tampilan — kernel tetap memakai PID asli untuk penjadwalan.

Mount Namespace: Isolasi Daftar Mount #

Namespace mount memberi proses daftar mount point sendiri — begitulah container mendapatkan filesystem yang tampak steril. Kita bisa membuktikan isolasinya dengan memasang tmpfs di dalam namespace lalu memeriksa isi direktorinya dari luar:

bash
unshare -Urm bash -c 'mkdir -p latihan-mnt && mount -t tmpfs tmpfs latihan-mnt && touch latihan-mnt/tersembunyi && ls latihan-mnt'
ls latihan-mnt | wc -l

Output yang Dihasilkan:

text
tersembunyi
0

Bedah blok di atas baris-per-baris:

  1. unshare -Urm: user namespace (-U, -r) membuka izin, flag -m meminta mount namespace untuk shell di dalamnya.
  2. mkdir ... && mount -t tmpfs ...: di dalam namespace, mount diminta menempel tmpfs di latihan-mnt — operasi yang biasanya hanya boleh root, sah karena kita root di user namespace tadi.
  3. touch latihan-mnt/tersembunyi && ls latihan-mnt: file dibuat di tmpfs itu dan tampak oleh proses dalam namespace.
  4. ls latihan-mnt | wc -l (baris kedua blok): dijalankan setelah unshare selesai — direktorinya masih ada, tetapi tmpfs-nya ikut lenyap bersama namespace, sehingga hitungannya 0.

Dari dalam namespace, file tersembunyi tampak berdiri di latihan-mnt; dari luar, tmpfs beserta isinya seolah tak pernah terpasang. File itu bukan disembunyikan dengan flag khusus — mount point-nya memang tidak terdaftar pada tampilan sistem luar. Persis mekanisme inilah yang dipakai overlayfs container untuk menyusun layer image menjadi root filesystem yang tampak utuh.

Namespace Lainnya dan Peran Docker #

Tiga jenis sisanya melengkapi panggung. Namespace net memberi container interface lo plus pasangan kabel virtual (veth) yang menjembatani ke bridge host — sehingga port 80 milik satu container tidak berbenturan dengan milik yang lain, sebagaimana dibedah pada chapter container networking . Namespace uts mengisolasi hostname — mengubah hostname di dalamnya tidak pernah menyentuh hostname asli sistem; ipc memisahkan antrian pesan antar-proses; dan cgroup menyembunyikan hierarki cgroup di luar miliknya.

Docker dan Podman tidak memakai unshare dari shell — runtime container memanggil clone() dengan seluruh flag sekaligus saat membuat container, lalu menggabungkannya dengan cgroups untuk pembatasan resource; peta lengkap kombinasi itu ada pada chapter container concepts . Perintah docker exec pun tak lain daripada nsenter ke namespace container yang sedang berjalan.

Ada satu simpul yang belum terurai: di dalam container kita “root”, tetapi jelas tidak bisa memformat disk host. Antara ilusi root penuh dan user biasa, kernel memecah privilege root menjadi satuan kecil bernama capability — dan itulah topik chapter berikutnya.