Port publishing menutup persoalan jaringan, tetapi masih menyisakan satu knob runtime yang kecil sekaligus paling sering dilupakan: direktori kerja — cwd — tempat proses container mulai bekerja. Bagi sebuah proses, cwd menentukan dua hal sekaligus: di mana path relatif diselesaikan, dan berkas mana yang ditemukan oleh skrip yang mengharapkan konfigurasinya berada tepat di sebelah dirinya. Image myapp sudah menetapkan /app lewat instruksi WORKDIR — buktinya kita saksikan pada Chapter WORKDIR dan USER — tetapi Siti baru saja menabrak image pihak ketiga yang mengharuskan dijalankan dari direktori tertentu yang berbeda dari bawaannya. Chapter ini membedah flag -w yang menimpa direktori kerja saat runtime, padanannya pada docker exec, dan bukti bahwa penimpaan itu tidak pernah menyentuh image.

Direktori Kerja Bawaan Image #

Setiap image menyimpan satu nilai direktori kerja pada konfigurasinya, diwarisi dari instruksi WORKDIR saat build, dan setiap proses yang dinyalakan container mulai hidup dari direktori itu. Nilai bawaannya adalah / bila Dockerfile tidak pernah menulis WORKDIR. Kita bandingkan langsung kedua wajah itu:

bash
$ docker run --rm myapp:1.0 pwd

Output yang Dihasilkan:

text
/app
bash
$ docker run --rm alpine:3.20 pwd

Output yang Dihasilkan:

text
/

Mari kita telaah dua jawaban singkat di atas:

  1. /app pada myapp:1.0 — instruksi WORKDIR /app tersimpan sebagai metadata image dan diwarisi setiap container yang berdiri di atasnya; nilai yang sama terbaca lewat docker image inspect --format '{{.Config.WorkingDir}}' myapp:1.0.
  2. / pada alpine:3.20 — Dockerfile alpine tidak menulis WORKDIR, sehingga direktori root filesystem menjadi rumah bawaan proses-prosesnya.
  3. pwd dijalankan sebagai proses utama — ini kembali pola command override dari Chapter Command Override; perintah singkat itu melaporkan cwd-nya sendiri, yang sekaligus adalah cwd bawaan image.

Flag -w Menimpa Direktori Kerja #

Flag -w (bentuk panjangnya --workdir) menimpa direktori kerja untuk container yang sedang diciptakan — mekanismenya persis padanan runtime dari WORKDIR:

bash
$ docker run --rm -w /data alpine:3.20 pwd

Output yang Dihasilkan:

text
/data

Mari kita telaah satu kata yang berubah itu:

  1. -w /data menggantikan / — proses utama container ini mulai hidup di /data, bukan di direktori root bawaan alpine.
  2. Direktori dibuat otomatis bila belum ada — /data tidak ada di dalam image alpine, dan daemon menyiapkannya saat container diciptakan — perilaku yang sama dengan WORKDIR saat build, dikerjakan saat create.
  3. Image tidak tersentuh — penimpaan menempel pada container; docker run alpine:3.20 pwd berikutnya tetap menjawab /.

Path Relatif Dihitung dari -w #

Perpindahan cwd terasa dampaknya begitu perintah memakai path relatif, karena path relatif selalu diselesaikan dari direktori kerja proses. Kita bedah dengan isi image myapp yang sudah kita hafal — dua berkas di dalam /app:

bash
$ docker run --rm -w / myapp:1.0 ls app

Output yang Dihasilkan:

text
package.json  server.js
bash
$ docker run --rm -w /app myapp:1.0 ls

Output yang Dihasilkan:

text
package.json  server.js

Mari kita telaah dua listing yang sama isi namun berbeda jalurnya:

  1. ls app menyelesaikan app dari / — cwd container pertama adalah / hasil timpaan -w, sehingga path relatif app menunjuk ke /app; tanpa timpaan itu, cwd container akan mewarisi /app dari image dan ls app justru mencari /app/app yang tidak ada.
  2. ls tanpa argumen membaca cwd-nya sendiri — container kedua bekerja dari /app, dan ls tanpa path menampilkan isi direktori kerja itu langsung.
  3. Inilah titik rapuh aplikasi — CMD ["node", "server.js"] myapp menemukan berkasnya karena server.js relatif terhadap cwd /app; geser cwd tanpa menyesuaikan, dan Node.js menjawab Error: Cannot find module. Kasus Siti persis seperti itu: skrip pihak ketiga membaca konfigurasi.json secara relatif dan langsung gagal saat image dijalankan dari cwd yang salah.

docker exec Juga Punya -w #

Proses tambahan yang ditanamkan docker exec mendapat cwd yang sama dengan container-nya, tetapi perintah itu punya flag -w sendiri untuk memindahkan proses tamu ke direktori lain. Container web masih berjalan dari Chapter User dan Permissions — bila sudah terhapus, jalankan ulang docker run -d --name web -p 8080:80 nginx:

