Chapter Memilih Jenis Mount ditutup dengan satu pola yang belum kita kunci: hampir semua mount yang kita pasang masih terbuka untuk ditulis oleh container. Padahal di dunia nyata, container tidak selalu layak dipercaya memegang pena — aplikasi yang bug bisa menimpa konfigurasi yang seharusnya tak tersentuh, proses yang diretas bisa menulis backdoor ke direktori yang dipasangkan, dan container utilitas yang iseng bisa merusak data referensi milik container lain. Docker menyediakan dua tingkat penguncian: suffix :ro yang membekukan satu mount tertentu, dan flag --read-only yang membekukan seluruh akar filesystem container. Chapter ini membedah keduanya, membuktikan bahwa read-only bekerja satu arah — container ditolak, dunia luar tetap bisa menulis — lalu merangkai kombinasi paling ketat: --read-only berdampingan dengan tmpfs sebagai satu-satunya lubang tempat aplikasi boleh mencoret.
Suffix :ro dan Bentuk Panjangnya #
Volume data-web milik kita — berisi halo.txt plus berkas bawaan nginx — masih menjadi bahan latihan utama. Kali ini kita pasang volumenya ke container nginx baru dengan satu suffix tambahan: :ro di ujung spesifikasi mount:
$ docker run -d --name web-ro \
-p 8081:80 \
-v data-web:/usr/share/nginx/html:ro \
nginxOutput yang Dihasilkan:
24685c86011fdae91da1b411adaf2aa56d7fd858a868ed6b50273f7c9cf29d0fMari kita telaah tiga cara menuliskan penguncian yang sama:
-v data-web:/usr/share/nginx/html:ro— field ketiga pada pola-vadalah mode; kosong berarti read-write bawaan,roberarti read-only untuk container ini.--mount type=volume,source=data-web,destination=/usr/share/nginx/html,readonly— bentuk panjang memakai kuncireadonlypada daftar opsi--mount; pada tingkat API engine, opsi ini terbaca sebagaireadonly=1.tmpfstidak bisa dikunci lewat suffix — hanya volume dan bind mount yang mengenal:ro; tmpfs dikunci lewat--mount ...readonlysaja bila diperlukan.
Kondisi mount tercatat rapi di inspect. Perhatikan dua field yang berubah nilainya:
$ docker inspect web-ro --format '{{json .Mounts}}'Output yang Dihasilkan:
[
{
"Type": "volume",
"Name": "data-web",
"Source": "/var/lib/docker/volumes/data-web/_data",
"Destination": "/usr/share/nginx/html",
"Mode": "ro",
"RW": false,
"Propagation": ""
}
]Dua field itulah yang dibaca daemon saat menolak tulisan: "Mode": "ro" mencatat mode yang kita minta, dan "RW": false menyatakan mount ini tidak boleh ditulis oleh container pemiliknya.
Tulisan dari Dalam Container yang Ditolak #
Membuktikan penguncian semudah mencoba menulis dari dalam container. Kita pinjam tangan touch lewat docker exec:
$ docker exec web-ro touch /usr/share/nginx/html/catatan.txtOutput yang Dihasilkan:
touch: cannot touch '/usr/share/nginx/html/catatan.txt': Read-only file systemPesan itu datang dari kernel, bukan dari Docker. Mari kita telaah apa yang sebenarnya terjadi:
docker exec web-ro touch ...— proses baru dilahirkan di dalam containerweb-rolalu mencoba membuat berkas di path yang termount:ro.Read-only file system— kernel menolak operasi tulis karena mount tersebut dipasang dengan flag read-only di level filesystem; pesan ini identik dengan yang muncul saat kita mencoba menulis ke CD-ROM atau partisi yang di-mountrodi Linux biasa.- Tidak ada proses yang dihukum — container tetap hidup, nginx tetap melayani; yang ditolak hanya operasi tulisnya, bukan container-nya.
Efek Satu Arah: Dunia Luar Masih Bisa Menulis #
Kesalahpahaman paling umum tentang :ro adalah menganggapnya membekukan data itu sendiri. Kenyataannya, :ro hanyalah kacamata yang dipakai satu container — volume atau direktori sumbernya tetap read-write bagi pihak lain. Kita buktikan dengan helper container yang memasang volume yang sama tanpa suffix:
$ docker run --rm -v data-web:/usr/share/nginx/html alpine:3.20 \
sh -c "echo 'Catatan dari helper rw.' > /usr/share/nginx/html/nota.txt"Perintah di atas selesai tanpa keluhan apa pun. Sekarang kita baca berkas itu dari container yang terkunci:
$ curl localhost:8081/nota.txtOutput yang Dihasilkan:
Catatan dari helper rw.Mari kita telaah bukti berjalan ini:
- Helper memasang
data-webtanpa:ro— container helper melihat volume sebagai read-write, sehinggaechomiliknya diterima kernel tanpa keberatan. web-romembaca perubahan seketika — keduanya memasang volume yang sama; tulisan helper muncul sebagai isi situs pada container yang terkunci, karena:rohanya mengatur arah untuk si pemilik suffix, bukan menyegel volume secara global.- Pola yang sama berlaku pada bind mount dari sisi host — pada skenario situs dev Chapter Memilih Jenis Mount, editor di host bebas mengubah berkas sementara container memasangnya
:ro; penolakan hanya berlaku terhadap proses yang berada di dalam container yang memasang mode itu.
Satu volume, dua pasang kacamata — inilah pola yang memungkinkan arsitektur produsen-konsumen: satu container bertugas menulis (job impor data, helper pembaruan), container lain cukup membaca (web server yang menyajikan). Tiga use case paling umum untuk :ro:
| Use case | Contoh | Mengapa :ro |
|---|---|---|
| Konfigurasi produksi | nginx.conf, app.ini yang dipasang ke container | Perubahan hanya lewat alur deploy di host, container tidak bisa mengubah konfigurasinya sendiri |
| Source referensi | Kode yang dipasang ke container pemindai atau penguji | Container hanya perlu membaca; tak ada alasan memberinya pena |
| Data referensi statis | Kamus, daftar harga, geo-IP database | Data dibaca banyak container; menutup jalur tulis mencegah salinan rusak diam-diam |
Kombinasi Keras: –read-only plus tmpfs #
Suffix :ro membekukan satu mount. Flag --read-only jauh lebih radikal: seluruh rootfs container — image beserta writable layer-nya — dipasang read-only, sehingga tidak ada satu path pun di akar filesystem yang boleh ditulis. Aplikasi nyata biasanya masih butuh menggores di dua tempat: berkas sementara di /tmp dan kadang cache di jalur tertentu; untuk itulah tmpfs dipasang sebagai lubang tulis yang diberikan secara sengaja. Kita rangkai keduanya dalam satu simulasi container api yang paling ketat:
$ mkdir -p config && printf 'mode=produksi\n' > config/app.ini
$ docker run --rm --name api-ketat \
--read-only \
--mount type=bind,source="$(pwd)/config",target=/etc/myapp,readonly \
--mount type=tmpfs,destination=/tmp,tmpfs-size=16m \
alpine:3.20 \
sh -c 'cat /etc/myapp/app.ini; touch /berkas-baru; touch /tmp/berkas-oke && ls -l /tmp/berkas-oke'Output yang Dihasilkan:
mode=produksi
touch: can't create '/berkas-baru': Read-only file system
-rw-r--r-- 1 root root 0 Oct 13 15:52 /tmp/berkas-okeTiga baris output itu menceritakan seluruh arsitektur penguncian. Mari kita telaahnya satu per satu:
mode=produksi— bind mountconfigterbaca sempurna di/etc/myapp; konfigurasi datang dari host dan dipasangreadonlydua lapis: flag--read-onlyyang membekukan akar, plus opsireadonlypada bind mount itu sendiri.touch: can't create '/berkas-baru': ...— menulis ke akar filesystem ditolak mentah-mentah; dengan--read-only, writable layer yang biasanya tempat container mencoret ikut terkunci, jadi/berkas-barugagal dibuat meski container berjalan sebagai root./tmp/berkas-oketercipta — tmpfs dengan batastmpfs-size=16mmenjadi satu-satunya wilayah yang boleh ditulis; penulisan itu hidup di RAM dan lenyap saat container berhenti, persis perilaku tmpfs yang kita kenal dari Chapter Tmpfs Mount.- Batas memori sebagai pengaman ekstra —
tmpfs-size=16mmemastikan aplikasi yang liar menulis berkas sementara tidak melahap RAM host; habisnya kuota tmpfs akan menolak tulisan berikutnya alih-alih memperlambat seluruh mesin.
:ro versus –read-only #
Dua tingkat penguncian itu sering tertukar karena namanya mirip. Tabel berikut memisahkan keduanya:
| Aspek | :ro pada satu mount | --read-only pada container |
|---|---|---|
| Cakupan | Hanya path yang di-mount dengan suffix itu | Seluruh rootfs container, termasuk writable layer |
| Tulisan yang masih lolos | Writable layer dan mount lain yang tidak dikunci | Hanya mount rw atau tmpfs yang dipasang setelahnya |
| Yang perlu disiapkan | Tidak ada — aplikasi tidak menulis ke path itu | Aplikasi harus tahu satu-satunya jalur tulisnya, biasanya /tmp |
| Beban operator | Ringan — tambahkan suffix saat docker run | Sedang — setiap kebutuhan tulis harus dipetakan ke tmpfs |
| Cocok untuk | Melindungi config, source, dan data referensi | Hardening ketat dan audit jejak tulis |
Sebelum menutup, kita rapikan panggung latihan: container web-ro sudah menuntaskan tugasnya, sementara nota.txt yang ditulis helper sengaja kita biarkan di dalam data-web — berkas itu akan menjadi saksi bahwa volume terus mengingat seluruh riwayat isinya:
$ docker rm -f web-roOutput yang Dihasilkan:
web-roData kini terlindungi dari tangan-tangan yang tidak seharusnya menulis — tetapi penguncian tidak menolong apa pun terhadap kegagalan disk, kesalahan docker volume rm yang keliru sasaran, atau serangan ransomware yang menyapu seluruh host. Perlindungan terhadap bencana semacam itu hanya ada satu kata: backup. Chapter Backup dan Restore Volume memperkenalkan pola resmi helper container yang membungkus isi volume menjadi arsip tar.gz dan menyuapkannya kembali ke volume baru — keterampilan yang sekaligus menjadi fondasi seluruh strategi migrasi data.
Referensi #
- docker container run
— referensi flag
--read-only,--mount, dan mode mount. - Bind Mounts — contoh resmi bind mount read-only untuk konfigurasi.
- Volumes — perilaku volume yang dipasang ro di satu container dan rw di container lain.