CI/CD-folyamat létrehozása mikroszolgáltatásokhoz a Kubernetesen az Azure DevOps és a Helm használatával

Azure Kubernetes Service (AKS)
Azure Container Registry
Azure DevOps

Egy mikroszolgáltatás-architektúra megbízható folyamatos integrációs/folyamatos kézbesítési (CI/CD) folyamatának létrehozása kihívást jelenthet. Az egyes csapatoknak képesnek kell lenniük a szolgáltatások gyors és megbízható kiadására anélkül, hogy megzavarná a többi csapatot, vagy az alkalmazás egészét destabilizálná.

Ez a cikk egy példa CI/CD-folyamatot mutat be a mikroszolgáltatások Azure Kubernetes Service-ben (AKS) való üzembe helyezéséhez. Minden csapat és projekt más, ezért ne vegye ezt a cikket kemény és gyors szabályok készleteként. Ehelyett a saját CI/CD-folyamat megtervezésének kiindulópontjaként szolgál.

A Kubernetes által üzemeltetett mikroszolgáltatások ci/CD-folyamatának céljai az alábbiak szerint foglalhatók össze:

  • A Teams egymástól függetlenül hozhatja létre és helyezheti üzembe szolgáltatásaikat.
  • A CI-folyamatot átadó kódmódosítások automatikusan üzembe lesznek helyezve egy éles környezetbe.
  • A minőségi kapuk a folyamat minden szakaszában érvényesítve vannak.
  • A szolgáltatás új verziója az előző verzió mellett helyezhető üzembe.

További háttér : CI/CD a mikroszolgáltatás-architektúrákhoz.

Feltételezések

A példa kedvéért íme néhány feltételezés a fejlesztői csapatról és a kódbázisról:

  • A kódtár egy monorepó, a mappákat mikroszolgáltatások rendezik.
  • A csapat elágaztatási stratégiája a törzsalapú fejlesztésen alapul.
  • A csapat kiadási ágakkal kezeli a kiadásokat. A rendszer külön kiadásokat hoz létre minden mikroszolgáltatáshoz.
  • A CI/CD-folyamat az Azure Pipelines használatával hozza létre, teszteli és üzembe helyezi a mikroszolgáltatásokat az AKS-ben.
  • Az egyes mikroszolgáltatások tárolórendszerképei az Azure Container Registryben vannak tárolva.
  • A csapat Helm-diagramokkal csomagolja be az egyes mikroszolgáltatásokat.
  • Leküldéses üzembehelyezési modellt használunk, ahol az Azure Pipelines és a társított ügynökök közvetlenül az AKS-fürthöz való csatlakozással hajtják végre az üzembe helyezéseket.

Ezek a feltételezések vezetik a CI/CD-folyamat számos konkrét részletét. Az itt ismertetett alapszintű megközelítés azonban más folyamatokhoz, eszközökhöz és szolgáltatásokhoz, például a Jenkinshez vagy a Docker Hubhoz igazítható.

Alternatívák

Az alábbi gyakori alternatívákat használhatják az ügyfelek az Azure Kubernetes Service-beli CI/CD-stratégia kiválasztásakor:

  • A Helm csomagkezelési és üzembehelyezési eszközként való használata helyett a Kustomize egy natív Kubernetes-konfigurációkezelő eszköz, amely sablonmentes módszert vezet be az alkalmazáskonfiguráció testreszabására és paraméterezésére.
  • Az Azure DevOps git-adattárakhoz és -folyamatokhoz való használata helyett a GitHub-adattárak használhatók privát és nyilvános Git-adattárakhoz, a GitHub Actions pedig CI/CD-folyamatokhoz.
  • Leküldéses üzemi modell használata helyett a Kubernetes-konfiguráció nagy méretekben történő kezelése a GitOps (lekéréses üzemi modell) használatával végezhető el, ahol a fürtön belüli Kubernetes-operátor a Git-adattárban tárolt konfiguráció alapján szinkronizálja a fürt állapotát.

Érvényesítési buildek

