3-arah bergabung di werf: penyebaran di Kubernetes dengan Helm "on steroids"

Sesuatu terjadi yang kami (dan bukan hanya kami) telah menunggu: werf , utilitas Open Source kami untuk membangun aplikasi dan mengirimkannya ke Kubernetes, sekarang mendukung penerapan perubahan menggunakan tambalan penggabungan 3 arah! Selain itu, dimungkinkan untuk mengadopsi sumber daya K8 yang ada ke dalam rilis Helm tanpa menciptakan kembali sumber daya ini.



Jika ini sangat singkat, maka atur WERF_THREE_WAY_MERGE=enabled - kami mendapatkan penyebaran "seperti di kubectl apply ", kompatibel dengan instalasi yang ada di Helm 2 dan bahkan sedikit lagi.

Tapi mari kita mulai dengan teorinya: apa patch 3-way-merge secara umum, bagaimana orang-orang sampai pada pendekatan dengan generasi mereka, dan mengapa mereka penting dalam proses CI / CD dengan infrastruktur berbasis Kubernet? Dan setelah itu - mari kita lihat apakah penggabungan 3-arah dalam werf itu, mode apa yang digunakan secara default dan bagaimana cara mengelolanya.

Apa itu tambalan 3 arah?


Jadi, mari kita mulai dengan tugas meluncurkan sumber daya yang dijelaskan dalam manifes YAML di Kubernetes.

Untuk bekerja dengan sumber daya, API Kubernetes menawarkan operasi dasar berikut: membuat, menambal, mengganti, dan menghapus. Diasumsikan bahwa dengan bantuan mereka perlu untuk membangun peluncuran sumber daya yang berkesinambungan untuk cluster. Bagaimana?

Tim kubectl yang imperatif


Pendekatan pertama untuk mengelola objek di Kubernetes adalah menggunakan perintah kubectl imperatif untuk membuat, memodifikasi, dan menghapus objek-objek ini. Sederhananya:

  • perintah kubectl run dapat menjalankan Deployment atau Pekerjaan:

     kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE 
  • perintah kubectl scale - ubah jumlah replika:

     kubectl scale --replicas=3 deployment/mysql 
  • dll.

Pandangan seperti itu mungkin tampak nyaman pada pandangan pertama. Namun, ada masalah:

  1. Sulit untuk diotomatisasi .
  2. Bagaimana cara mencerminkan konfigurasi di Git? Bagaimana cara meninjau perubahan yang terjadi pada sebuah cluster?
  3. Bagaimana memastikan reproduksibilitas konfigurasi saat restart?
  4. ...

Jelas bahwa pendekatan ini tidak cocok dengan menyimpan kode aplikasi dan infrastruktur sebagai kode (IaC; atau bahkan GitOps sebagai opsi yang lebih modern, mendapatkan popularitas di ekosistem Kubernetes). Karenanya, tim-tim ini tidak menerima pengembangan lebih lanjut di kubectl.

Buat, dapatkan, ganti, dan hapus operasi


Dengan kreasi utama , semuanya sederhana: kami mengirim manifes ke operasi create api kubus dan sumber daya dibuat. Representasi YAML dari manifes dapat disimpan di Git, dan untuk membuat, gunakan perintah kubectl create -f manifest.yaml .

Menghapus juga sederhana: kita mengganti manifest.yaml sama dari Git ke perintah kubectl delete -f manifest.yaml .

Operasi replace memungkinkan Anda untuk sepenuhnya mengganti konfigurasi sumber daya dengan yang baru, tanpa membuat ulang sumber daya. Ini berarti bahwa sebelum membuat perubahan ke sumber daya, logis untuk meminta versi saat ini dengan operasi get , ubah, dan perbarui dengan operasi replace . Penguncian optimis dibangun ke dalam apiserver kubus, dan jika objek telah berubah setelah get operasi, operasi replace akan gagal.

Untuk menyimpan konfigurasi di Git dan memperbarui menggunakan penggantian, Anda harus melakukan operasi get , tahan konfigurasi dari Git dengan apa yang kami dapatkan, dan lakukan replace . Biasanya, kubectl hanya memungkinkan Anda untuk menggunakan perintah kubectl replace -f manifest.yaml , di mana manifest.yaml adalah manifest.yaml yang disiapkan sepenuhnya (dalam kasus kami, disatukan) yang perlu diinstal. Ternyata pengguna perlu menerapkan manifes gabungan, tetapi ini bukan masalah sepele ...

Perlu dicatat bahwa walaupun manifest.yaml disimpan di Git, kita tidak dapat mengetahui sebelumnya apakah kita perlu membuat objek atau memperbaruinya - ini harus dilakukan oleh perangkat lunak pengguna.

