Image Build & Versioning Toolkit
On this page
Image Build & Versioning Toolkit adalah kumpulan perintah yang memberi setiap modul dalam satu stack versinya sendiri, mem-build image-nya di bawah versi itu, dan mengarsipkan image dengan cara yang menjaga versi-versinya tetap terpisah. Satu perintah mem-build modul sekaligus menaikkan versinya; satu menaikkan versi tanpa build; dua lagi menyimpan image ke file dan memuatnya kembali.
Stack berisi sembilan modul tak berubah serentak. Ketika satu service mendapat perbaikan, hanya service itu yang layak menerima nomor baru, dan tag yang dibawanya harus berarti tepat satu build, karena staging dan production akan menarik tag itu dan percaya bahwa isinya sama dengan yang diuji.
Sekilas
| Tools | build-all, upgrade-version-only, backup-docker-images, restore-docker-images |
|---|---|
| Bentuk | Script command-line; perintah versi saja dan backup memuat library pembantu bersama untuk menurunkan daftar modul, sedangkan build dan restore berdiri sendiri |
| Bahasa | Bash dengan awk, yang mengendalikan Docker Compose dan Cargo |
| Status | Stabil, berjalan di production |
| Kode sumber | Privat |
Yang dikerjakannya
A. Memberi versi pada tiap modul secara terpisah
Setiap modul menyimpan versinya di file environment miliknya sendiri, jadi satu service bisa berada di 2.13.0 sementara sisanya tetap di 2.11.2. Mem-build satu modul hanya menaikkan nomor modul itu; mem-build semuanya adalah opsi tersendiri yang harus disebut, karena menaikkan setiap versi untuk perubahan di satu service menciptakan rilis yang tak pernah terjadi.
B. Mem-build image di bawah versi barunya
Perintah build membaca versi modul saat ini dari file-nya, menuliskan versi baru, lalu mem-build image-nya. Modul yang ditulis dengan Rust meng-compile binary-nya di host lebih dulu, karena image-nya hanya menyalin binary yang sudah jadi; lokasi source-nya bisa dialihkan untuk mesin lain. Modul yang dipakai lintas project di-build dengan nama image universal, tanpa akhiran milik project mana pun, jadi image yang sama melayani setiap project yang memakainya.
C. Menolak memakai ulang versi
Bila modul sudah membawa versi yang diminta, build berhenti dan menjelaskan alasannya. Build ulang yang disengaja di bawah nomor yang sama, misalnya sesudah base image berubah tanpa perubahan source, butuh flag eksplisit.
D. Menaikkan versi tanpa build
Ketika image-nya sudah ada, hasil pull dari registry, perintah kedua hanya menyelaraskan versi modul dengannya. Daftar modulnya diturunkan dari file compose, bukan ditulis tangan, jadi modul baru ikut tercakup tanpa ada yang perlu ingat menambahkannya. Modul yang sudah berada di versi yang diminta dilaporkan baik-baik saja, dan modul tanpa file environment atau tanpa versi yang terbaca dilewati dengan pesan.
E. Mengarsipkan image berdasarkan nama dan tag
Perintah backup menyimpan image tiap modul ke file terkompresi yang dinamai menurut image sekaligus tag-nya, dengan versi tiap modul dibaca dari file miliknya dan nama image dari file compose-nya, yang memilih gagal ketimbang menghasilkan nama kosong. Ia bisa membaca modul environment lain, mencetak bantuannya sendiri, dan menolak opsi tak dikenal dengan exit code 2. Perintah restore memuat kembali semua arsip, atau hanya yang disebut. Nama yang diketik dari root repository ditemukan di folder arsip berdasarkan nama dasarnya. Pemuatan yang gagal menghentikan run.
Cara saya memakainya
| Perintah | Yang dikerjakan | Yang ditolak |
|---|---|---|
build-all | menaikkan versi satu modul dan mem-build image-nya | versi yang sudah dibawa modul itu; modul tak dikenal; build Rust yang gagal |
upgrade-version-only | menaikkan versi tanpa build | modul tak dikenal |
backup-docker-images | menyimpan tiap image sebagai <image>__<tag>.tgz | modul tak dikenal; image yang tak ada di daemon dilaporkan dan run dinyatakan gagal |
restore-docker-images | memuat kembali arsip beserta tag-nya | run tanpa satu pun arsip untuk dimuat |
Keputusan rancangan
Versi milik modul, dan versi lama dibaca, tak pernah diketik. Perintah build dulu meminta versi lama dan versi baru sekaligus. Salah ketik pada versi lama membuat penggantian tak menemukan apa pun, file-nya tetap seperti semula, dan script tetap melaporkan sukses. Kini versi lama diambil dari file milik modul itu. Penalaran yang sama sampai ke backup image: dengan satu argumen versi untuk seluruh stack, tak ada nilai yang benar, karena 2.11.2 melewatkan modul yang di 2.13.0 dan 2.13.0 melewatkan enam lainnya, dan keduanya tetap menulis backup separuh yang tampak lengkap.
Satu tag berarti satu build. Satu service storage pernah di-build ulang dengan endpoint baru di bawah tag 1.0.0 yang sudah ada, sementara registry masih menyimpan 1.0.0 yang lebih lama. Development menjalankan image lokal yang segar, staging menarik yang lama, dan pemeriksaan identitas gagal dengan 404 yang menunjuk ke mana-mana kecuali ke tag-nya. Karena itu build menolak menimpa versi yang sudah dibawa modulnya; staging dan production yang menarik satu tag menerima isi yang memang diuji.
Langkah yang gagal menghentikan build, bukan menghilang. Build Rust dulu duduk di rantai satu baris yang || true-nya menelan compile yang gagal, sehingga image mengemas binary sebelumnya di bawah versi baru lalu melaporkan sukses. Rantai itu sudah dibuang, dan error compile kini menghentikan semuanya. Di perintah build, versinya sendiri ditulis dengan hanya mengubah baris versinya, dicocokkan secara literal, dan isi file-nya diganti di tempat sehingga pemilik dan mode-nya tetap: cari-ganti sebelumnya memperlakukan titik pada 1.0.0 sebagai wildcard, cocok dengan satu nomor port, lalu mengubahnya menjadi 1.1.0, yang belakangan gagal sebagai port tak valid. Nama modul yang tak dikenal toolkit ditolak, bukan diam-diam tak mem-build apa pun, dan pesan penutupnya mengingatkan bahwa setiap modul lain tetap di versinya sendiri.
Arsip diberi label versi, dan publikasi tetap langkah terpisah. Menamai tiap arsip menurut tag-nya membuat dua versi dari satu modul tak pernah saling menimpa, dan folder-nya langsung memperlihatkan versi mana saja yang tersimpan. Build berhenti begitu image ada di mesin lokal. Push ke registry sengaja dikerjakan manual, karena tag yang di-push adalah tag yang akan ditarik setiap environment sesudahnya, dan momen itu layak mendapat perhatian manusia.
Spesifikasi
| Masukan | Satu modul, atau semua modul secara eksplisit, dan versi baru; untuk arsip, opsional satu modul atau environment lain sebagai sumber |
|---|---|
| Keluaran | Image bertag versi tiap modul, entri versi yang diperbarui, dan satu arsip terkompresi per image dan tag |
| Keamanan | Versi yang sudah ada tak ditimpa tanpa flag; compile yang gagal menghentikan build; modul tak dikenal ditolak; tak ada yang di-push otomatis |
| Prasyarat | Docker beserta Compose; Cargo untuk modul Rust; source modul tersedia di disk. Script-script ini mencari lokasinya sendiri, jadi bisa dijalankan dari working directory mana pun |
Terkait
Prosedur rilis yang langkah pertamanya mem-build image dengan toolkit ini.
Perintah Docker pendek yang dipakai build dan arsip image.
Tool cari-ganti yang saya pakai untuk mengganti nama di seluruh project; perintah build sengaja berhenti memakainya untuk nomor versi.
Setiap script mengikuti bentuk yang saya berikan pada setiap tool kecil, dalam varian Bash-nya.
Istilah
- Tag image
- Label sesudah titik dua pada nama image, di sini dipakai sebagai versi yang ditarik environment.
- Registry
- Server yang menyimpan image yang dipublikasikan, tempat staging dan production menariknya.
- Modul
- Satu service di dalam stack, dengan source, image, dan versinya sendiri.
- Rebuild
- Mem-build image lagi di bawah versi yang sudah dimilikinya, hanya diizinkan bila disengaja.
- Pencocokan literal
- Mencocokkan teks persis seperti tertulis, jadi titik berarti titik, bukan karakter apa pun.
- Arsip image
- Image yang disimpan ke file terkompresi, yang bisa dimuat di mesin lain dengan tag-nya tetap utuh.
Technologies covered
- Bash
- Rust
- Docker
- Docker Compose