Übung: Bereitstellen einer Lösung mit mehreren Containern in einem Kubernetes-Cluster

Abgeschlossen

Die Releasepipeline, die mit Ihrem Projekt bereitgestellt wird, dient dazu, die Lösung als Docker-Container zu erstellen und sie in Azure App Service bereitzustellen. Um die Bereitstellung mehrerer Container in einem Kubernetes-Cluster zu unterstützen, müssen Sie diese Pipeline ändern.

In dieser Lerneinheit lernen Sie Folgendes:

  • Aktualisieren der Pipeline so, dass sie bei einem Commit im Branch „main“ ausgelöst wird.
  • Definieren von Variablen, die innerhalb der Pipeline freigegeben werden sollen
  • Erstellen und Veröffentlichen von Docker-Images
  • Veröffentlichen von Kubernetes-Manifesten
  • Fügen Sie einen Task hinzu, um ein Image-Pullgeheimnis für die Verwendung zwischen Ihrer Kubernetes- und der Azure Container Registry-Instanz zu erstellen.
  • Bereitstellen aktualisierter Images in einem Kubernetes-Cluster

Aktualisieren der Pipeline zur Unterstützung von Triggern

  1. Melden Sie sich bei Ihrer Azure DevOps-Organisation an, und navigieren Sie dann zu Ihrem Projekt.

  2. Wählen Sie Pipelines und dann Ihre Pipeline aus.

  3. Wählen Sie Bearbeiten aus, um Ihre Datei azure-pipelines.yml zu bearbeiten.

    Andy: Das war die Buildphase, die wir für die vorherige Einzelcontainerlösung hatten. Ich wusste, dass sie nicht ordnungsgemäß ausgeführt wird, daher habe ich sie deaktiviert. Wir können beginnen, indem wir Trigger bei Commits im Branch main reaktivieren.

  4. Ersetzen Sie oben in der Datei die vorhandene Zeile trigger durch den folgenden Codeschnipsel. Dadurch wird jedes Mal eine Pipelineausführung ausgelöst, wenn ein Commit im Mainbranch erfolgt.

    trigger:
    - 'main'
    

Definieren von Variablen, auf die pipelineübergreifend zugegriffen werden kann

Andy: Wir müssen zwei Pipelinevariablen hinzufügen. Eine zum Angeben des Namens des Leaderboard-Repositorys, also leaderboard. Die andere für den Namen des Pullgeheimnisses des Images, das für die Freigabe zwischen AKS- und ACR-Instanzen während der Bereitstellung verwendet wird.

  1. Fügen Sie dem Abschnitt variables den folgenden hervorgehobenen Code hinzu.

    variables:
      buildConfiguration: 'Release'
      leaderboardRepository: 'leaderboard'
      webRepository: 'web'
      tag: '$(Build.BuildId)'
      imagePullSecret: 'secret'
    

Erstellen und Veröffentlichen des Docker-Images in Azure Container Registry

Andy: Wir haben bereits einen Task zum Erstellen der Web-App als Docker-Container, den wir in unserer Containerregistrierung veröffentlichen. Das Gleiche können wir mit einem zweiten Task für unser Leaderboard tun.

  1. Fügen Sie eine zweite Docker@2-Aufgabe hinzu, die den Leaderboardcontainer erstellt und veröffentlicht. Verwenden Sie dazu den folgenden hervorgehobenen Codeschnipsel. Fügen Sie diesen Task nach dem Task für den Webcontainer hinzu.

    - task: Docker@2
      displayName: 'Build and push the web image to container registry'
      inputs:
        command: buildAndPush
        buildContext: $(Build.Repository.LocalPath)
        repository: $(webRepository)
        dockerfile: '$(Build.SourcesDirectory)/Tailspin.SpaceGame.Web/Dockerfile'
        containerRegistry: 'Container Registry Connection'
        tags: |
          $(tag)
    
    - task: Docker@2
      displayName: 'Build and push the leaderboard image to container registry'
      inputs:
        command: buildAndPush
        buildContext: $(Build.Repository.LocalPath)
        repository: $(leaderboardRepository)
        dockerfile: '$(Build.SourcesDirectory)/Tailspin.SpaceGame.LeaderboardContainer/Dockerfile'
        containerRegistry: 'Container Registry Connection'
        tags: |
          $(tag)
    