Intinya: dapatkah kita membangun peluncuran berkelanjutan hanya dengan membuat, mengganti, dan menghapus, memastikan bahwa konfigurasi infrastruktur disimpan di Git bersama dengan kode dan CI / CD yang nyaman?

Pada dasarnya, kita dapat ... Untuk melakukan ini, kita perlu mengimplementasikan operasi gabungan manifes dan semacam ikatan yang:

  • memeriksa keberadaan objek di kluster,
  • melakukan penciptaan awal sumber daya,
  • memperbarui atau menghapusnya.

Saat memperbarui, Anda perlu mempertimbangkan bahwa sumber daya mungkin telah berubah sejak yang terakhir get dan secara otomatis menangani kasus penguncian yang optimis - lakukan upaya berulang untuk memperbarui.

Namun, mengapa menciptakan kembali roda ketika kube-apiserver menawarkan cara lain untuk memperbarui sumber daya: operasi patch , yang menghilangkan beberapa masalah yang dijelaskan dari pengguna?

Tambalan


Jadi kami sampai di tambalan.

Patch adalah cara utama untuk menerapkan perubahan pada objek yang ada di Kubernetes. Operasi patch berfungsi agar:

  • pengguna kube-apiserver perlu mengirim patch dalam format JSON dan menentukan objek,
  • dan apiserver itu sendiri akan menangani keadaan objek saat ini dan membawanya ke bentuk yang diinginkan.

Penguncian optimis dalam hal ini tidak diperlukan. Operasi ini lebih deklaratif dibandingkan dengan penggantian, meskipun pada awalnya mungkin tampak sebaliknya.

Dengan cara ini:

  • menggunakan operasi create , kita membuat objek dari manifes dari Git,
  • menggunakan delete - hapus jika objek tidak lagi diperlukan,
  • menggunakan patch - kita memodifikasi objek, membawanya ke bentuk yang dijelaskan dalam Git.

Namun, untuk melakukan ini, Anda harus membuat tambalan yang benar !

Bagaimana tambalan bekerja di Helm 2: 2-way-merge


Pertama kali rilis diinstal, Helm melakukan operasi create pada sumber daya grafik.

Saat memperbarui rilis Helm untuk setiap sumber daya:

  • menghitung tambalan antara versi sumber daya dari bagan sebelumnya dan versi bagan saat ini,
  • terapkan tambalan ini.

Kami akan menyebutnya patch 2-way-merge patch , karena 2 manifesto berpartisipasi dalam pembuatannya:

  • Manifes sumber daya dari rilis sebelumnya,
  • Manifes sumber daya dari sumber daya saat ini.

Saat menghapus, operasi delete dalam apiserver kubus dipanggil untuk sumber daya yang dideklarasikan dalam rilis sebelumnya tetapi tidak dideklarasikan dalam yang sekarang.

Pendekatan dengan 2 cara menggabungkan tambalan memiliki masalah: itu mengarah ke desync keadaan sebenarnya dari sumber daya di cluster dan manifes di Git .

Contoh masalah


  • Di Git, manifes disimpan pada bagan tempat bidang image Penerapan memiliki nilai ubuntu:18.04 .
  • Pengguna melalui kubectl edit mengubah nilai bidang ini ke ubuntu:19.04 .
  • Saat Anda menggunakan kembali bagan, Helm tidak menghasilkan tambalan , karena bidang image di versi rilis sebelumnya dan di bagan saat ini adalah sama.
  • Setelah penyebaran image berulang, ubuntu:19.04 tetap, meskipun ubuntu:18.04 ditulis pada bagan.

Kami mendapatkan desync dan kehilangan declarativeness.

Apa itu sumber daya yang disinkronkan?


Secara umum, tidak mungkin untuk mendapatkan kecocokan lengkap antara manifes sumber daya dalam menjalankan cluster dan manifes dari Git. Karena dalam manifes nyata mungkin ada anotasi layanan / label, wadah tambahan dan data lainnya ditambahkan dan dihapus secara dinamis oleh beberapa pengontrol dari sumber daya. Kami tidak bisa dan tidak ingin menyimpan data ini di Git. Namun, kami ingin saat meluncurkan, bidang yang kami tentukan secara eksplisit di Git mengambil nilai yang sesuai.

Ternyata ini aturan umum dari sumber daya yang disinkronkan : ketika Anda meluncurkan sumber daya, Anda dapat mengubah atau menghapus hanya bidang-bidang yang secara eksplisit ditentukan dalam manifes dari Git (atau terdaftar di versi sebelumnya, tetapi sekarang dihapus).

Patch 3-arah-gabung


