Das Erstellen eines zuverlässigen Continuous Integration und Continuous Delivery (CI/CD)-Prozesses für eine Microservicearchitektur kann schwierig sein. Einzelne Teams müssen in der Lage sein, Dienste schnell und zuverlässig zu veröffentlichen, ohne andere Teams zu stören oder die Stabilität der gesamten Anwendung zu gefährden.
Dieser Artikel beschreibt eine CI/CD-Beispielpipeline für das Bereitstellen von Microservices in Azure Kubernetes Service (AKS). Jedes Team und jedes Projekt ist anders, daher sollten Sie diesen Artikel nicht als feststehende Sammlung unverrückbarer Regeln verstehen. Er soll vielmehr einen Ausgangspunkt für Ihren Entwurf Ihres eigenen CI/CD-Prozesses bilden.
Die Ziele einer CI/CD-Pipeline für in Kubernetes gehostete Microservices lassen sich wie folgt zusammenfassen:
- Teams können ihre Dienste unabhängig voneinander entwickeln und bereitstellen.
- Codeänderungen, die den CI-Prozess durchlaufen, werden automatisch in einer produktionsähnlichen Umgebung bereitgestellt.
- In jeder Phase der Pipeline werden Quality Gates durchgesetzt.
- Eine neue Version eines Diensts kann parallel zur vorherigen Version bereitgestellt werden.
Hintergrundinformationen dazu finden Sie unter CI/CD für Microservicearchitekturen.
Annahmen
Für die Zwecke dieses Beispiels machen wir einige Annahmen über das Entwicklungsteam und die Codebasis:
- Für das Coderepository wird der Monorepo-Ansatz genutzt, und die Ordner sind nach Microservice organisiert.
- Die Branchstrategie des Teams basiert auf der Trunk-basierten Entwicklung.
- Das Team verwendet Releasebranches zur Verwaltung von Releases. Für jeden Microservice werden separate Releases erstellt.
- Der CI/CD-Prozess verwendet Azure Pipelines zum Erstellen, Testen und Bereitstellen der Microservices in AKS.
- Die Containerimages für die einzelnen Microservices sind in der Azure-Containerregistrierung gespeichert.
- Das Team verwendet Helm-Charts, um die Microservices zu verpacken.
- Ein Pushbereitstellungsmodell wird verwendet, bei dem Azure Pipelines und zugeordnete Agents Bereitstellungen ausführen, indem eine direkte Verbindung mit dem AKS-Cluster hergestellt wird.
Diese Annahmen bestimmen viele der spezifischen Details der CI/CD-Pipeline. Der hier beschriebene Grundansatz lässt sich jedoch für andere Prozesse, Tools und Dienste anpassen, wie etwa Jenkins oder Docker Hub.
Alternativen
Nachfolgend finden Sie allgemeine Alternativen, die Kunden bei der Auswahl einer CI/CD-Strategie mit Azure Kubernetes Service verwenden können:
- Als Alternative zur Verwendung von Helm als Paketverwaltungs- und Bereitstellungstool ist Kustomize ein systemeigenes Konfigurationsverwaltungstool von Kubernetes, das eine vorlagenfreie Methode zum Anpassen und Parametrisieren der Anwendungskonfiguration einführt.
- Als Alternative zur Verwendung von Azure DevOps für Git-Repositorys und -Pipelines können GitHub-Repositorys für private und öffentliche Git-Repositorys verwendet werden, und GitHub Actions können für CI/CD-Pipelines verwendet werden.
- Als Alternative zur Verwendung eines Pushbereitstellungsmodells kann die Verwaltung der Kubernetes-Konfiguration im großen Maßstab mithilfe von GitOps (Pull-Bereitstellungsmodell) erfolgen, bei dem ein In-Cluster Kubernetes-Operator den Clusterstatus synchronisiert, basierend auf der Konfiguration, die in einem Git-Repository gespeichert ist.
Validierungsbuilds
Nehmen wir an, ein Entwickler arbeitet an einem Microservice mit dem Namen „Delivery Service“ (Lieferdienst). Beim Entwickeln eines neuen Features checkt der Entwickler Code in einen Featurebranch ein. Für Featurebranches wird die Benennungskonvention feature/*
verwendet.
Die Builddefinitionsdatei enthält einen Trigger, der nach dem Branchnamen und dem Quellpfad filtert:
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/
Mit diesem Ansatz kann jedes Team über eine eigene Buildpipeline verfügen. Nur Code, der im Ordner /src/shipping/delivery
eingecheckt wird, löst einen Build des Lieferdiensts aus. Das Pushen von Commits auf einen Branch, der mit dem Filter übereinstimmt, löst einen CI-Build aus. An diesem Punkt des Workflows führt der CI-Build eine Codeüberprüfung mit minimalem Umfang durch:
- Erstellen des Codes.
- Ausführen von Komponententests.
Das Ziel besteht darin, die Buildzeiten kurz zu halten, damit der Entwickler schnell Feedback erhält. Wenn das Feature für die Zusammenführung mit dem Master bereit ist, öffnet der Entwickler einen PR-Vorgang. Durch diesen Vorgang wird ein weiterer CI-Build ausgelöst, bei dem einige zusätzliche Überprüfungen durchgeführt werden:
- Erstellen des Codes.
- Ausführen von Komponententests.
- Erstellen des Runtime-Containerimages.
- Durchführen von Überprüfungen auf Sicherheitsrisiken für das Image.
Hinweis
In Azure DevOps-Repos können Sie Richtlinien zum Schützen von Branches definieren. Für die Richtlinie sind beispielsweise ggf. ein erfolgreicher CI-Build sowie eine Genehmigung eines Prüfers erforderlich, damit die Zusammenführung mit dem Master erfolgen kann.
Vollständiger CI/CD-Build
An einem bestimmten Punkt ist das Team zum Bereitstellen einer neuen Version des Lieferdiensts bereit. Der Release Manager erstellt einen Branch vom Mainbranch und verwendet dazu das folgende Benennungsmuster: release/<microservice name>/<semver>
. Beispielsweise release/delivery/v1.0.2
.
Die Erstellung dieses Branches löst einen vollständigen CI-Build aus, für den alle der vorstehenden Schritte ausgeführt werden, plus:
- Pushübertragung des Containerimages in die Azure-Containerregistrierung Das Image wird mit der Versionsnummer aus dem Branchnamen versehen.
- Ausführen von
helm package
zum Verpacken des Helm-Charts für den Dienst Das Chart ist außerdem mit einer Versionsnummer gekennzeichnet. - Übertragen des Helm-Pakets an die Containerregistrierung per Push.
Wenn dieser Buildvorgang erfolgreich ist, wird mithilfe einer Releasepipeline von Azure Pipelines ein Bereitstellungsprozess (CD) ausgelöst. Diese Pipeline weist folgende Stufen auf:
- Bereitstellen des Helm-Charts in einer QA-Umgebung.
- Eine genehmigende Person meldet sich ab, bevor das Paket für die Produktion bereitgestellt wird. Weitere Informationen finden Sie unter Release deployment control using approvals (Steuerung von Releasebereitstellungen durch Genehmigungen).
- Versehen Sie das Docker-Image für den Produktionsnamespace in Azure Container Registry mit einem neuen Tag. Wenn das derzeitige Tag beispielsweise
myrepo.azurecr.io/delivery:v1.0.2
lautet, lautet das Tag für die Produktionmyrepo.azurecr.io/prod/delivery:v1.0.2
. - Stellen Sie das Helm-Chart in der Produktionsumgebung bereit.
Auch bei einem Monorepo (Einzelrepository) können diese Aufgaben einzelnen Microservices zugeordnet werden, damit die Teams Bereitstellungen schneller durchführen können. Der Prozess weist einige manuelle Schritte auf: Genehmigen von PRs, Erstellen von Releasebranches und Genehmigen von Bereitstellungen im Produktionscluster. Diese Schritte sind manuell. Sie können aber auch automatisiert werden, falls die Organisation dies vorzieht.
Isolation von Umgebungen
Sie verfügen über mehrere Umgebungen, in denen Sie Dienste bereitstellen, z. B. Entwicklung, Buildüberprüfungstests, Integrationstests, Auslastungstests und schließlich Produktion. Für diese Umgebungen ist ein gewisses Maß an Isolation erforderlich. In Kubernetes haben Sie die Wahl zwischen physischer Isolation und logischer Isolation. Physische Isolation bedeutet, dass die Bereitstellung in separaten Clustern erfolgt. Bei der logischen Isolation werden wie oben beschrieben Namespaces und Richtlinien verwendet.
Unsere Empfehlung lautet, einen dedizierten Produktionscluster mit einem zusätzlichen separaten Cluster für Ihre Entwicklungs- und Testumgebungen zu erstellen. Verwenden Sie die logische Isolation, um Umgebungen im Entwicklungs-/Testcluster zu trennen. Im Entwicklungs-/Testcluster bereitgestellte Dienste sollten niemals Zugriff auf Datenspeicher haben, in denen sich Geschäftsdaten befinden.
Buildprozess
Verpacken Sie nach Möglichkeit Ihren Buildprozess in einem Docker-Container. Mit dieser Konfiguration können Sie Codeartefakte mithilfe von Docker erstellen und ohne die Buildumgebung auf jedem Buildcomputer konfigurieren zu müssen. Ein Container-Buildprozess erleichtert das Aufskalieren der CI-Pipeline durch Hinzufügen neuer Build-Agents. Außerdem kann jeder Entwickler im Team den Code durch einfaches Ausführen des Buildcontainers erstellen.
Durch die Verwendung mehrstufiger Builds in Docker können Sie die Buildumgebung und das Laufzeitimage in einem einzelnen Dockerfile definieren. Dies ist beispielsweise ein Dockerfile, das eine .NET-Anwendung erstellt:
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"]
Dieses Dockerfile definiert mehrere Buildphasen. Beachten Sie, dass die Stage mit dem Namen base
die .NET-Runtime verwendet, während die Stage mit dem Namen build
das vollständige .NET SDK verwendet. Die build
-Stage wird verwendet, um das .NET-Projekt zu erstellen. Der endgültige Laufzeitcontainer wird jedoch aus base
erstellt, das nur die Runtime enthält und erheblich kleiner als das vollständige SDK-Image ist.
Erstellen eines Test Runners
Eine weitere bewährte Methode ist das Ausführen von Komponententests im Container. Dies ist beispielsweise ein Teil einer Docker-Datei, die einen Test Runner erstellt:
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"]
Ein Entwickler kann diese Docker-Datei zur lokalen Ausführung der Tests verwenden:
docker build . -t delivery-test:1 --target=testrunner
docker run delivery-test:1
Die CI-Pipeline sollte die Tests ebenfalls im Rahmen des Buildüberprüfungsschritts ausführen.
Beachten Sie, dass in dieser Datei der Docker-Befehl ENTRYPOINT
verwendet wird, um die Tests auszuführen, nicht der Docker-Befehl RUN
.
- Wenn Sie den Befehl
RUN
verwenden, werden die Tests jedes Mal ausgeführt, wenn Sie das Image erstellen. Durch Verwendung vonENTRYPOINT
sind die Tests optional aktivierbar. Sie werden nur ausgeführt, wenn Sie die Phasetestrunner
explizit ansteuern. - Ein Fehler im Test führt nicht zu einem Fehler beim Docker-Befehl
build
. Auf diese Weise können Sie Buildfehler des Containers von Testfehlern unterscheiden. - Testergebnisse können auf einem eingebundenen Volume gespeichert werden.
Bewährte Methoden für Container
Hier sind einige weitere bewährte Methoden, die beim Arbeiten mit Containern berücksichtigt werden sollten:
Definieren Sie organisationsweite Konventionen für Containertags und für die Versionsverwaltung sowie Namenskonventionen für im Cluster bereitgestellte Ressourcen (Pods, Dienste und Ähnliches). Dies kann die Diagnose von Bereitstellungsproblemen vereinfachen.
Im Rahmen des Entwicklungs- und Testzyklus erstellt der CI/CD-Prozess zahlreiche Containerimages. Nicht alle dieser Images kommen für die Veröffentlichung in Frage, und nur einige der so genannten Release Candidates werden in die Produktionsumgebung heraufgestuft. Entwickeln Sie eine klare Versionsverwaltungsstrategie, damit Sie wissen, welche Images derzeit in der Produktionsumgebung bereitgestellt sind, und bei Bedarf einen Rollback auf eine vorherige Version ausführen können.
Stellen Sie immer spezifische Containerversionstags bereit, nicht einfach
latest
.Verwenden Sie Namespaces in der Azure-Containerregistrierung, um Images, die bereits für die Produktion genehmigt wurden, von den noch in der Testphase befindlichen Images zu isolieren. Verschieben Sie ein Image nur dann in den Produktionsnamespace, wenn Sie bereit sind, es für die Produktion bereitzustellen. Wenn Sie diese Vorgehensweise mit der semantischen Versionsverwaltung von Containerimages kombinieren, verringert sich die Wahrscheinlichkeit, dass Sie versehentlich eine Version bereitstellen, die nicht für die Veröffentlichung freigegeben wurde.
Befolgen Sie das Prinzip der geringsten Rechte, indem Sie Container als Benutzer ohne besondere Rechte ausführen. In Kubernetes können Sie eine Pod-Sicherheitsrichtlinie erstellen, die die Ausführung von Containern als root verhindert.
Helm-Diagramme
Erwägen Sie die Verwendung von Helm zum Erstellen und Bereitstellen von Diensten. Dies sind einige der Features von Helm, die für CI/CD nützlich sind:
- Häufig wird ein einzelner Microservice durch mehrere Kubernetes-Objekte definiert. Helm ermöglicht das Verpacken dieser Objekte in einem einzelnen Helm-Chart.
- Ein Chart kann mit einem einzelnen Helm-Befehl statt einer Reihe von kubectl-Befehlen bereitgestellt werden.
- Charts enthalten eine explizite Versionsangabe. Verwenden Sie Helm, um eine Version zu veröffentlichen, Releases anzuzeigen und das Rollback zu einer früheren Version auszuführen. Nachverfolgen von Updates und Revisionen per semantischer Versionierung und möglicher Rollback auf eine vorherige Version
- Helm-Charts verwenden Vorlagen zur Vermeidung von doppelten Informationen, z.B. Bezeichnungen und Selektoren, über viele Dateien hinweg.
- Helm kann Abhängigkeiten zwischen Charts verwalten.
- Charts können in einem Helm-Repository gespeichert werden, beispielsweise in der Azure-Containerregistrierung, und in die Buildpipeline integriert werden.
Weitere Informationen zur Verwendung von Container Registry als Helm-Repository finden Sie unter Verwenden Sie Azure Container Registry als Helm-Repository für Ihre Anwendungsdiagramme.
Bei einem einzelnen Microservice können mehrere Kubernetes-Konfigurationsdateien im Spiel sein. Das Aktualisieren eines Diensts kann bedeuten, dass alle diese Dateien bearbeitet werden müssen, um Selektoren, Bezeichnungen und Imagetags zu aktualisieren. Helm behandelt diese als einzelnes Paket, das Chart genannt wird und es Ihnen ermöglicht, die YAML-Dateien mithilfe von Variablen komfortabel zu aktualisieren. Helm verwendet eine Vorlagensprache (die auf Go-Vorlagen beruht), um Ihnen das Schreiben von parametrisierten YAML-Konfigurationsdateien zu ermöglichen.
Dies ist beispielsweise ein Teil einer YAML-Datei, die eine Bereitstellung definiert:
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 }}
Sie können sehen, dass für den Bereitstellungsnamen, die Bezeichnungen und die Containerspezifikation sämtlich Vorlagenparameter verwendet werden, die zum Zeitpunkt der Bereitstellung zur Verfügung gestellt werden. Beispielsweise an der Befehlszeile:
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
Zwar könnte Ihre CI/CD-Pipeline ein Chart direkt in Kubernetes installieren, wir empfehlen jedoch, ein Chartarchiv (TGZ-Datei) zu erstellen und das Chart per Push in ein Helm-Repository zu übertragen, wie etwa die Azure-Containerregistrierung. Weitere Informationen finden Sie unter Package Docker-based apps in Helm charts in Azure Pipelines (Verpacken von Docker-basierten Apps in Helm-Charts in Azure Pipelines).
Revisionen
Helm-Charts weisen immer eine Versionsnummer auf, die semantische Versionierung befolgen muss. Ein Chart kann außerdem eine appVersion
aufweisen. Dieses Feld ist optional und muss nicht auf die Chartversion bezogen sein. Für manche Teams kann es sinnvoll sein, die Version von Anwendungen separat von Chartaktualisierungen zu verwalten. Es ist jedoch einfacher, nur eine Versionsnummer zu verwenden, so dass eine 1:1-Beziehung zwischen der Chartversion und der Anwendungsversion besteht. Auf diese Weise können Sie ein Chart pro Release speichern und das gewünschte Release komfortabel bereitstellen:
helm install <package-chart-name> --version <desiredVersion>
Eine weitere bewährte Methode besteht im Angeben einer Anmerkung für den Änderungsgrund in der Bereitstellungsvorlage:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "delivery.fullname" . | replace "." "" }}
labels:
...
annotations:
kubernetes.io/change-cause: {{ .Values.reason }}
Auf diese Weise können Sie mithilfe des Befehls kubectl rollout history
das Feld mit dem Änderungsgrund für jede Revision anzeigen. Im vorherigen Beispiel wird der Änderungsgrund als Helm-Chartparameter bereitgestellt.
kubectl rollout history deployments/delivery-v010 -n backend
deployment.extensions/delivery-v010
REVISION CHANGE-CAUSE
1 Initial deployment
Sie können aber auch den Befehl helm list
verwenden, um den Revisionsverlauf anzuzeigen:
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
In Azure Pipelines wird zwischen Buildpipelines und Releasepipelines unterschieden. Die Buildpipeline führt den CI-Prozess aus und erstellt Buildartefakte. Für eine Microservicearchitektur in Kubernetes sind diese Artefakte die Containerimages und Helm-Charts, die jeden Microservice definieren. Die Releasepipeline führt den CD-Prozess aus, der einen Microservice in einem Cluster bereitstellt.
Aufbauend auf dem weiter oben in diesem Artikel beschriebenen CI-Flow, kann eine Buildpipeline aus den folgenden Aufgaben bestehen:
Erstellen des Test Runner-Containers.
- task: Docker@1 inputs: azureSubscriptionEndpoint: $(AzureSubscription) azureContainerRegistry: $(AzureContainerRegistry) arguments: '--pull --target testrunner' dockerFile: $(System.DefaultWorkingDirectory)/$(dockerFileName) imageName: '$(imageName)-test'
Ausführen der Tests durch Aufrufen der Docker-Ausführung für den Test Runner-Container.
- task: Docker@1 inputs: azureSubscriptionEndpoint: $(AzureSubscription) azureContainerRegistry: $(AzureContainerRegistry) command: 'run' containerName: testrunner volumes: '$(System.DefaultWorkingDirectory)/TestResults:/app/tests/TestResults' imageName: '$(imageName)-test' runInBackground: false
Veröffentlichen der Testergebnisse. Siehe Erstellen eines Images.
- task: PublishTestResults@2 inputs: testResultsFormat: 'VSTest' testResultsFiles: 'TestResults/*.trx' searchFolder: '$(System.DefaultWorkingDirectory)' publishRunAttachments: true
Erstellen Sie den Runtimecontainer.
- task: Docker@1 inputs: azureSubscriptionEndpoint: $(AzureSubscription) azureContainerRegistry: $(AzureContainerRegistry) dockerFile: $(System.DefaultWorkingDirectory)/$(dockerFileName) includeLatestTag: false imageName: '$(imageName)'
Übertragen Sie das Containerimage per Push in die Azure Container Registry (oder eine andere Containerregistrierung).
- task: Docker@1 inputs: azureSubscriptionEndpoint: $(AzureSubscription) azureContainerRegistry: $(AzureContainerRegistry) command: 'Push an image' imageName: '$(imageName)' includeSourceTags: false
Verpacken Sie das Helm-Chart.
- task: HelmDeploy@0 inputs: command: package chartPath: $(chartPath) chartVersion: $(Build.SourceBranchName) arguments: '--app-version $(Build.SourceBranchName)'
Übertragen Sie das Helm-Paket in die Azure-Containerregistrierung (oder ein anderes Helm-Repository).
task: AzureCLI@1 inputs: azureSubscription: $(AzureSubscription) scriptLocation: inlineScript inlineScript: | az acr helm push $(System.ArtifactsDirectory)/$(repositoryName)-$(Build.SourceBranchName).tgz --name $(AzureContainerRegistry);
Die Ausgabe der CI-Pipeline ist ein produktionsbereites Containerimage und ein aktualisiertes Helm-Chart für den Microservice. An diesem Punkt kann die Releasepipeline übernehmen. Für jeden Microservice gibt es eine eindeutige Releasepipeline. Die Releasepipeline wird so konfiguriert, dass eine Triggerquelle auf die CI-Pipeline festgelegt ist, die das Artefakt veröffentlicht hat. Mit dieser Pipeline können Sie unabhängige Bereitstellungen jedes Mikroservices haben. Die Releasepipeline führt die folgenden Schritte aus:
- Stellen Sie das Helm-Diagramm für Entwicklungs-/QA/Staging-Umgebungen bereit. Der Befehl
Helm upgrade
kann mit dem Flag--install
verwendet werden, um die erste Installation und nachfolgende Upgrades zu unterstützen. - Warten auf eine genehmigende Person, die die Bereitstellung genehmigt oder ablehnt.
- Zuordnen eines neuen Tags zum Containerimage für das Release
- Übertragen Sie das Releasetag per Push in die Containerregistrierung.
- Stellen Sie das Helm-Chart im Produktionscluster bereit.
Weitere Informationen zum Erstellen einer Releasepipeline finden Sie unter Release pipelines, draft releases, and release options (Releasepipelines, Entwurfsreleases und Releaseoptionen).
Im folgenden Diagramm ist der in diesem Artikel beschriebene End-to-End-CI/CD--Prozess dargestellt:
Beitragende
Dieser Artikel wird von Microsoft gepflegt. Er wurde ursprünglich von folgenden Mitwirkenden geschrieben:
Hauptautor:
- John Poole | Senior Cloud Solutions Architect
Melden Sie sich bei LinkedIn an, um nicht öffentliche LinkedIn-Profile anzuzeigen.
Nächste Schritte
- Übernehmen einer Git-Verzweigungsstrategie
- Was ist Azure Pipelines?
- Releasepipelines, Entwurfsversionen und Releaseoptionen
- Steuerung von Releasebereitstellungen durch Genehmigungen
- Einführung in Containerregistrierungen in Azure