Tipp

Achten Sie darauf, dass der Task, den Sie hier hinzufügen, die gleiche Einrückung verwendet wie der vorherige Task, da Leerzeichen in einer YAML-Datei wichtig sind.

Veröffentlichen des Kubernetes-Manifests

Andy: Ich bin der Meinung, dass wir mit der nächsten Phase beginnen können. Oder fehlt noch irgendwas?

Mara: Sie haben erwähnt, dass es im Quellprojekt einige Manifestdateien gab, die die Bereitstellung und die Dienste definieren, die Kubernetes bei der Bereitstellung benötigt. Wir sollten diese veröffentlichen, bevor wir diese Phase abschließen.

Andy: Müssen wir das? Sind sie nicht weiterhin auf dem lokalen Datenträger gespeichert?

Mara: Das wäre der Fall, wenn wir die Bereitstellungstasks in derselben Phase wie den Build hinzufügen würden. Da unsere Bereitstellungsaufgaben jedoch in einer eigenen Bereitstellungsphase ausgeführt werden, erfolgt die Ausführung in einer neuen Umgebung, möglicherweise sogar auf einem anderen Agenten. Wir sollten unbedingt alles veröffentlichen, was in dieser Phase erzeugt wird und was die andere Phase benötigt.

Andy: Das ist ein gutes Argument. Ist das leicht umzusetzen? Wir müssen lediglich sicherstellen, dass der Ordner manifests auf den neuen Agent kopiert wird.

Mara: Dafür ist der Task PublishBuildArtifacts@1 vorgesehen. Er wird so häufig verwendet, dass es sogar die Kurzform publish dafür gibt.

  1. Fügen Sie einen Task publish hinzu, mit dem der Ordner manifests für eine zukünftige Phase gespeichert wird, wie im folgenden Codeausschnitt gezeigt. Achten Sie darauf, dass die Einrückung dieses Tasks mit derjenigen des vorherigen Tasks übereinstimmt.

    - task: Docker@2
      displayName: 'Build and push the leaderboard image to container registry'
      inputs:
        command: buildAndPush
        buildContext: $(Build.Repository.LocalPath)
        repository: $(leaderboardRepository)
        dockerfile: '$(Build.SourcesDirectory)/Tailspin.SpaceGame.LeaderboardContainer/Dockerfile'
        containerRegistry: 'Container Registry Connection'
        tags: |
          $(tag)
    
    - publish: '$(Build.SourcesDirectory)/manifests'
      artifact: manifests
    

Ersetzen der Bereitstellungsphase

Mara: Ich werde unsere vorhandene Bereitstellungsphase durch eine Phase ersetzen, die einen Bereitstellungsauftrag verwendet. Ein Bereitstellungsauftrag ist eine besondere Art von Auftrag, mit dem wir unsere Bereitstellung der zuvor erstellten Azure DevOps-Umgebung zuordnen können. Dies erleichtert die Nachverfolgung des Bereitstellungsverlaufs und ist besonders nützlich, wenn unsere Lösungen komplexer werden.

  1. Entfernen Sie die vorhandene Bereitstellungsphase (alles nach der Erstellungsphase), und ersetzen Sie sie durch den folgenden Codeschnipsel. Notieren Sie sich die hervorgehobene Zeile, die die zu verwendende Bereitstellungsumgebung angibt.

    - stage: 'Deploy'
      displayName: 'Deploy the containers'
      dependsOn: Build
      jobs:
      - deployment: Deploy
        displayName: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: 'Dev'
        variables:
        - group: Release
        strategy:
          runOnce:
            deploy:
              steps:
    

    Mara: Der erste Schritt, den wir in der Bereitstellungsphase hinzufügen, besteht darin, die zuvor veröffentlichten Manifestartefakte mit dem Task DownloadBuildArtifacts@0 herunterzuladen.

    Andy: Lassen Sie mich raten, es gibt die Kurzform download für diesen Task?

    Mara: Genau. Richtig geraten! Wir können den Spezifizierer current verwenden, um anzugeben, dass das Artefakt aus der aktuellen Ausführung der Pipeline verwendet werden soll.

  2. Fügen Sie als ersten Schritt der Bereitstellungsphase die hervorgehobenen Codezeilen hinzu.

    - stage: 'Deploy'
      displayName: 'Deploy the containers'
      dependsOn: Build
      jobs:
      - deployment: Deploy
        displayName: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: 'spike.default'
        variables:
        - group: Release
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: manifests
    

    Andy: Nun müssen wir ein Image-Pullgeheimnis erstellen, das von unserer ACR- und AKS-Instanz gemeinsam genutzt wird. Wissen Sie, ob es dafür einen Task gibt, den wir verwenden können?

    Mara: Ich habe gerade danach gesucht. Und wir haben Glück. Der Task KubernetesManifest@0 unterstützt eine Aktion zum Erstellen des erforderlichen Geheimnisses.

