Teknologi

Debugging Pipeline Warisan CRA + Django: Postmortem DevOps yang Mengungkap Masalah Tersembunyi

Ringkasan

  • Postmortem DevOps mengungkap masalah tersembunyi saat mengontainerisasi pipeline React CRA dan Django yang sudah usang, mulai dari Dockerfile yang salah, ketidaksesuaian versi Node, hingga kerumitan ekspor paket dan kerentanan keamanan.

Beberapa minggu lalu, saya ditugaskan untuk menyelesaikan dua tugas deployment yang terlihat rutin di atas kertas: mengontainerisasi dan mengirim frontend React, lalu melakukan hal yang sama untuk backend Django. Kedua aplikasi sudah berjalan di suatu tempat—satu di manage.py runserver, yang lain melalui Dockerfile dev yang tidak pernah disentuh selama bertahun-tahun. "Jadikan saja siap untuk produksi" adalah kalimat yang terdengar sederhana, tetapi kenyataannya jauh lebih rumit. Berikut adalah perjalanan saya melalui kegagalan, solusi sementara, dan pelajaran yang dipetik.

Bagian 1: Frontend yang Ternyata Bukan Next.js Dockerfile pertama yang saya warisi terlihat bersih di tahap runner:

FROM node:22-alpine AS runner COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static CMD ["node", "server.js"]

Ini adalah struktur multi-stage yang rapi dengan caching layer yang cerdas, tetapi ada satu masalah: proyek ini dibuat dengan create-react-app melalui craco, bukan Next.js. Direktori .next/standalone tidak pernah ada dalam build CRA, dan tidak ada server Node yang bisa dijalankan. Ini hampir pasti merupakan hasil copy-paste dari proyek Next.js yang tidak pernah disesuaikan. Build akan gagal langsung pada langkah COPY.

Pelajaran pertama: sebelum menyentuh Dockerfile, verifikasi apa yang sebenarnya dihasilkan oleh skrip build. Perintah "craco build" menghasilkan direktori statis build/. Tidak ada trik Dockerfile yang bisa memperbaiki model deployment yang tidak cocok; Anda harus menyesuaikan artefak. Ini berarti mengganti seluruh tahap runner dari proses Node menjadi server file statis nginx.

Dengan masalah frontend teratasi, kegagalan berikutnya adalah rebuild modul native:

error Command "rebuild" not found

Dockerfile tersebut menjalankan yarn install --frozen-lockfile --ignore-scripts, lalu yarn rebuild esbuild sharp. Kata rebuild adalah perintah npm, bukan Yarn Classic. Seseorang telah menonaktifkan skrip install (mungkin untuk mempercepat build atau karena kekhawatiran rantai pasokan) dan kemudian mencoba memaksa kompilasi biner native dengan sintaks dari manajer paket yang salah. Solusinya sederhana: hapus --ignore-scripts, biarkan yarn install menjalankan postinstall secara alami, dan hapus baris rebuild yang rusak.

Namun di balik bug permukaan ini, ada masalah yang lebih dalam: tahap deps menggunakan node:24-alpine sementara tahap builder/runner masih node:22-alpine. Modul native seperti sharp dan esbuild dikompilasi terhadap ABI Node tertentu. Kompilasi di versi 24 tetapi dijalankan di versi 22 berisiko menyebabkan crash saat runtime yang tidak akan terdeteksi oleh CI. Dua versi Node major yang berbeda telah hidup berdampingan karena skrip ignore melewatkan langkah kompilasi native yang seharusnya langsung menunjukkan ketidaksesuaian.

Pelajaran kedua: setiap FROM node:X-alpine dalam build multi-stage harus setuju pada X, kecuali ada alasan khusus. Ketidaksesuaian ABI yang diam-diam terjadi adalah jenis bug yang melewati CI dan muncul di produksi.

Setelah masalah Node teratasi, build yarn build akhirnya berjalan—hanya untuk menemukan:

Error: error:0308010C:digital envelope routines::unsupported

react-scripts@4.0.3 menggunakan Webpack 4, yang bergantung pada internal hashing MD4 Node yang dihapus saat Node bermigrasi ke OpenSSL 3 (Node 17+). Trik standar, NODE_OPTIONS=--openssl-legacy-provider, menyelesaikan masalah ini.

Kesalahan kedua muncul tak lama kemudian:

Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './lib/tokenize' is not defined by "exports"