Tegyük fel, hogy egy fejlesztő egy kézbesítési szolgáltatás nevű mikroszolgáltatáson dolgozik. Új funkció fejlesztésekor a fejlesztő egy szolgáltatáságba ellenőrzi a kódot. Konvenció szerint a funkcióágak neve feature/*.

CI/CD workflow

A builddefiníciós fájl tartalmaz egy eseményindítót, amely az ág neve és a forrás elérési útja alapján szűr:

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/

Ezzel a megközelítéssel minden csapat saját buildfolyamattal rendelkezhet. Csak a /src/shipping/delivery mappába bejelentkezett kód aktiválja a kézbesítési szolgáltatás buildelését. A véglegesítések egy olyan ágba való leküldése, amely megfelel a szűrő eseményindítóinak, ci-buildet hoz létre. A munkafolyamat ezen pontján a CI-build minimális kódellenőrzést futtat:

  1. Hozza létre a kódot.
  2. Egységtesztek futtatása.

A cél az, hogy a buildelési idő rövid maradjon, hogy a fejlesztő gyors visszajelzést kapjon. Ha a funkció készen áll a főkiszolgálóra való egyesítésre, a fejlesztő megnyit egy pr-t. Ez a művelet egy másik CI-buildet aktivál, amely további ellenőrzéseket hajt végre:

  1. Hozza létre a kódot.
  2. Egységtesztek futtatása.
  3. Hozza létre a futtatókörnyezet tárolójának rendszerképét.
  4. Biztonságirés-vizsgálat futtatása a képen.

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

Megjegyzés:

Az Azure DevOps-adattárakban szabályzatokat határozhat meg az ágak védelmére. A szabályzathoz szükség lehet például egy sikeres CI-buildre, valamint egy jóváhagyótól való kijelentkezésre a főkiszolgálóra való egyesítéshez.

Teljes CI/CD-build

Egy bizonyos ponton a csapat készen áll a kézbesítési szolgáltatás új verziójának üzembe helyezésére. A kiadáskezelő létrehoz egy ágat a fő ágból az alábbi elnevezési mintával: release/<microservice name>/<semver>. For example, release/delivery/v1.0.2.

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

Ennek az ágnak a létrehozása egy teljes CI-buildet aktivál, amely az összes előző lépést futtatja, valamint:

  1. A tárolórendszerkép leküldése az Azure Container Registrybe. A rendszerkép az ág nevéből vett verziószámmal van megjelölve.
  2. Futtassa helm package a szolgáltatás Helm-diagramjának csomagolásához. A diagram verziószámmal is fel van címkézve.
  3. A Helm-csomag leküldése a Container Registrybe.

Feltételezve, hogy ez a build sikeres, üzembe helyezési (CD-) folyamatot indít el egy Azure Pipelines-kiadási folyamat használatával. Ez a folyamat a következő lépéseket tartalmazza:

  1. A Helm-diagram üzembe helyezése minőségbiztosítási környezetben.
  2. A jóváhagyó kijelentkezik, mielőtt a csomag éles környezetbe kerül. Lásd: Kiadástelepítési vezérlő jóváhagyásokkal.
  3. Adja vissza a Docker-rendszerképet az Azure Container Registry éles névteréhez. Ha például az aktuális címke, myrepo.azurecr.io/delivery:v1.0.2akkor az éles címke.myrepo.azurecr.io/prod/delivery:v1.0.2
  4. Helyezze üzembe a Helm-diagramot az éles környezetben.

Ezek a feladatok még monorepóban is alkalmazhatók az egyes mikroszolgáltatásokra, hogy a csapatok nagy sebességgel telepíthessenek. A folyamat néhány manuális lépéssel rendelkezik: A PRS-ek jóváhagyása, kiadási ágak létrehozása és az éles fürtben való üzembe helyezés jóváhagyása. Ezek a lépések manuálisak; a szervezet tetszése szerint automatizálhatók.

Környezetek elkülönítése

Több olyan környezettel fog rendelkezni, ahol szolgáltatásokat helyez üzembe, beleértve a fejlesztési, füsttesztelési, integrációs tesztelési, terheléstesztelési és végül éles környezeteket. Ezeknek a környezeteknek bizonyos szintű elkülönítésre van szükségük. A Kubernetesben választhat a fizikai elkülönítés és a logikai elkülönítés között. A fizikai elkülönítés azt jelenti, hogy a fürtök külön-külön lesznek üzembe helyezve. A logikai elkülönítés névtereket és szabályzatokat használ a korábban leírtak szerint.

Javasoljuk, hogy hozzon létre egy dedikált éles fürtöt és egy külön fürtöt a fejlesztői/tesztelési környezetekhez. A logikai elkülönítés használatával elkülönítheti a környezeteket a fejlesztői/tesztelési fürtben. A fejlesztői/tesztelési fürtben üzembe helyezett szolgáltatásoknak soha nem szabad hozzáférniük az üzleti adatokat tároló adattárakhoz.

Létrehozási folyamat

Ha lehetséges, csomagolja be a buildelési folyamatot egy Docker-tárolóba. Ez a konfiguráció lehetővé teszi, hogy kódösszetevőket hozzon létre a Docker használatával, és ne konfiguráljon buildkörnyezetet az egyes buildelési gépeken. A tárolóalapú buildelési folyamat megkönnyíti a CI-folyamat skálázását új buildügynökök hozzáadásával. Emellett a csapat bármely fejlesztője egyszerűen létrehozhatja a kódot a buildtároló futtatásával.

A Docker többfázisú buildjeinek használatával egyetlen Docker-fájlban határozhatja meg a buildkörnyezetet és a futtatókörnyezet rendszerképét. Íme például egy Dockerfile, amely egy .NET-alkalmazást hoz létre:

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"]

Ez a Dockerfile több buildszakaszt határoz meg. Figyelje meg, hogy az elnevezett base szakasz a .NET-futtatókörnyezetet használja, míg a megnevezett build szakasz a teljes .NET SDK-t használja. A build szakasz a .NET-projekt létrehozásához használható. A végső futtatókörnyezeti tároló azonban csak a futtatókörnyezetet basetartalmazza, és jelentősen kisebb, mint a teljes SDK-rendszerkép.

Tesztfuttató létrehozása

Egy másik jó gyakorlat az egységtesztek futtatása a tárolóban. Itt látható például egy Docker-fájl, amely egy tesztfuttatót hoz létre:

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"]

A fejlesztő ezt a Docker-fájlt használhatja a tesztek helyi futtatásához:

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

A CI-folyamatnak a buildellenőrzési lépés részeként is futtatnia kell a teszteket.

Vegye figyelembe, hogy ez a fájl a Docker ENTRYPOINT paranccsal futtatja a teszteket, nem pedig a Docker RUN parancsot.

  • Ha a RUN parancsot használja, a tesztek minden alkalommal lefutnak, amikor létrehozza a rendszerképet. A használatával ENTRYPOINTa tesztek be vannak jelentkezve. Ezek csak akkor futnak, ha kifejezetten a szakaszt testrunner célozza meg.
  • A sikertelen tesztek nem okozzák a Docker-parancs build meghiúsulását. Így megkülönböztetheti a tároló buildelési hibáit a tesztelési hibáktól.
  • A teszteredmények egy csatlakoztatott kötetre menthetők.

Ajánlott tárolókezelési eljárások

Íme néhány további ajánlott eljárás, amelyeket érdemes megfontolni a tárolók esetében:

  • A fürtön üzembe helyezett erőforrások (podok, szolgáltatások stb.) tárolócímkékre, verziószámozási és elnevezési konvenciókra vonatkozó szervezeti szintű konvenciók definiálása. Így könnyebben diagnosztizálhatók az üzembe helyezési problémák.

  • A fejlesztési és tesztelési ciklus során a CI/CD folyamat számos tárolólemezképet fog létrehozni. Ezek közül a képek közül csak néhány lesz kiadásra jelölt, és csak néhány ilyen kiadási jelölt lesz előléptetve az éles környezetbe. Egyértelmű verziószámozási stratégiával rendelkezik, hogy tudja, mely rendszerképek vannak jelenleg üzembe helyezve az éles környezetben, és szükség esetén segítsen az előző verzióra való visszaállításban.

  • Mindig helyezzen üzembe konkrét tárolóverziócímkéket, ne latest.

  • Az Azure Container Registry névtereinek használatával elkülönítheti az éles környezetben jóváhagyott rendszerképeket a még tesztelt rendszerképektől. Ne helyezze át a rendszerképet az éles névtérbe, amíg készen nem áll az éles környezetben való üzembe helyezésre. Ha ezt a gyakorlatot a tárolólemezképek szemantikai verziószámozásával kombinálja, azzal csökkentheti annak az esélyét, hogy véletlenül üzembe helyez egy olyan verziót, amelyet nem hagytak jóvá a kiadásra.

  • Kövesse a minimális jogosultság elvét úgy, hogy a tárolókat nem jogosult felhasználóként futtatja. A Kubernetesben létrehozhat egy podbiztonsági szabályzatot, amely megakadályozza, hogy a tárolók gyökérként fussanak.

Helm-diagramok

Fontolja meg a Helm használatát a szolgáltatások kiépítésének és üzembe helyezésének kezeléséhez. A Helm néhány olyan funkciója, amely segít a CI/CD használatában:

  • Gyakran egyetlen mikroszolgáltatást több Kubernetes-objektum határoz meg. A Helm lehetővé teszi, hogy ezek az objektumok egyetlen Helm-diagramba legyenek csomagolva.
  • A diagramok kubectl-parancsok sorozata helyett egyetlen Helm-paranccsal helyezhetők üzembe.
  • A diagramok kifejezetten verziószámozottak. A Helm használatával kiadhat egy verziót, megtekintheti a kiadásokat, és visszaállíthatja az előző verziót. Frissítések és változatok nyomon követése szemantikai verziókövetés használatával, valamint az előző verzióra való visszaállítás lehetősége.
  • A Helm-diagramok sablonokkal kerülik az információk, például címkék és választók sokszorosítását számos fájlban.
  • A Helm képes kezelni a diagramok közötti függőségeket.
  • A diagramok tárolhatók egy Helm-adattárban, például az Azure Container Registryben, és integrálhatók a buildelési folyamatba.

További információ a Container Registry Helm-adattárként való használatáról: Az Azure Container Registry használata Helm-adattárként az alkalmazásdiagramokhoz.

Egyetlen mikroszolgáltatás több Kubernetes-konfigurációs fájlt is tartalmazhat. A szolgáltatás frissítése azt jelentheti, hogy az összes fájlt megérinti a választók, címkék és képcímkék frissítéséhez. A Helm ezeket egyetlen, diagramnak nevezett csomagként kezeli, és lehetővé teszi a YAML-fájlok egyszerű frissítését változók használatával. A Helm egy (Go-sablonokon alapuló) sablonnyelvet használ a paraméteres YAML-konfigurációs fájlok írásához.

Például egy YAML-fájl egy olyan része, amely egy üzembe helyezést határoz meg:

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 }}

Láthatja, hogy az üzembehelyezési név, a címkék és a tároló specifikációi mind sablonparamétereket használnak, amelyek az üzembe helyezéskor vannak megadva. Például a parancssorból:

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

Bár a CI/CD-folyamat közvetlenül a Kubernetesbe is telepíthet diagramokat, javasoljuk, hogy hozzon létre egy diagramarchívumot (.tgz-fájlt), és helyezze el a diagramot egy Helm-adattárba, például az Azure Container Registrybe. További információ: Package Docker-alapú alkalmazások Helm-diagramokban az Azure Pipelinesban.

Változatok

A Helm-diagramok mindig rendelkeznek verziószámmal, amelynek szemantikai verziószámozást kell használnia. A diagramok is tartalmazhatnak appVersion. Ez a mező nem kötelező, és nem kell a diagramverzióhoz kapcsolódnia. Előfordulhat, hogy egyes csapatok külön szeretnének alkalmazásverziókat használni a diagramok frissítésétől. Egyszerűbb módszer azonban egy verziószám használata, így 1:1-es kapcsolat áll fenn a diagram és az alkalmazás verziója között. Így kiadásonként egy diagramot tárolhat, és egyszerűen üzembe helyezheti a kívánt kiadást:

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

Egy másik ajánlott eljárás a változás okának megjegyzése az üzembe helyezési sablonban:

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

Ezzel a paranccsal megtekintheti az egyes változatok változási ok mezőjét kubectl rollout history . Az előző példában a változás oka Helm-diagramparaméterként van megadva.

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

A parancs segítségével megtekintheti a helm list változatelőzményeket is:

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

Az Azure Pipelinesban a folyamatok buildfolyamatokra és kiadási folyamatokra vannak osztva. A buildelési folyamat futtatja a CI-folyamatot, és buildösszetevőket hoz létre. A Kubernetes mikroszolgáltatás-architektúrájához ezek az összetevők az egyes mikroszolgáltatásokat meghatározó tárolórendszerképek és Helm-diagramok. A kiadási folyamat azt a CD-folyamatot futtatja, amely mikroszolgáltatást helyez üzembe egy fürtben.

A jelen cikkben korábban ismertetett CI-folyamat alapján a buildelési folyamat a következő feladatokból állhat:

  1. Hozza létre a tesztfuttató tárolót.

    - task: Docker@1
      inputs:
        azureSubscriptionEndpoint: $(AzureSubscription)
        azureContainerRegistry: $(AzureContainerRegistry)
        arguments: '--pull --target testrunner'
        dockerFile: $(System.DefaultWorkingDirectory)/$(dockerFileName)
        imageName: '$(imageName)-test'
    
  2. Futtassa a teszteket a docker-futtatás meghívásával a tesztfuttató tárolón.

    - 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. Tegye közzé a teszteredményeket. Lásd: Kép készítése.

    - task: PublishTestResults@2
      inputs:
        testResultsFormat: 'VSTest'
        testResultsFiles: 'TestResults/*.trx'
        searchFolder: '$(System.DefaultWorkingDirectory)'
        publishRunAttachments: true
    
  4. Hozza létre a futtatókörnyezet-tárolót.

    - task: Docker@1
      inputs:
        azureSubscriptionEndpoint: $(AzureSubscription)
        azureContainerRegistry: $(AzureContainerRegistry)
        dockerFile: $(System.DefaultWorkingDirectory)/$(dockerFileName)
        includeLatestTag: false
        imageName: '$(imageName)'
    
  5. A tárolórendszerkép leküldése az Azure Container Registrybe (vagy más tárolóregisztrációs adatbázisba).

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

    - task: HelmDeploy@0
      inputs:
        command: package
        chartPath: $(chartPath)
        chartVersion: $(Build.SourceBranchName)
        arguments: '--app-version $(Build.SourceBranchName)'
    
  7. A Helm-csomag leküldése az Azure Container Registrybe (vagy más Helm-adattárba).

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

A CI-folyamat kimenete egy éles üzemre kész tárolórendszerkép és a mikroszolgáltatás frissített Helm-diagramja. Ezen a ponton a kiadási folyamat átveheti a műveletet. Minden mikroszolgáltatáshoz egyedi kiadási folyamat lesz. A kiadási folyamat úgy lesz konfigurálva, hogy egy triggerforrás legyen beállítva az összetevőt közzétevő CI-folyamathoz. Ez a folyamat lehetővé teszi az egyes mikroszolgáltatások független üzembe helyezését. A kiadási folyamat a következő lépéseket hajtja végre:

  • A Helm-diagram üzembe helyezése fejlesztői/minőségbiztosítási/előkészítési környezetekben. A Helm upgrade parancs a --install jelzővel használható az első telepítés és az azt követő frissítések támogatásához.
  • Várja meg, amíg a jóváhagyó jóváhagyja vagy elutasítja az üzembe helyezést.
  • A tároló lemezképének újbóli címkézése kiadásra
  • Küldje le a kiadási címkét a tárolóregisztrációs adatbázisba.
  • Helyezze üzembe a Helm-diagramot az éles fürtben.

A kiadási folyamat létrehozásával kapcsolatos további információkért lásd a kiadási folyamatokat, a kiadási tervezeteket és a kiadási beállításokat.

Az alábbi ábrán az ebben a cikkben ismertetett, végpontok közötti CI/CD-folyamat látható:

CD/CD pipeline

Közreműködők

Ezt a cikket a Microsoft tartja karban. Eredetileg a következő közreműködők írták.

Fő szerző:

A nem nyilvános LinkedIn-profilok megtekintéséhez jelentkezzen be a LinkedInbe.

További lépések