Penutup Chapter Checklist Production meninggalkan satu pengamatan yang terus bergema: build, scan, tag, catat digest, deploy, verifikasi, audit — urutan langkah yang sama, setiap kali, tanpa improvisasi. Budi membaca ulang lembar audit bulanannya dan menyadari bahwa seluruh urutan itu masih digerakkan oleh tangan: setiap rilis dimulai dengan docker build di laptop, disusul docker push yang diketik manual, dan diakhiri perjalanan SSH ke VPS untuk menarik image baru — disiplin yang bertahan selama kepala dingin, lalu melorot begitu jadwal padat. Kabar baiknya, seluruh bahan otomatisasi sudah berdiri tegak: kode toko hidup di repositori GitHub budi/toko dengan backend Node.js di folder backend/, Dockerfile sudah teruji membangun image yang ramping, dan registry terbukti mendistribusikan image lintas mesin. Section ini menyerahkan seluruh ritual manual tersebut kepada mesin, dan chapter pembuka ini membangun fondasinya: tiga sifat container yang membuat otomatisasi bukan sekadar mungkin, melainkan kokoh.
Tiga Sifat Container yang Menopang Pipeline #
Pipeline yang bisa dipercaya dibangun di atas tiga janji kecil yang tidak boleh bocor: bahan yang sama harus menghasilkan produk yang sama, produk yang sudah diperiksa tidak boleh diam-diam berganti isi, dan ruang kerja tempat produk diperiksa harus sama dengan ruang kerja tempat produk dipakai. Container menepati ketiganya sekaligus, dan kita bawa ketiganya ke meja satu per satu.
Build Deterministik #
Bayangkan fungsi matematika sederhana: f(x) = x². Input 5 selalu menghasilkan 25 — hari ini, minggu depan, di siapa pun yang menghitungnya. Build image mengikuti pola yang sama: sebuah image adalah fungsi dari dua input, yaitu build context (kumpulan berkas yang dikirim ke builder) dan Dockerfile (urutan instruksi yang membangunnya). BuildKit mengevaluasi fungsi ini dengan menghitung cache key untuk setiap instruksi — checksum berkas untuk COPY, teks perintah untuk RUN — sehingga context dan Dockerfile yang identik menghasilkan rantai layer yang identik pula, mekanisme yang sudah kita bedah tuntas pada Chapter Build Cache.
Konsekuensinya bagi CI/CD lurus dan tegas. Sebuah commit di Git mewakili keadaan bahan yang terkunci: kode, package-lock.json, .dockerignore, semuanya dibekukan pada satu titik riwayat. Pipeline yang membangun image dari commit tertentu sedang mengevaluasi fungsi yang sama dengan input yang sama, di mesin mana pun dan kapan pun. Dua syarat kecil tetap perlu dijaga agar janji ini tidak bocor: RUN yang menembus jaringan — misalnya npm ci — harus diikat lock file agar versi paket tidak berpindah diam-diam, dan base image sebaiknya dipatok berdasarkan digest agar tag seperti node:22-alpine tidak berganti isi di tengah jalan. Kedua disiplin itu sudah kita kunci pada Chapter Reproducible Build dan Chapter Image Digest.
Artifact Immutable #
Test yang lolos pada sebuah image hanya berharga bila image yang naik ke produksi adalah image yang persis sama dengan yang diuji. Di sinilah sifat kedua bekerja: sebuah image yang terdaftar di registry bersifat immutable — isinya tidak dapat diubah; yang dapat berubah hanyalah label yang menunjuk ke image tersebut. Digest adalah label yang tidak pernah berubah: sidik jari sha256: diikuti 64 karakter heksadesimal yang dihitung dari manifest dan seluruh layer image. Tag 1.5.0 bisa ditimpa siapa pun yang berhak push, tetapi digest menunjuk kumpulan byte yang sama selamanya. Budi membuktikan sifat ini pada image produksi yang berjalan di VPS, tepat pada image yang diaudit pada chapter sebelumnya:
$ docker inspect --format '{{json .RepoDigests}}' registry.example.com/toko/backend:1.5.0Output yang Dihasilkan:
["registry.example.com/toko/backend@sha256:5b8e2f7a9c4d1e6b3a5c7d9e1f2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a"]Mari kita telaah baris tersebut:
- Field
.RepoDigests— catatan yang ditorehkan ketika image ditarik dari registry; isinya adalah digest image sebagaimana dilihat registry, berbeda dari image ID lokal yang merupakan digest konfigurasi. sha256:+ 64 heksadesimal — identitas penuh image; mengubah satu byte pada satu layer mengubah seluruh digest, sehingga dua mesin yang menampilkan digest yang sama memegang image yang identik byte-per-byte.- Alamat
registry.example.com/toko/backend— digest berlaku untuk pasangan repository dan isi; tag1.5.0pada baris perintah hanyalah jalan pintas menuju digest ini. - Implikasi untuk pipeline — setiap build mencatat digest hasilnya, dan deployment menunjuk digest tersebut; test, scan, dan deploy kini berbicara tentang objek yang sama tanpa bisa diselundupi penggantinya.
Runner Bercontainer #
Sifat ketiga menutup lingkaran dari sisi tempat kerja berlangsung. Job CI tidak harus berjalan di atas mesin yang dipasangi toolchain secara manual — job dapat dieksekusi di dalam container, sehingga npm test berjalan di atas node:22-alpine yang sama dengan base image aplikasi. Runner menyediakan mesin kosong; langkah pertama job menarik image, dan dalam hitungan detik lingkungan eksekusi siap — tanpa skrip instalasi Node.js, tanpa manajer versi, tanpa perdebatan versi antar anggota tim. Seluruh kebiasaan menjalankan test di dalam container yang kita bangun pada Chapter Menjalankan Test di Container terbawa utuh ke mesin CI; yang berubah hanyalah siapa yang mengetik perintahnya — dari Budi menjadi pipeline.
Bentuk Sebuah Pipeline #
Ketiga sifat itu bertemu dalam satu bentuk kerja yang kita sebut pipeline: rangkaian tahap yang menyala sendiri pada suatu peristiwa, berjalan berurutan, dan berhenti pada kegagalan pertama. Diagram berikut memetakan pipeline yang akan kita rakit sepanjang section ini — bentuk yang sama dengan ritual manual yang dijalankan Budi pada setiap rilis toko:
Mari kita telaah alurnya tahap demi tahap:
- Commit — peristiwa Git apa pun — push ke cabang utama maupun tag rilis — menyalakan pipeline; tidak ada tombol yang ditekan manusia.
- Lint dan test — gerbang pertama: kode yang gagal test tidak berhak menjadi image, sehingga kesalahan tertahan sebelum menular menjadi artifact.
- Build image — Dockerfile di folder
backend/dievaluasi; image lahir sebagai fungsi dari commit yang memicunya. - Scan image — image hasil build diperiksa kerentanannya dengan kebiasaan dari Chapter Image Scanning.
- Push ke registry — image beserta digest-nya tercatat di
ghcr.iodan registry privat — padanan otomatis daridocker pushpada Chapter Push dan Pull Image. - Deploy ke produksi — server menarik image yang ditunjuk, dan hanya image itu, berdasarkan digest yang tercatat.
- Jalur gagal — kegagalan pada tahap mana pun menghentikan keseluruhan pipeline; rilis tertahan dan produksi tidak tersentuh.
Tahap-tahap itu baru konsep; cara merakitnya menjadi berkas YAML yang hidup di dalam repositori adalah pekerjaan chapter-chapter berikutnya.
Pipeline Bercontainer versus Non-Container #
Untuk merasakan mengapa runner bercontainer begitu berharga, bandingkan dua dunia yang pernah dihuni setiap tim. Pipeline generasi lama memasang toolchain di mesin runner lewat skrip instalasi — dan membayar bunganya diam-diam seiring waktu. Tabel berikut membandingkan keduanya pada empat pertanyaan yang paling sering menagih:
| Pertanyaan | Pipeline non-container | Pipeline bercontainer |
|---|---|---|
| Setup per bahasa | skrip instalasi berbeda untuk Node.js, Go, Rust — dirawat satu per satu | tarik image siap pakai — node:22-alpine, golang:1.24-alpine, rust:1.99-alpine — tanpa instalasi |
| Drift toolchain antar runner | versi berbeda-beda antar mesin seiring pembaruan dan usia | versi dibekukan di dalam image; runner mana pun menjalankan versi yang sama |
| Hasil identik antar mesin | tidak dijamin — bergantung pada keadaan mesin masing-masing | dijamin selama build context dan Dockerfile sama |
| Kecepatan onboarding anggota baru | membaca dokumen setup lalu mereplikasi lingkungan manual | clone repositori; pipeline dan image yang mendefinisikan segalanya |
Perhatikan bahwa dua baris terakhir tabel adalah janji yang sudah kita uji tuntas di awal section registry: Siti berhasil menjalankan stack di laptopnya hanya dengan pull dan satu berkas compose. Pipeline bercontainer memperluas janji yang sama ke arah mesin CI — anggota tim baru dan runner baru sama-sama tidak perlu ritual inisiasi, karena lingkungan didefinisikan oleh image, bukan oleh mesin.
Peta Istilah #
Sepanjang section ini kita akan sering menyebut segelintir istilah CI/CD, jadi mari kita sepakati maknanya sekali di sini supaya chapter berikutnya bisa langsung bekerja. Istilah-istilah berikut dipakai konsisten di seluruh layanan CI, termasuk GitHub Actions yang menjadi kendaraan kita:
| Istilah | Artinya dalam pipeline kita |
|---|---|
| pipeline | keseluruhan rangkaian tahap otomatis yang berjalan pada satu peristiwa — misalnya push ke main |
| stage / job | satu blok pekerjaan dalam pipeline — test, build, scan, deploy — dengan syarat lulus dan gagalnya sendiri |
| artifact | benda yang dihasilkan pipeline; pada course ini: image, dengan digest sebagai identitasnya |
| registry | gudang penyimpanan dan distribusi artifact — ghcr.io dan registry.example.com |
| runner | mesin yang mengeksekusi job dan menyediakan Docker untuk membangun serta menjalankan container |
Tiga sifat — build deterministik, artifact immutable, runner bercontainer — adalah fondasinya, dan pipeline adalah rumah yang berdiri di atas fondasi itu. Pertanyaan berikutnya bukan lagi mengapa, melainkan bagaimana: siapa yang mengeksekusi build, di mesin apa, dan dipicu peristiwa apa. Ternyata ada tiga jalur utama untuk menjawabnya, dan memilih di antara ketiganya dengan sadar adalah pekerjaan chapter berikutnya, Automated Image Build.
Referensi #
- Docker build — bagaimana image dibangun dari Dockerfile dan build context.
- docker image inspect — membaca field RepoDigests sebagai identitas image.
- GitHub Actions — konsep workflow, event, job, dan runner yang dipakai sepanjang section ini.