Masalah ini berasal dari postcss-safe-parser, ketergantungan transitif dari rantai minimisasi CSS react-scripts@4, yang menyertakan salinan postcss kuno dan bersarang. File package.json postcss lama tidak pernah mendeklarasikan bidang exports wildcard. Node 17+ menerapkan ekspor secara ketat dan langsung error pada path apa pun yang tidak dideklarasikan secara eksplisit. Node 16 hanya memberikan peringatan; Node 24 menolak.

Awalnya, saya berpikir untuk menurunkan tahap build ke Node 16, versi terakhir sebelum ini menjadi error keras. Ini berhasil, tetapi ini adalah solusi yang salah. Node 16 sudah EOL; memilihnya hanya untuk menghindari aturan hanyalah penundaan masalah, bukan solusi. Jawaban yang lebih baik adalah mengakui bahwa ini adalah utang ketergantungan aplikasi, bukan masalah infrastruktur. Perbaikan sebenarnya adalah perubahan yarn.lock oleh tim pengembangan untuk menetapkan resolusi pada postcss yang bersarang.

Sebagai DevOps engineer, mengedit package.json secara manual bukanlah tugas saya. Solusi yang saya pilih adalah mempatch file package.json yang rusak dari dalam Dockerfile itu sendiri, setelah yarn install, menggunakan skrip Node inline kecil:

RUN node -e " const fs = require('fs'); const path = 'node_modules/postcss-safe-parser/node_modules/postcss/package.json'; if (fs.existsSync(path)) { const pkg = JSON.parse(fs.readFileSync(path)); pkg.exports = pkg.exports || {}; pkg.exports['./lib/*'] = './lib/*.js'; fs.writeFileSync(path, JSON.stringify(pkg, null, 2)); }"

Tidak ada perubahan lockfile, tidak ada keterlibatan dev, dan Node tetap di versi 24 di seluruh armada. Ini adalah solusi sementara; jika pohon ketergantungan bergeser dan postcss-safe-parser bersarang di tempat lain, patch akan berhenti diterapkan dan error asli akan muncul kembali. Ini adalah fitur, bukan bug: kegagalan menjadi jelas dan dapat dilacak daripada terus-menerus menutupi target yang bergerak.

Saya mencatat masalah mendasar ini kepada tim pengembangan untuk perbaikan yang tepat. Pelajaran ketiga: ketahui lapisan mana yang bertanggung jawab atas perbaikan mana. Menurunkan infrastruktur untuk menghindari bug tingkat aplikasi adalah perangkap yang mudah terjatuh saat Anda bisa memperbaiki dari Dockerfile, tetapi "bisa" dan "seharusnya" adalah pertanyaan yang berbeda. Pisahkan patch, buat terlihat, dan berikan perbaikan sebenarnya kepada pemilik kode.

Setelah build berhasil, Trivy gagal dalam pipeline:

Total: 4 (HIGH: 4, CRITICAL: 0) c-ares CVE-2026-33630 libexpat CVE-2026-56131 / 56407 / 56408

Masalah keamanan ini tidak ada hubungannya dengan perubahan kode, tetapi menyoroti pentingnya pemindaian terus-menerus dan respons cepat terhadap vektor risiko yang ditemukan.

Postmortem ini menggarisbawahi pentingnya verifikasi artefak build, menyelaraskan versi Node, menangani utang ketergantungan, dan menjaga pemisahan tanggung jawab yang jelas antara pengembang dan DevOps. Bagi tim teknologi di Indonesia yang sering menghadapi warisan sistem, pengalaman ini menjadi pengingat berharga tentang audit yang cermat, kolaborasi lintas fungsi, dan solusi sementara yang terlihat bukan pengganti perbaikan yang tepat.

Mengapa Ini Penting

Artikel ini relevan bagi ekosistem teknologi Indonesia karena banyak proyek masih bergantung pada sistem legacy yang dibangun dengan CRA dan Django. Pengalaman nyata tentang kesalahan Dockerfile, ketidaksesuaian ABI Node, dan utang ketergantungan memberikan panduan praktis untuk menghindari kegagalan yang mahal di produksi. Selain itu, temuan Trivy tentang CVE pada library sistem menunjukkan pentingnya mengintegrasikan pemindaian keamanan secara rutin dalam pipeline CI/CD, yang sering diabaikan oleh tim lokal. Dengan memahami dan menerapkan pelajaran-pelajaran ini, organisasi dapat meningkatkan keandalan deployment, mengurangi risiko keamanan, dan membangun praktik DevOps yang lebih berkelanjutan.

Sumber Asli
Internasional
Tanggal
12 Juli 2026
Waktu Baca
6 menit