Pendekatan yang Lebih Baik untuk Penerapan Berkelanjutan Google Cloud

Diterbitkan: 2022-03-11

Continuous deployment (CD) adalah praktik penerapan kode baru secara otomatis ke produksi. Sebagian besar sistem penerapan berkelanjutan memvalidasi bahwa kode yang akan digunakan layak dengan menjalankan unit dan pengujian fungsional, dan jika semuanya terlihat baik, penerapan diluncurkan. Peluncuran itu sendiri biasanya terjadi secara bertahap agar dapat melakukan rollback jika kode tidak berperilaku seperti yang diharapkan.

Tidak ada kekurangan posting blog tentang cara mengimplementasikan pipa CD Anda sendiri menggunakan berbagai alat seperti tumpukan AWS, tumpukan Google Cloud, pipa Bitbucket, dll. Tetapi saya menemukan bahwa kebanyakan dari mereka tidak sesuai dengan ide saya tentang pipa CD yang bagus. akan terlihat seperti: yang pertama dibuat, dan hanya menguji dan menyebarkan file tunggal itu.

Dalam artikel ini, saya akan membuat pipeline penerapan berkelanjutan berbasis peristiwa yang dibuat terlebih dahulu dan kemudian menjalankan pengujian pada artefak akhir penerapan kami. Ini tidak hanya membuat hasil pengujian kami lebih andal, tetapi juga membuat saluran CD mudah diperpanjang. Ini akan terlihat seperti ini:

  1. Komit dibuat ke repositori sumber kami.
  2. Ini memicu pembuatan gambar terkait.
  3. Pengujian dijalankan pada artefak yang dibangun.
  4. Jika semuanya terlihat bagus, gambar dikerahkan ke produksi.

Artikel ini mengasumsikan setidaknya pemahaman yang lewat dengan Kubernetes dan teknologi container, tetapi jika Anda tidak terbiasa atau dapat menggunakan penyegaran, lihat Apa itu Kubernetes? Panduan untuk Containerization dan Deployment.

Masalah dengan Kebanyakan Pengaturan CD

Inilah masalah saya dengan sebagian besar saluran pipa CD: Mereka biasanya melakukan semua yang ada di file build. Sebagian besar posting blog yang saya baca tentang ini akan memiliki beberapa variasi dari urutan berikut dalam file build apa pun yang mereka miliki ( cloudbuild.yaml untuk Google Cloud Build, bitbucket-pipeline.yaml untuk Bitbucket).

  1. Jalankan tes
  2. Bangun gambar
  3. Dorong gambar ke repo kontainer
  4. Perbarui lingkungan dengan gambar baru

Anda tidak menjalankan pengujian pada artefak akhir Anda.

Dengan melakukan hal-hal dalam urutan ini, Anda menjalankan tes Anda. Jika mereka berhasil, Anda membangun citra dan melanjutkan dengan sisa alur. Apa yang terjadi jika proses pembuatan mengubah gambar Anda sedemikian rupa sehingga tes tidak lulus lagi? Menurut pendapat saya, Anda harus mulai dengan memproduksi artefak (gambar kontainer akhir) dan artefak ini tidak boleh berubah antara build dan waktu digunakan untuk produksi. Ini memastikan bahwa data yang Anda miliki tentang artefak tersebut (hasil tes, ukuran, dll) selalu valid.

Lingkungan bangunan Anda memiliki "kunci kerajaan".

Dengan menggunakan lingkungan build untuk men-deploy image ke tumpukan produksi, Anda secara efektif mengizinkannya mengubah lingkungan produksi. Saya melihat ini sebagai hal yang sangat buruk karena siapa pun yang memiliki akses tulis ke repositori sumber Anda sekarang dapat melakukan apa pun yang mereka inginkan ke lingkungan produksi Anda.

Anda harus menjalankan ulang seluruh pipeline jika langkah terakhir gagal.

Jika langkah terakhir gagal (misalnya, karena masalah kredensial), Anda harus menjalankan kembali seluruh saluran Anda, menghabiskan waktu dan sumber daya lain yang lebih baik digunakan untuk melakukan hal lain.

Ini membawa saya ke poin terakhir saya:

Langkah Anda tidak mandiri.

Dalam pengertian yang lebih umum, memiliki langkah-langkah independen memungkinkan Anda memiliki lebih banyak fleksibilitas dalam saluran Anda. Katakanlah Anda ingin menambahkan tes fungsional ke saluran Anda. Dengan memiliki langkah-langkah Anda dalam satu file build, Anda harus membuat lingkungan build Anda menjalankan lingkungan pengujian fungsional dan menjalankan pengujian di dalamnya (kemungkinan besar secara berurutan). Jika langkah Anda independen, Anda dapat memulai pengujian unit dan pengujian fungsional dengan peristiwa "image built". Mereka kemudian akan berjalan secara paralel di lingkungan mereka sendiri.

Pengaturan CD Ideal Saya

Menurut pendapat saya, cara yang lebih baik untuk mendekati masalah ini adalah dengan memiliki serangkaian langkah independen yang semuanya dihubungkan bersama oleh mekanisme peristiwa.

Ini memiliki beberapa keunggulan dibandingkan dengan metode sebelumnya:

Anda dapat mengambil beberapa tindakan independen pada acara yang berbeda.

Seperti yang dinyatakan di atas, pembuatan gambar baru yang berhasil hanya akan menerbitkan acara "pembuatan yang berhasil". Pada gilirannya, kita dapat menjalankan beberapa hal saat peristiwa ini dipicu. Dalam kasus kami, kami akan memulai tes unit dan fungsional. Anda juga dapat memikirkan hal-hal seperti memberi tahu developer saat peristiwa build gagal dipicu atau jika pengujian tidak lulus.

Setiap lingkungan memiliki seperangkat haknya sendiri.

Dengan membuat setiap langkah terjadi di lingkungannya sendiri, kami menghilangkan kebutuhan akan satu lingkungan untuk memiliki semua hak. Sekarang lingkungan build hanya dapat membangun, lingkungan pengujian hanya dapat menguji, dan lingkungan penerapan hanya dapat diterapkan. Ini memungkinkan Anda untuk yakin bahwa, setelah gambar Anda dibuat, itu tidak akan berubah. Artefak yang dihasilkan adalah yang akan berakhir di tumpukan produksi Anda. Ini juga memungkinkan pengauditan yang lebih mudah tentang langkah mana dari saluran Anda yang melakukan apa karena Anda dapat menautkan satu set kredensial ke satu langkah.

Ada lebih banyak fleksibilitas.

Ingin mengirim email ke seseorang di setiap build yang berhasil? Cukup tambahkan sesuatu yang bereaksi terhadap peristiwa itu dan kirimkan email. Sangat mudah—Anda tidak perlu mengubah kode build Anda dan Anda tidak perlu membuat hardcode email seseorang di repositori sumber Anda.

Percobaan ulang lebih mudah.

Memiliki langkah-langkah independen juga berarti Anda tidak perlu memulai ulang seluruh jalur pipa jika satu langkah gagal. Jika kondisi gagal bersifat sementara atau telah diperbaiki secara manual, Anda bisa saja mencoba kembali langkah yang gagal tersebut. Hal ini memungkinkan untuk pipa yang lebih efisien. Jika langkah pembuatan memakan waktu beberapa menit, sebaiknya Anda tidak perlu membuat ulang gambar hanya karena Anda lupa memberikan akses tulis lingkungan penerapan ke kluster Anda.

Menerapkan Penerapan Berkelanjutan Google Cloud

Google Cloud Platform memiliki semua alat yang diperlukan untuk membangun sistem seperti itu dalam waktu singkat dan dengan sedikit kode.

Aplikasi pengujian kami adalah aplikasi Flask sederhana yang hanya menyajikan sepotong teks statis. Aplikasi ini di-deploy ke cluster Kubernetes yang menyajikannya ke internet yang lebih luas.

Saya akan mengimplementasikan versi sederhana dari pipeline yang saya perkenalkan sebelumnya. Saya pada dasarnya menghapus langkah-langkah pengujian sehingga sekarang terlihat seperti ini:

  • Komit baru dibuat ke repositori sumber
  • Ini memicu pembuatan gambar. Jika berhasil, itu didorong ke repositori penampung dan sebuah acara dipublikasikan ke topik Pub/Sub
  • Skrip kecil berlangganan ke subjek itu dan memeriksa parameter gambar—jika cocok dengan yang kita minta, skrip itu akan disebarkan ke kluster Kubernetes.

Berikut adalah representasi grafis dari pipa kami.

Representasi grafis dari pipa

Alirannya adalah sebagai berikut:

  1. Seseorang melakukan ke repositori kami.
  2. Ini memicu cloud build yang membangun image Docker berdasarkan repositori sumber.
  3. Cloud build mendorong image ke repositori container dan memublikasikan pesan ke cloud pub/sub.
  4. Ini memicu fungsi cloud yang memeriksa parameter dari pesan yang dipublikasikan (status build, nama image yang dibuat, dll.).
  5. Jika parameternya bagus, fungsi cloud memperbarui penerapan Kubernetes dengan gambar baru.
  6. Kubernetes men-deploy container baru dengan image baru.

Kode sumber

Kode sumber kami adalah aplikasi Flask yang sangat sederhana yang hanya menyajikan beberapa teks statis. Berikut adalah struktur proyek kami:

 ├── docker │ ├── Dockerfile │ └── uwsgi.ini ├── k8s │ ├── deployment.yaml │ └── service.yaml ├── LICENSE ├── Pipfile ├── Pipfile.lock └── src └── main.py

Direktori Docker berisi semua yang diperlukan untuk membangun image Docker. Gambar didasarkan dari gambar uWSGI dan Nginx dan hanya menginstal dependensi dan menyalin aplikasi ke jalur yang benar.

Direktori k8s berisi konfigurasi Kubernetes. Ini terdiri dari satu layanan dan satu penyebaran. Deployment memulai satu container berdasarkan image yang dibuat dari Dockerfile . Layanan kemudian memulai penyeimbang beban yang memiliki alamat IP publik dan mengalihkan ke wadah aplikasi.

Pembuatan Awan

Konfigurasi cloud build sendiri dapat dilakukan melalui cloud console atau command line Google Cloud. Saya memilih untuk menggunakan konsol cloud.

Tangkapan layar konsol cloud

Di sini, kami membuat gambar untuk komit apa pun di cabang mana pun, tetapi Anda dapat memiliki gambar yang berbeda untuk pengembangan dan produksi, misalnya.

Jika build berhasil, cloud build akan memublikasikan gambar ke registri penampung sendiri. Ini kemudian akan memublikasikan pesan ke pub/sub topik cloud-builds.

Cloud build juga memublikasikan pesan saat build sedang berlangsung dan saat gagal, jadi Anda juga dapat membuat sesuatu bereaksi terhadap pesan tersebut.

Dokumentasi untuk pemberitahuan pub/sub cloud build ada di sini dan format pesannya dapat ditemukan di sini

Cloud Pub/Sub

Jika Anda melihat di pub/sub tab cloud di konsol cloud, Anda akan melihat bahwa cloud build telah membuat topik yang disebut cloud build. Di sinilah cloud build menerbitkan pembaruan statusnya.

Tangkapan Layar Proyek Pub/Sub

Fungsi Awan

Apa yang akan kita lakukan sekarang adalah membuat fungsi cloud yang dipicu pada setiap pesan yang dipublikasikan ke topik cloud-builds. Sekali lagi, Anda dapat menggunakan konsol cloud atau utilitas baris perintah Google Cloud. Apa yang saya lakukan dalam kasus saya adalah saya menggunakan cloud build untuk menerapkan fungsi cloud setiap kali ada perubahan.

Kode sumber untuk fungsi cloud ada di sini.

Pertama-tama mari kita lihat kode yang menerapkan fungsi cloud ini:

 steps: - name: 'gcr.io/cloud-builders/gcloud' id: 'test' args: ['functions', 'deploy', 'new-image-trigger', '--runtime=python37', '--trigger-topic=cloud-builds', '--entry-point=onNewImage', '--region=us-east1', '--source=https://source.developers.google.com/projects/$PROJECT_ID/repos/$REPO_NAME']

Di sini, kami menggunakan gambar Google Cloud Docker. Ini memungkinkan untuk menjalankan perintah GCcloud dengan mudah. Apa yang kami jalankan setara dengan menjalankan perintah berikut dari terminal secara langsung:

 gcloud functions deploy new-image-trigger --runtime=python37 --trigger-topic=cloud-builds --entry-point=onNewImage --region=us-east1 --source=https://source.developers.google.com/projects/$PROJECT_ID/repos/$REPO_NAME

Kami meminta Google Cloud untuk menerapkan fungsi cloud baru (atau mengganti jika fungsi dengan nama tersebut di wilayah tersebut sudah ada) yang akan menggunakan waktu proses Python 3.7 dan akan dipicu oleh pesan baru dalam topik cloud-builds. Kami juga memberi tahu Google di mana menemukan kode sumber untuk fungsi itu (di sini PROJECT_ID dan REPO_NAME adalah variabel lingkungan yang disetel oleh proses pembuatan). Kami juga memberi tahu fungsi apa yang harus dipanggil sebagai titik masuk.

Sebagai catatan tambahan, agar ini berfungsi, Anda harus memberikan akun layanan cloudbuild Anda "pengembang fungsi cloud" dan "pengguna akun layanan" sehingga dapat menyebarkan fungsi cloud.

Berikut adalah beberapa cuplikan kode fungsi cloud yang dikomentari

Data titik masuk akan berisi pesan yang diterima di pub/sub topik.

 def onNewImage(data, context):

Langkah pertama adalah mendapatkan variabel untuk penerapan spesifik tersebut dari lingkungan (kami mendefinisikannya dengan memodifikasi fungsi cloud di konsol cloud.

 project = os.environ.get('PROJECT') zone = os.environ.get('ZONE') cluster = os.environ.get('CLUSTER') deployment = os.environ.get('DEPLOYMENT') deploy_image = os.environ.get('IMAGE') target_container = os.environ.get('CONTAINER')

Kami akan melewati bagian di mana kami memeriksa bahwa struktur pesan adalah apa yang kami harapkan dan kami memvalidasi bahwa pembangunan berhasil dan menghasilkan satu artefak gambar.

Langkah selanjutnya adalah memastikan bahwa image yang dibangun adalah yang ingin kita deploy.

 image = decoded_data['results']['images'][0]['name'] image_basename = image.split('/')[-1].split(':')[0] if image_basename != deploy_image: logging.error(f'{image_basename} is different from {deploy_image}') return

Sekarang, kami mendapatkan klien Kubernetes dan mengambil penerapan yang ingin kami modifikasi

 v1 = get_kube_client(project, zone, cluster) dep = v1.read_namespaced_deployment(deployment, 'default') if dep is None: logging.error(f'There was no deployment named {deployment}') return

Terakhir, kami menambal penerapan dengan gambar baru; Kubernetes akan mengurus peluncurannya.

 for i, container in enumerate(dep.spec.template.spec.containers): if container.name == target_container: dep.spec.template.spec.containers[i].image = image logging.info(f'Updating to {image}') v1.patch_namespaced_deployment(deployment, 'default', dep)

Kesimpulan

Ini adalah contoh yang sangat mendasar tentang bagaimana saya menyukai hal-hal yang dirancang dalam pipa CD. Anda dapat memiliki lebih banyak langkah hanya dengan mengubah peristiwa pub/sub yang memicu apa.

Misalnya, Anda dapat menjalankan penampung yang menjalankan pengujian di dalam gambar dan memublikasikan peristiwa tentang keberhasilan dan peristiwa lainnya pada kegagalan dan bereaksi terhadapnya dengan memperbarui penerapan atau memberi peringatan bergantung pada hasilnya.

Pipeline yang kami buat cukup sederhana, tetapi Anda dapat menulis fungsi cloud lain untuk bagian lain (misalnya, fungsi cloud yang akan mengirim email ke pengembang yang melakukan kode yang merusak pengujian unit Anda).

Seperti yang Anda lihat, lingkungan build kami tidak dapat mengubah apa pun di cluster Kubernetes kami, dan kode penerapan kami (fungsi cloud) tidak dapat mengubah gambar yang dibuat. Pemisahan hak istimewa kami terlihat bagus, dan kami dapat tidur nyenyak mengetahui bahwa pengembang jahat tidak akan menjatuhkan klaster produksi kami. Kami juga dapat memberi pengembang kami yang lebih berorientasi operasi akses ke kode fungsi cloud sehingga mereka dapat memperbaiki atau meningkatkannya.

Jika Anda memiliki pertanyaan, komentar, atau perbaikan, jangan ragu untuk menghubungi di komentar di bawah.