Gagasan utama tambalan penggabungan 3-arah : kami membuat tambalan antara versi terapan terakhir manifes dari Git dan versi target manifes dari Git, dengan mempertimbangkan versi manifes saat ini dari gugus kerja. Tambalan terakhir harus mematuhi aturan sumber daya yang disinkronkan:

  • bidang baru yang ditambahkan ke versi target ditambahkan menggunakan tambalan;
  • bidang yang sebelumnya ada dalam versi terakhir yang diterapkan dan tidak ada di bidang target diatur ulang menggunakan tambalan;
  • Bidang dalam versi objek saat ini yang berbeda dari versi target manifes diperbarui menggunakan tambalan.

Dengan prinsip inilah kubectl apply tambalan dihasilkan:

  • versi terapan yang terakhir dari manifes disimpan dalam anotasi objek itu sendiri,
  • target - diambil dari file YAML yang ditentukan,
  • saat ini - dari cluster yang berfungsi.

Sekarang setelah kami memahami teorinya, saatnya untuk memberi tahu Anda apa yang kami lakukan di werf.

Terapkan perubahan ke werf


Sebelumnya, werf, seperti Helm 2, menggunakan patch 2-way-merge.

Perbaikan tambalan


Untuk beralih ke jenis tambalan baru - 3-way-merge - langkah pertama kami memperkenalkan tambalan perbaikan yang disebut.

Saat digunakan, tambalan penggabungan 2 arah standar digunakan, tetapi tidak juga menghasilkan tambalan yang menyinkronkan keadaan sebenarnya dari sumber daya dengan apa yang ditulis dalam Git (tambalan semacam itu dibuat menggunakan aturan sumber daya tersinkronisasi yang sama seperti dijelaskan di atas).

Dalam hal rassynchrony, pada akhir penyebaran, pengguna menerima PERINGATAN dengan pesan dan tambalan yang sesuai, yang harus diterapkan untuk membawa sumber daya ke formulir yang disinkronkan. Juga, tambalan ini dicatat dalam werf.io/repair-patch anotasi khusus. Diasumsikan bahwa pengguna sendiri akan menerapkan tambalan ini dengan tangannya: werf pada prinsipnya tidak akan menerapkannya.

Membuat tambalan perbaikan adalah tindakan sementara yang memungkinkan Anda untuk benar-benar menguji pembuatan tambalan pada prinsip penggabungan 3 arah, tetapi tidak secara otomatis menerapkan tambalan ini. Saat ini, mode operasi ini diaktifkan secara default.

Patch 3-arah-gabung hanya untuk rilis baru


Mulai 1 Desember 2019, versi beta dan alfa dari werf mulai secara default untuk menggunakan patch 3-way-merge penuh untuk menerapkan perubahan hanya untuk rilis Helm baru yang diluncurkan melalui werf. Rilis yang ada akan terus menggunakan pendekatan perbaikan patch 2-arah-gabung +.

Anda dapat mengaktifkan mode operasi ini secara eksplisit dengan mengatur WERF_THREE_WAY_MERGE_MODE=onlyNewReleases sekarang.

Catatan : fitur muncul di werf lebih dari beberapa rilis: di saluran alpha menjadi siap dari versi v1.0.5-alpha.19 , dan di saluran beta dengan v1.0.4-beta.20 .

Patch 3-arah-gabung untuk semua rilis


Mulai 15 Desember 2019, versi beta dan alfa dari werf mulai menggunakan tambalan penggabungan 3-arah sepenuhnya secara default untuk menerapkan perubahan untuk semua rilis.

Mode operasi ini dapat WERF_THREE_WAY_MERGE_MODE=enabled secara eksplisit WERF_THREE_WAY_MERGE_MODE=enabled menetapkan WERF_THREE_WAY_MERGE_MODE=enabled sekarang.

Apa yang harus dilakukan dengan sumber daya autoscaling?


Kubernetes memiliki 2 jenis autoscaling: HPA (horizontal) dan VPA (vertikal).

Horisontal otomatis memilih jumlah replika, vertikal - jumlah sumber daya. Baik jumlah replika dan persyaratan sumber daya ditentukan dalam manifes sumber daya (lihat spec.replicas atau spec.containers[].resources.limits.cpu , spec.containers[].resources.limits.memory dan lainnya ).

Masalah: jika pengguna mengkonfigurasi sumber daya pada bagan sehingga menampilkan nilai spesifik untuk sumber daya atau replika dan auto-scaler diaktifkan untuk sumber daya ini, maka dengan setiap penerapan werf akan mereset nilai-nilai ini ke apa yang tertulis dalam manifes grafik.

Ada dua solusi untuk masalah ini. Sebagai permulaan, yang terbaik adalah membuang nilai autoscale yang ditentukan secara eksplisit dalam manifes grafik. Jika karena alasan tertentu opsi ini tidak cocok (misalnya, karena nyaman untuk menetapkan batas sumber daya awal dan jumlah replika pada grafik), maka werf menawarkan anotasi berikut:

  • werf.io/set-replicas-only-on-creation=true
  • werf.io/set-resources-only-on-creation=true

Jika anotasi semacam itu ada, werf tidak akan mereset nilai yang sesuai pada setiap penyebaran, tetapi hanya menetapkannya pada awal pembuatan sumber daya.

Untuk informasi lebih lanjut, lihat dokumentasi proyek untuk HPA dan VPA .

Tolak penggunaan patch 3-way-merge


Pengguna masih dapat melarang penggunaan tambalan baru di werf menggunakan variabel lingkungan WERF_THREE_WAY_MERGE_MODE=disabled . Namun, mulai 1 Maret 2020, larangan ini akan berhenti berfungsi dan hanya akan mungkin menggunakan tambalan penggabungan 3 arah.

Adopsi sumber daya di werf


Menguasai metode menerapkan perubahan dalam 3-way-merge-patch memungkinkan kami untuk segera mengimplementasikan fitur seperti adopsi sumber daya yang ada di cluster dalam rilis Helm.

Helm 2 memiliki masalah: Anda tidak dapat menambahkan ke manifes bagan sumber daya yang sudah ada di cluster tanpa membuat ulang sumber ini dari awal (lihat # 6031 , # 3275 ). Kami mengajar werf untuk menerima sumber daya yang ada dalam rilis. Untuk melakukan ini, Anda perlu menetapkan anotasi pada versi sumber daya saat ini dari sebuah cluster yang berjalan (misalnya, menggunakan kubectl edit ):

 "werf.io/allow-adoption-by-release": RELEASE_NAME 

Sekarang sumber daya perlu dijelaskan pada bagan dan pada penyebaran berikutnya oleh rilis werf dari rilis dengan nama yang sesuai, sumber daya yang ada akan diterima ke dalam rilis ini dan akan tetap di bawah kendali. Selain itu, dalam proses menerima sumber daya untuk dirilis, werf akan membawa status sumber daya saat ini dari kelompok kerja ke negara yang dijelaskan pada bagan menggunakan tambalan penggabungan 3 arah yang sama dan aturan sumber daya yang disinkronkan.

Catatan : pengaturan WERF_THREE_WAY_MERGE_MODE tidak memengaruhi adopsi sumber daya - dalam hal adopsi, patch gabungan 3 arah selalu digunakan.

Detailnya ada di dokumentasi .

Kesimpulan dan Rencana Masa Depan


Saya berharap bahwa setelah artikel ini menjadi lebih jelas apa patch 3-way-merge dan mengapa mereka datang kepada mereka. Dari sudut pandang praktis pengembangan proyek werf, implementasi mereka adalah langkah lain menuju peningkatan penyebaran Helm-seperti. Sekarang Anda dapat melupakan masalah dengan sinkronisasi konfigurasi, yang sering terjadi ketika menggunakan Helm 2. Pada saat yang sama, fitur baru yang bermanfaat dari adopsi sumber daya Kubernet yang sudah diunggah ke rilis Helm telah ditambahkan.

Masih ada beberapa masalah dan kesulitan dalam penerapan seperti Helm, seperti penggunaan templat-Go, dan kami akan terus menyelesaikannya.

Informasi tentang metode pembaruan sumber daya dan adopsi juga dapat ditemukan di halaman dokumentasi ini .

Helm 3


Catatan khusus layak untuk versi utama Helm yang baru dirilis baru-baru ini - v3 - yang juga menggunakan tambalan penggabungan 3 arah dan menyingkirkan Tiller. Versi baru Helm memerlukan migrasi instalasi yang ada untuk mengubahnya menjadi format penyimpanan rilis baru.

Werf, pada bagiannya, sekarang telah menghilangkan penggunaan Tiller, beralih ke penggabungan 3-arah dan menambahkan lebih banyak , sambil tetap kompatibel dengan instalasi yang ada di Helm 2 (tidak ada skrip migrasi yang diperlukan). Oleh karena itu, sampai werf beralih ke Helm 3, pengguna werf tidak kehilangan keunggulan utama Helm 3 dibandingkan Helm 2 (mereka juga ada di werf).

Namun, beralih werf ke basis kode Helm 3 tidak bisa dihindari dan akan terjadi dalam waktu dekat. Agaknya itu bukan werf 1.1 atau werf 1.2 (saat ini, versi utama werf adalah 1.0; untuk rincian lebih lanjut tentang perangkat versi werf lihat di sini ). Selama waktu ini, Helm 3 akan memiliki waktu untuk stabil.

PS


Baca juga di blog kami:

Source: https://habr.com/ru/post/id476646/


All Articles