Container Healthy, Browser Mati: Jebakan Migrasi Docker Compose
Status healthy lima jam padahal browser di dalam kontainer mati sejak awal. Pelajaran soal user default, HOME, dan healthcheck dari satu migrasi compose.
Barusan, pas preflight rutin, camofox-doctor nyampe di layer L2 dan endpoint pembuka tab balik HTTP 503 tiga kali berturut-turut. Dugaan pertama saya simpel: browsernya crash sesaat, tinggal restart kontainer, beres. Saya salah besar. Log Docker nunjukin pesan yang panjang dan terlalu spesifik buat dilewatin: "Firefox is unable to launch if the $HOME folder isn't owned by the current user". Saya masuk ke kontainer, jalanin ps aux, dan proses Node di PID 1 ternyata jalan sebagai root. Padahal stat di folder home root bilang direktori itu milik uid 1000, user bernama node. Server yang kelihatannya sehat itu nggak pernah bisa bikin satu browser pun hidup.
Default user: jatuh ke root tanpa kita sadari
Semua ini bermula dari migrasi. Kontainer camofox sebelumnya dibuat manual, lalu saya rapikan ke satu file compose bareng service Ollama GPU buat embedding lokal. File barunya saya tulis tanpa directive user dan tanpa env HOME. Padahal dokumentasi resmi Docker bilang jelas: tanpa override, proses kontainer jalan sebagai root [2]. Di image ini, /root malah dimiliki uid 1000, jadi kombinasi "proses root, home milik orang lain" itu persis yang nggak boleh buat Camoufox. Nggak ada yang aneh-aneh dari server Node-nya, tapi Firefox punya guard khusus di startup: sejak Firefox 61, dia menolak jalan sebagai root di sesi user lain, dan itu keputusan sadar Mozilla, bukan bug [4]. Perangkap kepemilikan HOME ini juga sudah lama dikeluhkan orang di repo Playwright [1].
Yang bikin nggak nyaman: selama lima jam lebih kontainer ini dilaporkan healthy. Healthcheck-nya cuma ngecek port via /dev/tcp, dan itu memang lolos terus karena servernya hidup, yang mati kan browsernya. Di referensi docker run, healthcheck didefinisikan sebagai perintah yang dijalankan buat ngecek kesehatan, dengan retry berapa kali sebelum dinyatakan unhealthy [3]. Definisinya nggak salah, tapi gampang banget dipakai dangkal-dangkal aja.
Opini saya sekarang tegas: healthcheck yang cuma membuktikan port terbuka itu lampu hijau palsu. Dia ngasih rasa aman yang nggak berdasar, dan ini bahaya di jam-jam awal insiden justru karena nggak ada alarm. Kalau healthcheck-nya ngelakuin satu aksi yang butuh browser beneran hidup (misalnya bikin tab baru), kontainer ini pasti udah unhealthy dari detik pertama dan saya nggak buang lima jam. Lima jam "healthy" itu bukan jaminan apa-apa; itu cuma bukti kalau pemeriksaannya nggak pernah nyentuh jalur yang rusak.
Pelajaran kedua buat saya: migrasi ke compose itu momen dimana semua asumsi implisit dari setup lama harus dieksplisitkan. User proses, env yang memengaruhi resolusi path kayak HOME, volume yang nyimpen state. Image dengan layout nggak standar itu gampang banget salah pasang kalau file compose-nya ditulis dari ingatan.
Dua baris, dua lapis error
Perbaikan pertama: tambah user 1000:1000 di compose. Saya kira selesai. Eh, yang muncul malah error lapis kedua: HTTP 500 dengan pesan "Version information not found" yang menunjuk file version.json di folder cache si user node. Ternyata Camoufox resolve cache binary-nya lewat variabel HOME, dan begitu prosesnya jalan sebagai uid 1000, HOME jatuh ke folder home user node yang kosongan. Jadi fix-nya dua baris yang harus jalan bareng: