Membangun alur CI/CD untuk layanan mikro di Kubernetes dengan Azure DevOps dan Helm

Azure Kubernetes Service (AKS)
Azure Container Registry
Azure DevOps

Mungkin sulit untuk membuat proses integrasi berkelanjutan/pengiriman berkelanjutan (CI/CD) yang andal untuk arsitektur layanan mikro. Masing-masing tim harus dapat merilis layanan dengan cepat dan andal, tanpa mengganggu tim lain atau mengacaukan aplikasi secara keseluruhan.

Artikel ini menjelaskan contoh saluran CI/CD untuk menerapkan layanan mikro ke Azure Kubernetes Service (AKS). Setiap tim dan proyek itu berbeda, jangan menganggap artikel ini sebagai seperangkat aturan yang mengikat. Sebaliknya, ini dimaksudkan sebagai titik awal untuk merancang proses CI/CD Anda sendiri.

Tujuan dari saluran CI/CD untuk layanan mikro yang disimpan Kubernetes dapat diringkas sebagai berikut:

  • Tim dapat membangun dan menerapkan layanan mereka secara mandiri.
  • Perubahan kode yang melewati proses CI secara otomatis diterapkan ke lingkungan seperti produksi.
  • Gerbang kualitas diberlakukan pada setiap tahap saluran.
  • Layanan versi baru dapat ditempatkan secara berdampingan dengan versi sebelumnya.

Untuk informasi selengkapnya, lihat CI/CD untuk arsitektur layanan mikro.

Asumsi

Untuk tujuan contoh ini, berikut adalah beberapa asumsi tentang tim pengembangan dan basis kode:

  • Kode repositori adalah monorepo, dengan folder yang diatur oleh layanan mikro.
  • Strategi percabangan tim berdasarkan pada pengembangan basis batang.
  • Tim menggunakan cabang rilisuntuk mengelola rilis. Rilis terpisah dibuat untuk setiap layanan mikro.
  • Proses CI/CD menggunakan Azure Pipelines untuk membangun, menguji, dan menyebarkan layanan mikro ke AKS.
  • Gambar kontainer untuk layanan mikro disimpan di Azure Container Registry.
  • Tim menggunakan diagram Helm untuk mengemas setiap layanan mikro.
  • Model penyebaran push digunakan, di mana Azure Pipelines dan agen terkait melakukan penyebaran dengan menyambungkan langsung ke kluster AKS.

Asumsi ini mendorong banyak detail spesifik saluran CI/CD. Namun, pendekatan dasar yang dijelaskan di sini disesuaikan untuk proses, alat, dan layanan lain, seperti Jenkins atau Docker Hub.

Alternatif

Berikut ini adalah alternatif umum yang mungkin digunakan pelanggan saat memilih strategi CI/CD dengan Azure Kubernetes Service:

  • Sebagai alternatif untuk menggunakan Helm sebagai alat manajemen dan penyebaran paket, Kustomize adalah alat manajemen konfigurasi asli Kubernetes yang memperkenalkan cara bebas templat untuk menyesuaikan dan membuat parameter konfigurasi aplikasi.
  • Sebagai alternatif untuk menggunakan Azure DevOps untuk repositori dan alur Git, Repositori GitHub dapat digunakan untuk repositori Git privat dan publik, dan GitHub Actions dapat digunakan untuk alur CI/CD.
  • Sebagai alternatif untuk menggunakan model penyebaran push, mengelola konfigurasi Kubernetes dalam skala besar dapat dilakukan menggunakan GitOps (model penyebaran pull), di mana operator Kubernetes dalam kluster menyinkronkan status kluster, berdasarkan konfigurasi yang disimpan dalam repositori Git.

Pembuatan validasi

