Bagaimana Saya Menjalankan Tiga Environment di Satu Mesin Tanpa Membiarkannya Saling Menghapus
On this page
- Pendahuluan
- A. Kenapa tidak pakai tiga mesin saja
- B. Tiga perkara yang tak boleh dipakai bersama
- C. Apa taruhannya kalau ini keliru
- D. Berapa ongkos sebenarnya "satu mesin"
- E. Tiga hambatan yang menghalangi
- Metode
- A. Satu subnet per environment, diputuskan sekali
- B. State tinggal di luar folder project
- C. Path tak boleh bergantung pada letak foldernya
- D. Identitas yang dipakai runtime, yang bukan identitas yang Anda lihat
- E. Apa yang aman dipakai bersama
- F. Urutan menyalakan, dan kenapa script mengalahkan ingatan
- Hasil dan Pembahasan
- A. Kegagalan yang bakal melaporkan keberhasilan
- B. Kenapa kegagalan senyap berkerumun di sini
- C. Berapa sebenarnya ongkos berbagi satu host
- D. Di mana pendekatan ini berhenti cocok
- Simpulan
- Istilah
Bertahun-tahun saya cuma punya satu environment di laptop, dan itu sudah cukup. Lalu project yang saya kerjakan menuntut dua lagi: satu tempat menguji rilis sebelum dilepas, dan satu lagi yang dipakai orang sungguhan. Jawaban yang masuk akal adalah tiga mesin. Jawaban yang sanggup saya sediakan cuma satu.
Ternyata ketiganya memang bisa hidup di satu mesin. Cara itu juga menyimpan beberapa jalan untuk kehilangan data tanpa suara — dan mencegahnya itulah yang sebenarnya ingin saya ceritakan di sini.
Pendahuluan
Environment — atau lengkapnya deployment environment — adalah satu salinan sistem yang utuh dan benar-benar berjalan: service-nya, database-nya, file-nya, konfigurasinya. Kebanyakan project akhirnya punya minimal dua. Satu untuk mengerjakan hal baru, tempat rusak itu wajar. Satu lagi dipakai user sungguhan, tempat rusak itu tidak wajar.
Di antara keduanya banyak tim menyelipkan yang ketiga. Staging adalah gladi bersih: rilis yang sebentar lagi naik ke production, dijalankan di atas data yang menyerupai aslinya, supaya kegagalannya terjadi di depan mata saya — bukan di depan user.
Sistem yang saya urus adalah layanan dokumen untuk sebuah instansi publik. Bukan satu program, melainkan selusin program yang saling bekerja sama, masing-masing hidup dalam container sendiri — proses terbungkus yang punya filesystem dan pandangan jaringannya sendiri, terpisah dari apa pun yang ada di mesin itu. Ada API yang diajak bicara browser, ada certificate authority yang menerbitkan kredensial untuk menandatangani, beberapa service penanda tangan, penyimpan file unggahan, satu klaster database, dan satu klaster pencarian tempat log ditampung.
Jumlah itu penting untuk cerita selanjutnya. Mau satu environment atau tiga, tiap environment tetap butuh set yang lengkap. Tiga environment bukan berarti tiga program, melainkan tiga-tiganya dari segalanya.
Ketiganya juga tidak memuat jenis data yang sama, dan perbedaan itu yang membentuk hampir semua keputusan di bawah. Development memuat apa pun yang kebetulan saya ketik saat mencoba — hilang pun cuma rugi satu sore. Staging memuat salinan data nyata hasil pemulihan backup, supaya rilis diuji terhadap bentuk dan volume yang sesungguhnya. Production memuat satu-satunya salinan yang berarti. Makin ke kanan, makin mahal harga sebuah kekeliruan, dan makin perlu ketiganya tidak bisa saling menyentuh.
A. Kenapa tidak pakai tiga mesin saja
Mesin terpisah akan membuat tulisan ini tak perlu ada, dan itu layak disebut terus terang sebelum menjelaskan alternatifnya.
Saat dua environment tinggal di dua host, keterpisahannya gratis. Keduanya tak bisa bertabrakan lewat jaringan, tak bisa saling menimpa file, tak bisa mengacaukan proses satu sama lain — bukan karena ada yang mengonfigurasinya begitu, melainkan karena memang tak ada yang dipakai bersama sejak awal.
Keterbatasan saya biasa saja, dan mungkin terasa akrab. Yang ada cuma laptop kerja dan satu server. Meminta dua server lagi khusus untuk staging berarti berbulan-bulan pengadaan untuk sistem yang butuh staging lebih cepat, dan pembenarannya — "supaya rilis bisa digladi bersih" — termasuk jenis yang sulit bertahan dalam percakapan anggaran.
Maka pertanyaannya menyempit dan justru jadi lebih menarik: apa yang wajib dipisah, dan apa yang aman dipakai bersama? Seluruh isi di bawah adalah jawaban atas itu, dan jawabannya tidak gamblang. Ketiga pemisahan itu bisa gagal, dan ketiganya gagal tanpa suara.
B. Tiga perkara yang tak boleh dipakai bersama
Karena sisa tulisan ini bertumpu pada tiga istilah, ketiganya layak didefinisikan sebelum muncul sebagai judul seksi.
Pertama jaringan. Container saling bicara lewat jaringan virtual — jaringan hasil definisi software yang cuma ada di dalam host. Tiap jaringan diberi subnet: rentang alamat yang dipesan khusus, ditulis dengan notasi semacam 10.x.42.0/24, dan angka sesudah garis miring menyatakan seberapa banyak bagian alamat yang dikunci. Tiap jaringan juga punya gateway, yaitu alamat yang ditempati host itu sendiri di jaringan tersebut, yang dipakai container untuk menggapai apa pun di luar jaringannya. Kalau dua environment berbagi jaringan, service di satu environment bisa menggapai database di environment lain — bukan karena ada yang berniat begitu, tapi karena alamatnya memang ketemu dan tak ada yang mencegah.
# satu rentang alamat per environment, gateway diturunkan dari rentang itu
Kedua state: data yang menumpuk selama sistem berjalan, sebagai lawan dari konfigurasi yang diberikan kepadanya. File database itu state. File konfigurasi container bukan. Pembedaan ini menentukan sebab state adalah bagian yang tak bisa dibuat ulang — dan bagian yang paling gampang dimusnahkan oleh operasi yang tampak tak berbahaya.
Ketiga, identitas yang dipakai runtime container di balik layar, yang ia sebut nama project. Yang satu ini tak kasat mata dengan cara yang tak berlaku bagi dua lainnya: ia tak muncul di file mana pun yang lazim dibuka, nilai bawaannya biasanya benar, dan ketika nilai bawaan itu keliru ia membuang container tanpa bertanya. Saya membahasnya lengkap belakangan, sebab ia kegagalan yang paling tak saya duga.
C. Apa taruhannya kalau ini keliru
Sebelum masuk ke mekanismenya, ada baiknya menyebut kenapa ketiganya pantas dijaga.
Sistemnya memegang dokumen bertanda tangan untuk sebuah instansi publik. Catatan tentang apa yang ditandatangani, oleh siapa, dan kapan wajib tetap utuh dan bisa diverifikasi bertahun-tahun — itu bukan preferensi operasional, melainkan alasan sistemnya ada sejak awal. Data production bukan sekadar merepotkan kalau hilang; kehilangannya berarti instansi itu tak sanggup membuktikan bahwa dokumen yang ia tandatangani memang ditandatangani.
Staging justru memperumit, bukan menyederhanakan. Karena staging dipulihkan dari backup production, ia memegang salinan data nyata juga. Jadi kekeliruan yang mengaburkan dua environment bukan cuma merusak environment uji — ia bisa menaruh catatan sungguhan di tempat yang tak semestinya, atau diam-diam mengosongkan database yang oleh segala pemeriksaan dilaporkan sehat.
Frasa terakhir itu tema seluruh tulisan ini. Kegagalan yang dibahas di bawah tak satu pun mengumumkan dirinya. Semuanya lolos health check.
D. Berapa ongkos sebenarnya "satu mesin"
Enaknya memakai mesin terpisah: keterpisahannya gratis. Begitu dua environment ditumpuk di satu host, tiap yang dipakai bersama berubah jadi pertanyaan — jaringannya, filesystem-nya, nomor port-nya, dan, ini yang saya pelajari dengan cara mahal, nama yang dipakai runtime container di balik layar.
Jawaban yang akhirnya saya pakai ada tiga bagian, sepadan dengan tiga istilah di atas. Jaringan wajib dipisah supaya service tak sengaja menyeberang antar environment. State wajib tinggal di luar folder project supaya menyalin folder tak pernah berarti menyalin database. Dan runtime container wajib diberi tahu secara eksplisit environment mana yang memiliki tiap stack — sebab tebakan bawaannya keliru, dengan cara yang menghapus barang.
E. Tiga hambatan yang menghalangi
Dinyatakan sebagai tujuan, yang saya mau sebenarnya sederhana. Menjalankan tiga environment utuh — development, staging, dan production, masing-masing lengkap dengan belasan service-nya — di atas hardware yang sudah ada, dan membuat ketiganya berperilaku seolah duduk di mesin terpisah. Tanpa membeli server kedua, tanpa melepas gladi resik yang justru jadi alasan staging ada, dan di atas segalanya tanpa satu environment pun sanggup menjangkau environment lain lalu mengosongkannya.
Gampang dirumuskan, canggung dibangun. Ada tiga hambatan yang menghalangi, satu untuk tiap perkara yang tak boleh dipakai bersama, dan ketiganya berbagi satu sifat yang butuh waktu lama sampai saya bisa menamainya: tak satu pun gagal dengan ribut. Tiap mekanisme melakukan persis apa yang diminta. Yang keliru adalah permintaannya, dan permintaan keliru yang dieksekusi dengan benar tak memunculkan error di mana pun.
Hambatan pertama: jaringan bersama tak melahirkan kegagalan — ia melahirkan koneksi yang berhasil ke tempat yang salah. Container saling menggapai lewat nama di atas jaringan virtual, dan kalau dua environment duduk di jaringan yang sama, name resolution atas nama database dari service di staging justru mengembalikan milik production. Tak ada yang menolak koneksinya, sebab dari sudut pandang jaringan memang tak ada yang salah. Pertahanan yang menggoda adalah memberi tiap environment nama container yang berbeda, atau menggeser port yang dipublikasikan; keduanya cuma membuat tabrakan lebih kecil kemungkinannya disadari, dan tak satu pun membuatnya mustahil, sebab name resolution di dalam jaringan bersama tak menengok keduanya.
Hambatan kedua: path data yang salah arah tak melahirkan kegagalan — ia melahirkan direktori kosong, dan database dengan senang hati mengadopsinya. Ketika state tinggal di dalam folder project, menyalin folder berarti menyalin database; dan menurunkan path data dari lokasi kode membuat konfigurasi yang sama menunjuk tempat berbeda di laptop dan di server. Inilah yang paling mahal di antara ketiganya: proses restore bisa menulis database hasil pemulihan ke path yang benar sementara container membaca path yang lain, database menginisialisasi direktori kosong yang ia temukan, dan seluruh health check menyala hijau di atas sistem yang tak berisi apa-apa. Alternatif yang harus saya tinggalkan justru yang terkesan pintar — path relatif terhadap posisi project, yang tampak portabel dan justru karena itulah satu perintah yang sama berarti dua hal berbeda di dua host.
Hambatan ketiga: identitas runtime yang dipakai bersama tak melahirkan kegagalan — ia melahirkan penghapusan yang berhasil atas container yang tak berbuat salah. Docker Compose — tool yang menyalakan sekumpulan container dari satu file konfigurasi — menentukan container mana milik sebuah stack lewat project name yang secara bawaan diambil dari nama folder, sementara ketiga environment saya memakai nama folder yang identik — memang disengaja, sebab itulah yang membuat staging murah dilahirkan dari sebuah template. Tiga folder bernama sama, di mata runtime, adalah satu stack: menyalakan production bisa menghapus container development yang sedang jalan, tanpa peringatan. Pertahanan yang tak bekerja justru yang paling kelihatan — prefix berbeda per environment pada tiap container, yang membuat docker ps memang menampilkan tiga himpunan terpisah. Itu mengubah labelnya, bukan kepemilikannya.
Ketiganya dikerjakan dalam urutan itu, dan urutannya bukan kebetulan. Jaringan didahulukan sebab selama environment masih bisa saling menggapai, memisahkan apa pun yang lain cuma hiasan — data yang disimpan hati-hati tetap berjarak satu hostname keliru dari terbagi. State menyusul sebab kegagalannya yang tak bisa dipulihkan: container bisa dilahirkan ulang, database yang terhapus tidak. Identitas runtime ditaruh terakhir bukan karena paling remeh, melainkan karena ia yang paling tak terduga — dan paling gampang dipercaya justru setelah dua yang pertama mengajarkan bahwa kegagalan berbahaya di sini adalah yang melaporkan keberhasilan.
Metode
A. Satu subnet per environment, diputuskan sekali
Inilah jawaban atas hambatan pertama: jaringan tempat koneksi yang keliru justru berhasil.
Container saling bicara lewat jaringan virtual. Kalau dua environment berbagi jaringan, service di staging bisa menggapai database production — bukan karena ada yang berniat begitu, tapi karena alamatnya memang ketemu dan tak ada yang mencegah.
Maka tiap environment dapat jaringan sendiri dengan subnet sendiri, yaitu rentang alamat privat yang dipesan khusus:
Tiap jaringan punya gateway: alamat yang ditempati host itu sendiri di jaringan tersebut, yang dipakai container untuk menggapai layanan di luar jaringannya. Lazimnya alamat pertama yang bisa dipakai dalam rentang itu.
Ada satu keputusan awal yang menghapus sekelompok kekeliruan sekaligus: gateway tak pernah dikonfigurasi terpisah, melainkan diturunkan dari subnet. Diberi 10.x.42.0/24, gateway-nya 10.x.42.1 — dihitung, bukan diketik. Dua nilai yang wajib cocok tapi diisi terpisah, cepat atau lambat akan berbeda. Satu-satunya perbaikan yang bertahan adalah berhenti punya dua nilai.
B. State tinggal di luar folder project
Inilah jawaban atas hambatan kedua, dan dua seksi berikutnya sama-sama bagian darinya — di mana state itu duduk, dan bagaimana path-nya ditulis.
Pemisahan kedua menyangkut filesystem. Naluri pertama saya dulu menaruh data tiap environment bersebelahan dengan konfigurasinya, persis seperti yang dicontohkan kebanyakan tutorial:
volumes:
- ./data/postgres:/var/lib/postgresql/data # state di sebelah configEnak dibaca, dan keliru untuk apa pun yang berumur lebih panjang dari sebuah demo. Sebab artinya folder project bukan lagi sekadar konfigurasi — ia juga sebuah database. Menyalinnya, memindahkannya, atau menghapusnya jadi tak bisa dilakukan tanpa berpikir keras soal apa yang sedang dimusnahkan.
Maka state dipindah keluar, ke path yang menyebutkan dirinya sendiri:
volumes:
- ${MODULE_DATA}/data/postgres:/var/lib/postgresql/data # state -> /data
- ./config/postgres/init.sql:/docker-entrypoint-initdb.d/:rodengan MODULE_DATA ditulis terang-terangan di environment file tiap modul — /data/<project>/<environment>/<modul>. Konfigurasi tetap di project dan ikut terlacak version control. State tinggal di bawah satu akar yang bisa dipasang di disk sendiri, di-backup dengan jadwalnya sendiri, dan — ini yang penting — tak pernah tersentuh oleh git checkout.
Folder project pun jadi stateless: aman di-clone, dipindah, atau dihapus.
C. Path tak boleh bergantung pada letak foldernya
Versi pertama skema ini menurunkan path data dari direktori kerja saat itu. Kelihatan pintar, dan memang jalan — selama cuma ada satu mesin.
Skema itu patah begitu mesinnya jadi dua. Di laptop project-nya tinggal di folder dokumen, di server ia tinggal di home directory. Environment sama, konfigurasi sama, path data berbeda — jadi perintah yang sama akan menggarap data yang berbeda, tergantung mesin mana yang mengetiknya.
Aturan yang akhirnya saya pegang: path data tak boleh diturunkan dari letak kodenya. Ia path absolut, ditulis terang-terangan, sama persis di tiap host.
D. Identitas yang dipakai runtime, yang bukan identitas yang Anda lihat
Inilah jawaban atas hambatan ketiga, dan yang paling tak terduga di antara ketiganya.
Docker Compose membawa dua identitas berbeda, dan cuma satu yang kasat mata:
Yang kedua — nama project — memutuskan kumpulan container mana yang dianggap "miliknya sendiri" oleh sebuah perintah compose. Saat Anda menjalankan down, itulah yang menentukan apa yang dibuang. Nilai bawaannya: nama folder.
Ketiga environment saya sengaja memakai nama folder yang sama, sebab justru itu yang membuat staging bisa dilahirkan sebagai salinan template development. Tiga folder bernama api, di tiga environment berbeda — dan karena itu, di mata Compose, satu stack.
Akibatnya: menaikkan production bisa membuang container development yang sedang jalan. Bukan memperingatkan. Membuang.
Yang membuatnya benar-benar berbahaya: pertahanan yang paling terpikirkan ternyata tak mempan. Nama berbeda untuk tiap container lewat awalan per environment membuat docker ps memperlihatkan tiga kelompok yang jelas berbeda. Itu mengubah labelnya, bukan kepemilikannya. Perbaikannya: nyatakan nama project secara eksplisit, sekali, di konfigurasi tiap environment:
COMPOSE_PROJECT_NAME=production_api # production/api/.env
COMPOSE_PROJECT_NAME=staging_api # staging/<versi>/api/.envGenerator yang melahirkan staging dan production kini menuliskannya otomatis. Nama folder boleh tetap kembar — dan justru itulah yang membuat staging murah dibuat.
Adil juga kalau saya membela nilai bawaannya. Menurunkan identitas stack dari nama foldernya itu tebakan yang masuk akal: kebanyakan orang menaruh satu stack per folder, dan bagi mereka aturan itu bekerja diam-diam dengan benar. Persoalannya, tebakan itu diambil dari sebuah nama file, sedangkan nama file tak memuat apa pun tentang maksud. Dua folder bernama sama ya satu stack, sejauh yang bisa dibaca aturan itu — entah keduanya sekandang atau terpisah oleh batas rilis.
Bentuk umum persoalan ini layak diberi nama, sebab bentuk ini berulang: tools yang menyimpulkan identitas dari penanda yang kebetulan, cepat atau lambat akan menyimpulkannya keliru. Pertahanannya bukan mengingat-ingat kasus pinggirannya, melainkan menyatakan identitas itu terang-terangan sehingga tak ada lagi yang perlu disimpulkan.
E. Apa yang aman dipakai bersama
Mendaftar apa saja yang wajib dipisah gampang membuat orang mengira semuanya wajib dipisah. Padahal sebagian besar isi host dipakai bersama tanpa akibat apa pun, dan bagian itu perlu disebut juga.
Image container dipakai bersama, dan memang seharusnya begitu. Image itu tak berubah dan dikenali dari isinya — image yang sama di tiga environment ya byte yang sama, jadi menariknya sekali saja bukan penghematan yang dipaksakan. Berbagi image juga yang membuat staging bermakna: artefak yang digladi bersih persis artefak yang nanti jalan di production, bukan hasil build ulangnya.
Kernel host, runtime container, dan reverse proxy di depan semuanya juga dipakai bersama. Proxy ini yang menarik, sebab dialah satu-satunya komponen yang mesti tahu ketiga environment sekaligus. Reverse proxy adalah web server yang menerima tiap request dari luar lalu meneruskannya ke service yang semestinya menjawab. Proxy aman dipakai bersama karena tugasnya sesempit itu: ia cuma menentukan ke environment mana request diteruskan, dengan mendengarkan di alamat berbeda untuk tiap environment — development di alamat yang hanya ada di dalam mesin itu, staging dan production di alamat yang tergapai dari jaringannya masing-masing. Proxy tak menyimpan data dan tak menyambungkan satu environment ke environment lain; menjaga ketiganya supaya tak saling menggapai adalah tugas jaringan terpisah yang dijelaskan di atas.
Yang tak dipakai bersama: apa pun yang memegang state atau mengklaim nama — jaringan, direktori data, dan pandangan runtime soal stack mana ini. Cuma itu daftarnya, dan cukup pendek untuk diingat.
F. Urutan menyalakan, dan kenapa script mengalahkan ingatan
Selusin container tak bisa naik dalam urutan sembarang. Penyimpan file dan jalur log wajib ada sebelum service yang menulis ke sana. Pengetahuan macam ini betah mengendap di kepala satu orang, lalu lenyap begitu orang itu cuti.
Maka pengetahuan itu dititipkan ke script. Menaikkan satu environment jadi satu perintah yang menyambangi tiap modul menurut urutan ketergantungan; menurunkannya membalik urutan itu. Tak ada yang pintar di dalamnya, dan justru itu maksudnya: ini beda antara prosedur dan kebiasaan.
Hasil dan Pembahasan
A. Kegagalan yang bakal melaporkan keberhasilan
Kegagalan termahal di sini sama sekali tak akan memunculkan error. Inilah hambatan kedua dalam wujudnya yang paling matang — layak diikuti langkah demi langkah, sebab tiap komponennya berperilaku benar dari awal sampai akhir.
Melahirkan environment baru dikerjakan dengan menyalin konfigurasi development lalu menimpa segelintir nilai yang wajib berbeda. Bila MODULE_DATA — path data dari bagian B — tak ikut ditimpa, salinannya mempertahankan path milik development.
Hasilnya: environment yang konfigurasinya menyebut "staging" di mana-mana, kecuali di satu tempat yang justru menentukan — volume-nya menunjuk direktori data milik development.
Runut apa yang terjadi sesudahnya. Proses restore menulis database hasil pemulihan ke path staging yang benar. Container database, yang membaca path dari konfigurasinya, malah membuka direktori development — yang bisa saja kosong, sebab development sering disetel ulang. Container naik mulus. Health check lolos: database-nya mendengarkan, dan menjawab.
Menurut segala ukuran otomatis, environment itu sehat. Isinya tak ada.
Menghitung tabel menangkapnya, jadi langkah ini permanen:
select count(*) from information_schema.tables where table_schema = 'public';Pelajarannya bukan "periksa path-nya", melainkan bahwa health check menjawab pertanyaan yang jauh lebih sempit daripada kelihatannya. "Apakah service-nya menjawab?" bukan "apakah service-nya menyajikan data yang benar?" — dan celah antara dua pertanyaan itu persis tempat bersarangnya kegagalan senyap. Pemeriksaan yang tak sanggup membedakan database kosong dari database penuh, akan melaporkan database kosong sebagai sehat, selamanya.
B. Kenapa kegagalan senyap berkerumun di sini
Bahwa ketiga hambatan sama-sama gagal tanpa suara sudah dinyatakan sejak awal. Layak ditanyakan kenapa mesti begitu — sebab alasannya struktural, bukan sekadar nasib buruk beruntun, dan itu mengubah rupa pemeriksaan yang berguna.
Timbang apa yang dijaga masing-masing. Ketiganya, seperti sudah diuraikan, menukar sebuah kegagalan dengan sebuah keberhasilan yang salah sasaran: sambungan yang berhasil ke tempat keliru, direktori kosong yang diadopsi dengan senang hati, penghapusan yang berhasil atas container tak bersalah.
Di ketiga kasus, mekanismenya mengerjakan persis yang diminta. Yang keliru permintaannya, bukan pelaksanaannya. Itu sebabnya tak satu pun muncul di log: log mencatat apa yang dikerjakan sebuah komponen, dan tiap komponen mengerjakan tugasnya dengan benar.
Ada akibat praktisnya buat cara memeriksa environment ini. Tiap verifikasi yang saya percayai membandingkan dengan sesuatu di luar sistem yang sedang diperiksa: jumlah tabel dibanding harapan, daftar container yang jalan dibanding environment yang semestinya memilikinya, alamat hasil resolusi dibanding subnet yang semestinya menampungnya. Pemeriksaan yang cuma bertanya kepada sistem tentang dirinya sendiri akan membenarkan keadaan apa pun yang sedang dialami sistem itu, termasuk keadaan yang keliru.
Dua sisanya sependek hitungan tabel tadi, dan masing-masing menjawab satu hambatan yang tersisa. Yang pertama bertanya kepada runtime: himpunan container ini sebenarnya milik stack yang mana? Label di docker ps tak sanggup menjawabnya, sebab label itulah yang justru menyesatkan di seksi D.
# Ownership, not naming: which project does the runtime think these are?
Yang kedua menjalankan name resolution untuk nama service dari dalam satu environment, lalu mencocokkan alamat yang kembali dengan subnet yang semestinya ditempati environment itu. Name resolution yang berhasil bukan intinya; nama yang menunjuk ke rentang yang salah itulah intinya.
# Expect 10.x.2.x from inside staging. Anything else is a crossed boundary.
C. Berapa sebenarnya ongkos berbagi satu host
Tiga environment di satu mesin bukan gratis, dan ongkosnya terutama memori. Tiap environment menjalankan klaster pencariannya sendiri, dan klaster pencarian bukan barang sederhana: tiga stack penuh bersama-sama meminta kira-kira empat belas gigabyte.
Prakteknya ketiganya jarang hidup berbarengan. Staging ada selama peninjauan rilis berlangsung lalu diturunkan; konfigurasi dan datanya tetap hidup, container-nya tak perlu. Itu sifat rancangan yang disengaja — environment yang murah dihidupkan kembali tak perlu terus menyala.
Yang tidak jadi ongkos dari berbagi host, begitu ketiga pemisahan di atas terpasang, adalah keselamatan. Ketiga environment tak bisa saling menggapai lewat jaringan, tak bisa saling membaca data, dan tak bisa saling membuang container.
D. Di mana pendekatan ini berhenti cocok
Perlu saya sebut batasnya, sebab "tiga environment, satu mesin" bukan anjuran yang berlaku umum.
Pendekatan ini cocok di sini karena beban production-nya sedang dan bisa ditebak — layanan internal untuk populasi user yang diketahui, bukan situs publik dengan lalu lintas naik-turun. Kalau production harus tahan lonjakan, berbagi host dengan dua environment lain tak bisa dibela: tetangga berisiknya adalah Anda sendiri.
Ia pun mengandaikan operator tunggal. Sebagian besar yang membuatnya aman adalah adanya satu orang yang tahu environment mana yang sedang menyala. Dengan tim yang lebih besar, pemisahan yang sama perlu ditegakkan mekanisme yang lebih kokoh daripada kesepakatan.
Yang berlaku umum adalah cara menalarnya. Apa pun keterbatasan Anda, pertanyaannya sama: hal mana yang wajib terpisah, dan apa kegagalannya bila tidak? Untuk jaringan, kegagalannya service menggapai environment yang keliru. Untuk state, satu operasi folder memusnahkan database. Untuk identitas project di runtime, satu environment membuang container milik environment lain — dan yang terakhir ini layak diperiksa hari ini juga, sebab nilai bawaannya senyap dan gejalanya menyerupai hal lain sama sekali.
Simpulan
Tiga environment di satu mesin adalah pertukaran yang disengaja, dan ia bertahan selama pemisahannya sungguhan. Jaringan dipisah subnet, state dipisah dari kode lewat path absolut, dan stack dipisah lewat identitas project yang dinyatakan terang-terangan — ketiganya menutup tabrakan yang benar-benar bisa terjadi.
Pelajaran yang lebih luas menyangkut satu golongan kegagalan, bukan satu setelan konfigurasi. Kegagalan yang paling mahal di sini tak mengumumkan dirinya. Stack yang terikat ke direktori data yang keliru lolos semua pemeriksaan. Stack yang berbagi identitas project dengan stack lain tak memperingatkan sebelum membuangnya. Keduanya terlihat persis seperti keberhasilan, sampai detik seseorang menghitung apa yang semestinya ada dan menemukan nol.
Maka pemeriksaan yang layak dipertahankan adalah yang menanyakan perkara yang tak bisa dijawab benar oleh sistem yang rusak. Bukan "apakah service-nya menyala?" — service dengan database kosong menyala dengan indah. Hitung tabelnya.
Istilah
- Environment
- Satu salinan sistem yang utuh dan berjalan — service, data, dan konfigurasi — yang dijaga terpisah dari salinan lain.
- Staging
- Environment untuk menggladi bersih rilis di atas data yang menyerupai aslinya, sebelum rilis itu sampai ke production.
- Subnet
- Rentang alamat jaringan yang dipesan. Memberi tiap environment rentangnya sendiri menahan service-nya agar tak saling menggapai.
- Gateway
- Alamat yang ditempati host pada sebuah jaringan container, dipakai container untuk menggapai layanan di luarnya. Lebih baik diturunkan dari subnet ketimbang dikonfigurasi terpisah.
- Nama project
- Identitas yang dipakai runtime container untuk memutuskan container mana milik sebuah stack. Nilai bawaannya nama folder — itu sebabnya nama folder kembar di environment berbeda itu berbahaya.
- Folder stateless
- Direktori project yang cuma memuat konfigurasi, sehingga menyalin, memindah, atau menghapusnya tak mungkin memusnahkan data.
Technologies covered
- Bash
- Linux
- Docker