bash
$ docker exec -w /var/log/nginx web ls

Output yang Dihasilkan:

text
access.log  error.log

Mari kita telaah perintah tanpa satu pun cd itu:

  1. -w /var/log/nginx hanya berlaku untuk proses eksekusi ini — proses utama nginx di dalam web tidak berpindah; hanya ls yang ditanamkan tadi yang mulai hidup di direktori log.
  2. ls tanpa argumen kembali membaca cwd — kedua berkas yang tampil adalah berkas log standar image nginx; perintah ini setara dengan membuka shell, cd /var/log/nginx, lalu ls — diringkas jadi satu baris tanpa sesi interaktif.
  3. Berbeda dengan docker run, exec tidak menyiapkan direktori — flag -w pada exec tidak membuat folder bila path belum ada di dalam container; pastikan path yang dituju memang sudah hadir di image atau di volume yang ditempelkan.

-w Runtime versus WORKDIR Image #

Bukti paling meyakinkan bahwa penimpaan runtime tidak menyentuh image datang dari membandingkan konfigurasi keduanya secara langsung. Budi menjalankan myapp dengan cwd /tmp, lalu membaca konfigurasi container dan konfigurasi imagenya:

bash
$ docker run -d --name myapp-tmp -w /tmp myapp:1.0

Output yang Dihasilkan:

text
4a7e2c9b1d3f6b8d4a2f9c7e1b3d5f7a9c2e4d6f8a1c3e5b7a2d9f4c1e6b3d8a
bash
$ docker inspect --format '{{.Config.WorkingDir}}' myapp-tmp

Output yang Dihasilkan:

text
/tmp
bash
$ docker image inspect --format '{{.Config.WorkingDir}}' myapp:1.0

Output yang Dihasilkan:

text
/app
bash
$ docker rm -f myapp-tmp

Output yang Dihasilkan:

text
myapp-tmp

Mari kita telaah pasangan jawaban yang berbeda itu:

  1. Container menjawab /tmp — saat container diciptakan, daemon menyalin konfigurasi image lalu menimpa bidang WorkingDir dengan nilai -w; salinan itulah yang dibaca docker inspect pada container.
  2. Image tetap menjawab /app — konfigurasi image tidak berubah sedikit pun; container berikutnya tanpa -w kembali mewarisi /app.
  3. docker rm -f membersihkan latihan — container yang hanya hidup untuk membuktikan mekanisme ini langsung dibuang, kebiasaan --rm dalam bentuk manual. Tabel berikut merangkum hubungan keduanya:
AspekWORKDIR di Dockerfile-w saat docker run
Menetapkan saatbuildcontainer diciptakan
Menempel diimage — permanencontainer itu saja
Direktori dibuat bila belum adaya — saat buildya — saat create
Nilai bawaan/ bila instruksi tidak ditulisWorkingDir image
Kapan menangbila runtime tidak menyebut -w-w selalu menimpa WORKDIR image
Proses tambahan execmewarisi cwd containerpunya flag -w sendiri per eksekusi

Kebiasaan Path Absolut #

Direktori kerja adalah kenyamanan, bukan kontrak. Aplikasi yang sehat membaca berkas pentingnya lewat path absolut — dari variabel konfigurasi, environment variable yang kita set pada Chapter Environment Variable, atau lokasi baku image — sehingga cwd tidak pernah menentukan nasibnya. Flag -w paling tepat dipakai untuk image pihak ketiga yang memang mengharuskan cwd tertentu, dan untuk menjalankan ulang berkas kerja dari direktori yang dimaksudkan skrip.

Kasus Siti tadi terjawab dengan pola gabungan: skrip pihak ketiganya dijalankan dengan -w /kerja sambil menempelkan berkas konfigurasi ke path itu, dan skrip menemukan konfigurasi.json tepat di sebelah cwd-nya — tanpa membangun ulang image, tanpa mengubah satu baris kode pihak ketiga. Lima knob runtime pertama Section ini kini lengkap kita pegang: command override mengubah apa yang dijalankan, environment variable mengubah bagaimana aplikasi dikonfigurasi, --user mengubah siapa yang bekerja, -p membuka pintu ke host, dan -w menentukan dari mana pekerjaan dimulai. Namun seluruh konfigurasi itu hanya berlaku selama container hidup — dan kita sudah terlalu sering menyaksikan container mati mendadak: aplikasi crash, OOM killer mengirim sinyal 9, atau host restart di tengah malam. Siapa yang membangkitkan container kembali setelah kejatuhan semacam itu? Docker menyimpan jawaban deklaratifnya pada restart policy — pembuka Chapter Restart Policy.

Referensi #