Kubernetes-Manifestaufgabe

Der Kubernetes-Manifesttask ist darauf ausgelegt, alle für Kubernetes erforderlichen allgemeinen Bereitstellungsvorgänge zu verwalten. Er unterstützt mehrere Optionen vom Typ action, die von der Erstellung von Geheimnissen bis hin zur Bereitstellung von Images reichen. In diesem Fall wird die createSecret-Aktion zusammen mit den folgenden Parametern verwendet:

  • action gibt das Feature an, das ausgeführt werden soll. In diesem Fall wird mit createSecret das gemeinsam genutzte Geheimnis erstellt.
  • connectionType gibt den Typ der zu verwendenden Dienstverbindung an. Optionen: azureResourceManager oder kubernetesServiceConnection.
  • secretName gibt den Namen des zu erstellenden Geheimnisses an.
  • dockerRegistryEndpoint gibt den Namen der Azure Container Registry-Dienstverbindung an.
  • azureSubscriptionConnection gibt den Namen der ARM-Dienstverbindung an.
  • azureResourceGroup gibt den Namen Ihrer Ressourcengruppe an.
  • kubernetesCluster gibt den Namen Ihres AKS-Clusters an.
  • namespace gibt den Kubernetes-Namespace an, für den diese Aktion gilt.
  1. Fügen Sie den folgenden hervorgehobenen Codeschnipsel am Ende Ihrer Pipeline hinzu. Vergewissern Sie sich, dass sowohl der Name der Ressourcengruppe als auch der Name des Clusters mit den Namen übereinstimmen, die Sie zuvor erstellt haben. Achten Sie darauf, dass die Einrückung dieses Tasks mit derjenigen des Tasks Herunterladen übereinstimmt.

    - task: KubernetesManifest@1
      displayName: Create imagePullSecret
      inputs:
        action: createSecret
        connectionType: azureResourceManager
        secretName: $(imagePullSecret)
        dockerRegistryEndpoint: 'Container Registry Connection'
        azureSubscriptionConnection: 'Kubernetes Cluster Connection'
        azureResourceGroup: 'tailspin-space-game-rg'
        kubernetesCluster: 'tailspinspacegame-24591'
        namespace: 'default'
    

    Andy: Der letzte Schritt besteht im Auslösen der Bereitstellung unserer Images im Kubernetes-Cluster. Der Dokumentation zufolge können wir wohl denselben Task verwenden, jedoch mit einer anderen Aktion und anderen Parametern.

    • action gibt das Feature an, das ausgeführt werden soll. In diesem Fall deploy für die Bereitstellung im AKS-Cluster.
    • connectionType gibt den Typ der zu verwendenden Dienstverbindung an. Optionen: azureResourceManager oder kubernetesServiceConnection.
    • azureSubscriptionConnection gibt den Namen der ARM-Dienstverbindung an.
    • azureResourceGroup gibt den Namen Ihrer Ressourcengruppe an.
    • kubernetesCluster gibt den Namen Ihres AKS-Clusters an.
    • namespace gibt den Kubernetes-Namespace an, für den diese Aktion gilt.
    • imagePullSecrets gibt die Liste der Geheimnisse an, die mittels Pullvorgang aus der Containerregistrierung abgerufen werden müssen.
    • containers gibt die Liste der bereitzustellenden Containerimages an.
  2. Fügen Sie den folgenden hervorgehobenen Codeschnipsel am Ende der Pipeline hinzu. Vergewissern Sie sich, dass sowohl der Name der Ressourcengruppe als auch der Name des Clusters mit den Namen übereinstimmen, die Sie zuvor erstellt haben. Achten Sie darauf, dass die Einrückung dieses Tasks mit derjenigen des vorherigen Tasks übereinstimmt.

    - task: KubernetesManifest@1
      displayName: Deploy to Kubernetes cluster
      inputs:
        action: deploy
        connectionType: azureResourceManager
        azureSubscriptionConnection: 'Kubernetes Cluster Connection'
        azureResourceGroup: 'tailspin-space-game-rg'
        kubernetesCluster: 'tailspinspacegame-24591'
        namespace: 'default'
        manifests: |
          $(Pipeline.Workspace)/manifests/deployment.yml
          $(Pipeline.Workspace)/manifests/service.yml
        imagePullSecrets: |
          $(imagePullSecret)
        containers: |
          $(RegistryName)/$(webRepository):$(tag)
          $(RegistryName)/$(leaderboardRepository):$(tag)
    