Misalkan pengembang sedang mengerjakan layanan mikro yang disebut Delivery Service. Saat mengembangkan fitur baru, pengembang memeriksa kode ke cabang fitur. Dengan konvensi, cabang fitur diberi nama feature/*.

CI/CD workflow

Pengembangan berkas definisi menyertakan pemicu yang memfilter berdasarkan nama cabang dan sumber:

trigger:
  batch: true
  branches:
    include:
    # for new release to production: release flow strategy
    - release/delivery/v*
    - refs/release/delivery/v*
    - master
    - feature/delivery/*
    - topic/delivery/*
  paths:
    include:
    - /src/shipping/delivery/

Dengan menggunakan pendekatan ini, setiap tim dapat memiliki saluran pembangunannya sendiri. Hanya kode yang dicentang ke dalam /src/shipping/deliveryfolder yang memicu pembuatan Layanan Pengiriman. Mendorong komitmen ke cabang yang cocok dengan filter akan memicu pembuatan CI. Pada titik dalam alur kerja ini, pembuatan CI akan menjalankan beberapa verifikasi kode minimal:

  1. Buat kode.
  2. Jalankan pengujian unit.

Tujuannya adalah untuk mempersingkat waktu pembuatan sehingga pengembang bisa mendapatkan umpan balik yang cepat. Setelah fitur siap untuk bergabung di master, pengembang membuka PR. Operasi ini memicu pembangunana CI lain yang melakukan beberapa pemeriksaan tambahan:

  1. Buat kode.
  2. Jalankan pengujian unit.
  3. Buat proses gambar kontainer.
  4. Jalankan pemindaian kerentanan pada gambar.

Diagram showing ci-delivery-full in the Build pipeline.

Catatan

Di Azure DevOps Repos, Anda dapat menentukan kebijakan untuk melindungi cabang. Misalnya, kebijakan tersebut memerlukan pengembangan CI yang berhasil mendapat izin dari pemberi persetujuan untuk bergabung menjadi master.

Pembuatan CI/CD penuh

Pada titik tertentu, tim siap untuk menerapkan versi baru dari layanan Pengiriman. Manajer rilis membuat cabang dari cabang utama dengan pola penamaan berikut:release/<microservice name>/<semver>. Contohnya, release/delivery/v1.0.2.

Diagram showing ci-delivery-full in the Build pipeline and cd-delivery in the Release pipeline.

Pembuatan cabang ini memicu pengembangan CI lengkap yang menjalankan semua langkah sebelumnya ditambah:

  1. Dorong gambar kontainer ke Azure Container Registry. Gambar ditandai dengan nomor versi yang diambil dari nama cabang.
  2. Jalankanhelm package pengemasan bagan Helm untuk layanan tersebut. Tandai juga bagan dengan nomor versi.
  3. Dorong paket Helm ke Container Registry.

Dengan asumsi pengembangan berhasil, itu akan memicu proses penyebaran (CD) menggunakan Azure Pipelines saluran rilis. Saluran ini terdiri dari beberapa langkah berikut:

  1. Terapkan bagan Helm ke lingkungan QA.
  2. Pilih persetujuan untuk menandatangani sebelum paket di pindah ke produksi. Lihat lepaskan kontrol penerapan rilis menggunakan persetujuan.
  3. Lakukan penandaan ulang gambar Docker untuk ruang nama produksi di Azure Container Registry. Misalnya, jika tag saat ini adalah myrepo.azurecr.io/delivery:v1.0.2, tag produksi adalah myrepo.azurecr.io/prod/delivery:v1.0.2.
  4. Terapkan bagan Helm ke lingkungan produksi.

Bahkan dalam monorepo, tugas-tugas ini dapat digabungkan ke layanan mikro individu sehingga tim dapat menyebar dengan kecepatan tinggi. Proses ini memiliki beberapa langkah manual: Menyetujui PR, membuat cabang rilis, dan menyetujui penerapan ke dalam cluster produksi. Langkah-langkah ini dilakukan secara manual; namun dapat diotomatisasi jika diinginkan oleh organisasi.

Isolasi lingkungan

Anda memiliki beberapa lingkungan tempat untuk menerapkan layanan, termasuk lingkungan untuk pengembangan, pengujian asap, pengujian integrasi, pengujian beban, dan terakhir, produksi. Lingkungan membutuhkan beberapa tingkat isolasi. Di Kubernetes, Anda memiliki pilihan antara isolasi fisik dan isolasi logis. Isolasi fisik berarti menyebarkan ke klaster yang terpisah. Isolasi logis menggunakan ruang nama dan kebijakan, seperti yang dijelaskan sebelumnya.

Rekomendasi kami adalah membuat klaster produksi khusus bersama dengan klaster terpisah untuk lingkungan pengembangan/pengujian Anda. Gunakan isolasi logis untuk memisahkan lingkungan dalam klaster pengembangan/pengujian. Layanan yang disebarkan ke klaster pengembangan/pengujian tidak memiliki akses ke penyimpanan data bisnis.

Proses build

Jika memungkinkan, kemas proses build Anda ke dalam kontainer Docker. Konfigurasi ini memungkinkan Anda membuat kode menggunakan Docker dan tanpa mengonfigurasi lingkungan build di setiap mesin build. Proses build dalam kontainer memudahkan penskalaan saluran CI dengan menambahkan agen build baru. Selain itu, pengembang mana pun di tim dapat membuat kode hanya dengan menjalankan kontainer build.

Dengan menggunakan build multi-tahap di Docker, Anda dapat menentukan lingkungan build dan menjalankan gambar dalam satu Dockerfile. Sebagai contoh, berikut Dockerfile untuk membangun aplikasi .NET:

FROM mcr.microsoft.com/dotnet/core/runtime:3.1 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src/Fabrikam.Workflow.Service

COPY Fabrikam.Workflow.Service/Fabrikam.Workflow.Service.csproj .
RUN dotnet restore Fabrikam.Workflow.Service.csproj

COPY Fabrikam.Workflow.Service/. .
RUN dotnet build Fabrikam.Workflow.Service.csproj -c release -o /app --no-restore

FROM build AS testrunner
WORKDIR /src/tests

COPY Fabrikam.Workflow.Service.Tests/*.csproj .
RUN dotnet restore Fabrikam.Workflow.Service.Tests.csproj

COPY Fabrikam.Workflow.Service.Tests/. .
ENTRYPOINT ["dotnet", "test", "--logger:trx"]

FROM build AS publish
RUN dotnet publish Fabrikam.Workflow.Service.csproj -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Fabrikam.Workflow.Service.dll"]

Dockerfile ini mendefinisikan beberapa tahapan build. Perhatikan bahwa tahapan base menggunakan .NET runtime, sedangkan tahapan build menggunakan .NET SDK lengkap. Tahap ini builddigunakan untuk membangun proyek .NET. Namun wadah runtime terakhir dibuat dari base, yang hanya berisi runtime dan secara signifikan lebih kecil dari gambar SDK lengkap.

Melakukan tes pengujian

Praktik baik lainnya adalah menjalankan pengujian unit dalam wadah. Misalnya, berikut adalah bagian dari file Docker yang membangun tes pengujian:

FROM build AS testrunner
WORKDIR /src/tests

COPY Fabrikam.Workflow.Service.Tests/*.csproj .
RUN dotnet restore Fabrikam.Workflow.Service.Tests.csproj

COPY Fabrikam.Workflow.Service.Tests/. .
ENTRYPOINT ["dotnet", "test", "--logger:trx"]

Pengembang dapat menggunakan file Docker ini untuk menjalankan pengujian secara lokal:

docker build . -t delivery-test:1 --target=testrunner
docker run delivery-test:1

Alur CI juga harus menjalankan pengujian sebagai bagian dari langkah verifikasi.

Perhatikan bahwa file ini menggunakan perintah ENTRYPOINT Docker untuk menjalankan tes, bukan perintah RUNDocker.

  • Jika Anda menggunakan perintah RUN, pengujian dilakukan setiap kali Anda membuat gambar. Dengan menggunakanENTRYPOINT, tes menjadi opsional. Mereka berjalan hanya ketika Anda secara eksplisit menargetkan testrunner lokasi.
  • Tes yang gagal tidak menyebabkan perintah Docker buildgagal. Dengan begitu, Anda dapat membedakan kegagalan pembuatan kontainer dengan kegagalan pengujian.
  • Hasil tes dapat disimpan ke volume terpasang.

Praktik baik kontainer

Berikut beberapa praktik baik lain yang perlu dipertimbangkan untuk kontainer:

  • Tetapkan konvensi di seluruh organisasi untuk tanda penampung, pembuatan versi, dan konvensi penamaan untuk sumber daya yang tersebar di klaster (pod, layanan, dan sebagainya). Hal itu akan mempermudah untuk mendiagnosis masalah penerapan.

  • Selama siklus pengembangan dan pengujian, proses CI/CD akan menghasilkan banyak gambar kontainer. Hanya beberapa dari gambar tersebut yang merupakan kandidat untuk dirilis, dan hanya beberapa dari kandidat rilis tersebut yang akan dipromosikan ke produksi. Miliki strategi pembuatan versi yang jelas sehingga Anda tahu gambar mana yang saat ini diterapkan ke produksi dan untuk membantu memutar kembali ke versi sebelumnya jika diperlukan.

  • Selalu terapkan tanda versi penampung tertentu, bukanlatest.

  • Gunakan ruang di Azure Container Registry untuk mengisolasi gambar yang disetujui untuk produksi dari gambar yang masih diuji. Jangan pindahkan gambar ke ruang produksi sampai Anda siap menerapkannya ke produksi. Jika Anda menggabungkan dengan versi semantik dari penampungan gambar, ini dapat mengurangi kemungkinan penerapan versi yang tidak sesuai untuk rilis secara tidak sengaja.

  • Ikuti prinsip hak istimewa terendah dengan menjalankan kontainer sebagai pengguna yang tidak memiliki hak istimewa. Di Kubernetes, Anda dapat membuat kebijakan keamanan pod yang mencegah kontainer berjalan sebagai root.

Bagan Helm

Pertimbangkan untuk menggunakan Helm dalam mengelola pembuatan dan penerapan layanan. Berikut beberapa fitur Helm yang membantu CI/CD:

  • Seringkali, satu layanan mikro didefinisikan oleh beberapa objek Kubernetes. Helm memungkinkan objek-objek ini untuk dikemas ke dalam satu bagan Helm.
  • Bagan dapat dijalankan dengan satu perintah Helm daripada serangkaian perintah kubectl.
  • Bagan terdiri dari beberapa versi. Gunakan Helm untuk merilis versi, melihat rilis, dan mengembalikan ke versi sebelumnya. Melacak pembaruan dan revisi, menggunakan versi semantik, dapat dilakukan bersama dengan mengembalikan ke versi sebelumnya.
  • Bagan helm menggunakan templat untuk menghindari duplikasi informasi, seperti label dan pemilih, di beberapa berkas.
  • Helm dapat mengatur ketergantungan antar grafik.
  • Bagan dapat disimpan dalam repositori Helm, seperti Azure Container Registry, dan diintegrasikan ke dalam alur build.

Untuk informasi selengkapnya tentang penggunaan Container Registry sebagai repositori Helm, lihat cara menggunakan Azure Container Registry sebagai repositori Helm bagan aplikasi .

Layanan mikro tunggal melibatkan beberapa konfigurasi Kubernetes. Memperbarui layanan dapat berarti menyentuh semua berkas ini untuk memperbarui pemilih, label, dan tanda gambar. Helm memberlakukan ini sebagai satu paket yang disebut bagan dan memungkinkan Anda untuk memperbarui YAML dengan mudah menggunakan variabel. Helm menggunakan bahasa templat (berdasarkan template Go) untuk memungkinkan Anda menulis konfigurasi YAML dengan parameter.

Misalnya, ini merupakan bagian dari YAML yang mendefinisikan pengembangan:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "package.fullname" . | replace "." "" }}
  labels:
    app.kubernetes.io/name: {{ include "package.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
  annotations:
    kubernetes.io/change-cause: {{ .Values.reason }}

...

  spec:
      containers:
      - name: &package-container_name fabrikam-package
        image: {{ .Values.dockerregistry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        env:
        - name: LOG_LEVEL
          value: {{ .Values.log.level }}

Anda dapat melihat bahwa penerapan nama, label, dan spesifikasi kontainer semuanya menggunakan parameter templat, yang disediakan pada waktu pengembangan. Misalnya, dari perintah:

helm install $HELM_CHARTS/package/ \
     --set image.tag=0.1.0 \
     --set image.repository=package \
     --set dockerregistry=$ACR_SERVER \
     --namespace backend \
     --name package-v0.1.0

Meskipun alur CI/CD Anda dapat menginstal bagan langsung ke Kubernetes, sebaiknya buat arsip bagan (.tgz file) dan dorong bagan ke repositori Helm seperti Azure Container Registry. Untuk informasi selengkapnya, lihat Paket aplikasi berbasis Docker di bagan Helm di Azure Pipelines .

Revisi

Bagan helm selalu memiliki nomor versi, biasanya menggunakan versi semantik. Bagan juga dapat memilikiappVersion. Kegiatan ini opsional dan tidak terkait dengan versi bagan. Beberapa tim mungkin menginginkan versi aplikasi secara terpisah dari pembaruan bagan. Tetapi pendekatan yang lebih sederhana adalah dengan menggunakan satu nomor versi, jadi ada hubungan 1:1 antara versi bagan dan versi aplikasi. Dengan begitu, Anda dapat menyimpan satu bagan per rilis dan dengan mudah menerapkan rilis yang diinginkan:

helm install <package-chart-name> --version <desiredVersion>

Praktik baik lainnya adalah menyediakan anotasi penyebab perubahan dalam templet pengembangan:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "delivery.fullname" . | replace "." "" }}
  labels:
     ...
  annotations:
    kubernetes.io/change-cause: {{ .Values.reason }}

Ini memungkinkan Anda melihat penyebab perubahan pada setiap revisi, dengan menggunakan kubectl rollout historyperintah. Pada contoh sebelumnya, penyebab perubahan disediakan sebagai parameter diagram Helm.

kubectl rollout history deployments/delivery-v010 -n backend
deployment.extensions/delivery-v010
REVISION  CHANGE-CAUSE
1         Initial deployment

Anda dapat menggunakan helm listperintah untuk melihat riwayat revisi:

helm list
NAME            REVISION    UPDATED                     STATUS        CHART            APP VERSION     NAMESPACE
delivery-v0.1.0 1           Sun Apr  7 00:25:30 2020    DEPLOYED      delivery-v0.1.0  v0.1.0          backend

Azure DevOps Pipeline

Di Azure Pipelines, alur dibagi menjadi alur build dan alur rilis. Alur build menjalankan proses CI dan membuat artefak build. Untuk arsitektur layanan mikro di Kubernetes, artefak merupakan gambar kontainer dan diagram Helm yang mendefinisikan setiap layanan mikro. Alur rilis menjalankan proses CD yang menyebarkan layanan mikro ke dalam sebuah klaster.

Berdasarkan alur CI yang dijelaskan sebelumnya dalam artikel ini, alur build terdiri dari bagian berikut:

  1. Bangun pengujian kontainer.

    - task: Docker@1
      inputs:
        azureSubscriptionEndpoint: $(AzureSubscription)
        azureContainerRegistry: $(AzureContainerRegistry)
        arguments: '--pull --target testrunner'
        dockerFile: $(System.DefaultWorkingDirectory)/$(dockerFileName)
        imageName: '$(imageName)-test'
    
  2. Lakukan pengujian, dengan menjalankan docker run pada saat menguji kontainer.

    - task: Docker@1
      inputs:
        azureSubscriptionEndpoint: $(AzureSubscription)
        azureContainerRegistry: $(AzureContainerRegistry)
        command: 'run'
        containerName: testrunner
        volumes: '$(System.DefaultWorkingDirectory)/TestResults:/app/tests/TestResults'
        imageName: '$(imageName)-test'
        runInBackground: false
    
  3. Publikasikan hasil tes. Lihat Membuat gambar.

    - task: PublishTestResults@2
      inputs:
        testResultsFormat: 'VSTest'
        testResultsFiles: 'TestResults/*.trx'
        searchFolder: '$(System.DefaultWorkingDirectory)'
        publishRunAttachments: true
    
  4. Buat proses gambar kontainer.

    - task: Docker@1
      inputs:
        azureSubscriptionEndpoint: $(AzureSubscription)
        azureContainerRegistry: $(AzureContainerRegistry)
        dockerFile: $(System.DefaultWorkingDirectory)/$(dockerFileName)
        includeLatestTag: false
        imageName: '$(imageName)'
    
  5. Dorong gambar ke Azure Container Registry (atau registri kontainer lainnya).

    - task: Docker@1
      inputs:
        azureSubscriptionEndpoint: $(AzureSubscription)
        azureContainerRegistry: $(AzureContainerRegistry)
        command: 'Push an image'
        imageName: '$(imageName)'
        includeSourceTags: false
    
  6. Kemas bagan Helm.

    - task: HelmDeploy@0
      inputs:
        command: package
        chartPath: $(chartPath)
        chartVersion: $(Build.SourceBranchName)
        arguments: '--app-version $(Build.SourceBranchName)'
    
  7. Dorong paket Helm ke Azure Container Registry (atau repositori Helm lainnya).

    task: AzureCLI@1
      inputs:
        azureSubscription: $(AzureSubscription)
        scriptLocation: inlineScript
        inlineScript: |
        az acr helm push $(System.ArtifactsDirectory)/$(repositoryName)-$(Build.SourceBranchName).tgz --name $(AzureContainerRegistry);
    

Keluaran dari alur CI adalah gambar kontainer siap produksi dan bagan Helm yang diperbarui untuk layanan mikro. Pada titik ini, alur rilis dapat mengambil alih. Akan ada alur rilis unik untuk setiap layanan mikro. Alur rilis akan dikonfigurasi agar sumber pemicu diatur ke alur CI yang menerbitkan artefak. Alur ini memungkinkan Anda untuk memiliki penyebaran independen dari setiap layanan mikro. Alur rilis melakukan langkah-langkah berikut:

  • Sebarkan bagan Helm ke lingkungan dev/QA/staging. Perintah Helm upgrade dapat digunakan dengan --install bendera untuk mendukung penginstalan pertama dan peningkatan berikutnya.
  • Tunggu hingga pemberi persetujuan menyetujui atau menolak penerapan tersebut.
  • Beri tanda ulang pada gambar kontainer yang akan dirilis
  • Dorong tanda rilis ke registri kontainer.
  • Sebarkan bagan Helm di kluster produksi.

Untuk informasi selengkapnya tentang pembuatan alur rilis, lihat Alur rilis, draf rilis, dan opsi rilis.

Diagram berikut menjelaskan proses end-to-end CI/CD dalam artikel ini:

CD/CD pipeline

Kontributor

Artikel ini dikelola oleh Microsoft. Ini awalnya ditulis oleh kontributor berikut.

Penulis utama:

Untuk melihat profil LinkedIn non-publik, masuk ke LinkedIn.

Langkah berikutnya