Ausführen Ihrer Pipeline

  1. Wählen Sie rechts oben auf der Seite Speichern aus. Wählen Sie Speichern aus, um Ihre Commitnachricht zu bestätigen.

  2. Wählen Sie Ausführen aus, bestätigen Sie Ihren Branchnamen, und wählen Sie dann Ausführen aus, um eine Pipelineausführung auszulösen.

  3. Wählen Sie Pipelines und dann Ihre Pipeline aus, um die Protokolle anzuzeigen, während Ihre Pipeline ausgeführt wird.

  4. Nachdem die Pipelineausführung abgeschlossen ist, wählen Sie im linken Bereich Umgebungen aus. Wählen Sie dann die Entwicklungsumgebung aus, um Ihre Bereitstellungsaufträge anzuzeigen.

  5. Sehen Sie sich nun unsere bereitgestellte Web-App und den API-Endpunkt an. Dazu müssen wir die externen IP-Adressen für die Web- und Leaderboard-Dienste abrufen.

  6. Navigieren Sie zum Azure-Portal, wählen Sie Ihren AKS-Cluster und dann Dienste und eingehende Elemente aus.

    Screenshot of how to find the external IPs for your web and leaderboard services.

  7. Wählen Sie die Externe IP-Adresse für Ihren Dienst Web aus, um Ihre Website in AKS anzuzeigen.

    Screenshot of the Space Game web site.

  8. Kehren Sie zu Ihrem Azure-Portalfenster an die Stelle zurück, an der Sie aufgehört haben, und kopieren Sie dann die Externe IP-Adresse des Diensts Leaderboard. Unter dieser IP-Adresse wird die Leaderboard-API öffentlich gehostet.

  9. Ersetzen Sie den Platzhalter im folgenden Link durch die externe IP-Adresse, die Sie kopiert haben. Sie können auch den Abfrageparameter pageSize=10 hinzufügen, um das Anzeigen der JSON-Antwort in Ihrem Browser zu vereinfachen. Verwenden Sie eine URL wie die folgende auf einer neuen Browserregisterkarte.

    http://[IP]/api/Leaderboard?pageSize=10
    
  10. Sie können die unformatierte JSON-Antwort von der in Ihrem AKS-Cluster gehosteten Leaderboard-API anzeigen. Sie verfügen jetzt über eine REST-API, die Sie von anderen Anwendungen aufrufen können.

    Screenshot of a web browser showing the JSON response from the leaderboard service.

Andy: Das hat super geklappt! Ich bin der Meinung, dass die Verwendung von Kubernetes eine hervorragende Möglichkeit für uns ist, eine umfassendere Microservicestrategie einzuführen.