Creare una pipeline CI/CD per i microservizi su Kubernetes mediante Azure DevOps e Helm

La creazione di un processo di integrazione continua e recapito continuo (CI/CD) affidabile per un'architettura di microservizi può risultare complessa. Ogni team deve rilasciare i servizi in modo rapido e affidabile, senza interrompere altri team o destabilizzare l'applicazione nel suo complesso.

Questo articolo descrive una pipeline CI/CD di esempio per la distribuzione di microservizi in Servizio Azure Kubernetes (AKS). Ogni team e progetto è diverso, quindi non considerare questo articolo come un insieme di regole rigide. Usarlo invece come punto di partenza per progettare un processo CI/CD personalizzato.

L'elenco seguente riepiloga gli obiettivi di una pipeline CI/CD per i microservizi ospitati in Kubernetes:

  • Teams può creare e distribuire i propri servizi in modo indipendente.
  • Modifiche al codice che passano automaticamente il processo CI vengono distribuite in un ambiente simile a quello di produzione.
  • Ogni fase della pipeline applica controlli di qualità.
  • Una nuova versione di un servizio può essere distribuita side-by-side con la versione precedente.

Per altre informazioni, vedere CI/CD per le architetture di microservizi.

Presupposti

Per questo esempio, ecco alcuni presupposti relativi al team di sviluppo e alla codebase:

  • Il repository del codice è organizzato come un monorepo, con cartelle disposte per microservizio.
  • La strategia di ramificazione del team è basata sullo trunk-based development.
  • Il team usa i rami di rilascio per gestire le versioni. Vengono create versioni separate per ogni microservizio.
  • Il processo CI/CD usa Azure Pipelines per compilare, testare e distribuire i microservizi su AKS.
  • Le immagini del contenitore per tutti i microservizi vengono archiviate in un'unica istanza di Registro Azure Container condivisa, con un repository separato per ogni microservizio. Usare le autorizzazioni ABAC del repository di Azure Container Registry per limitare ogni identità della pipeline al proprio repository, oppure usare registri distinti quando sono richiesti confini di attendibilità più rigorosi.
  • Il team usa grafici Helm per creare un pacchetto di ogni microservizio.
  • Viene usato un modello di distribuzione push, in cui Azure Pipelines e gli agenti associati eseguono distribuzioni connettendosi direttamente al cluster del servizio Azure Kubernetes.

Questi presupposti determinano molti dei dettagli specifici della pipeline CI/CD. Tuttavia, è possibile adattare l'approccio di base descritto qui per altri processi, strumenti e servizi, ad esempio GitHub Actions, Jenkins o Docker Hub.

Le alternative

Quando scegli una strategia CI/CD con AKS, considera le seguenti alternative comuni:

  • Anziché usare Helm come strumento di gestione e distribuzione dei pacchetti, è possibile usare Kustomize, uno strumento di gestione della configurazione nativa di Kubernetes che introduce un modo senza modello per personalizzare e parametrizzare la configurazione dell'applicazione.

  • Anziché usare Azure DevOps per i repository Git e le pipeline, è possibile usare i repository GitHub per i repository Git privati e pubblici e GitHub Actions per le pipeline CI/CD.

    GitHub Actions offre l'integrazione con AKS con flussi di lavoro di base e supporta OpenID Connect (OIDC) per un'autenticazione sicura verso Azure senza l'uso di segreti.

  • Invece di usare un modello di distribuzione push, è consigliabile gestire la configurazione di Kubernetes su larga scala usando un gitOps (modello di distribuzione pull). Un operatore Kubernetes nel cluster, ad esempio Flux o Argo CD , sincronizza lo stato del cluster in base alla configurazione archiviata in un repository Git. GitOps elimina la necessità che le pipeline abbiano accesso diretto al cluster, riduce la superficie di attacco e offre funzionalità di autoripristino e di rilevamento della deriva.

    Tip

    Quando valuti i modelli di distribuzione basati su push o su pull (GitOps), considera i requisiti del carico di lavoro. Le distribuzioni basate su push offrono aggiornamenti deterministici e controllo diretto della pipeline, che si adatta alle procedure di distribuzione sicure. Le distribuzioni basate sul pull (GitOps) offrono coerenza, controllabilità e riparazione automatica, che li rende ideali per gli ambienti in cui i cluster devono riconciliarsi con uno stato desiderato senza l'accesso diretto da pipeline a cluster.

Compilazioni di convalida

Si supponga che uno sviluppatore stia lavorando a un microservizio denominato Servizio di distribuzione. Quando si sviluppa una nuova funzionalità, lo sviluppatore controlla il codice in un ramo di funzionalità. Per convenzione, i rami di funzionalità sono denominati feature/*.

Diagramma di un flusso di lavoro del ramo di funzionalità.

Il diagramma mostra due linee orizzontali dei branch Git e una pipeline di build sotto di esse. Nella parte superiore è presente il ramo principale, rappresentato come linea orizzontale. Il ramo feature/8150 si differenzia dal principale. Questo ramo ha tre punti posizionati su di esso, collettivamente etichettati commit. Da ognuno dei tre commit, una freccia punta verso il basso verso un riquadro nella parte inferiore del diagramma. La casella è denominata Pipeline di compilazione e contiene il nome della pipeline ci-delivery-validation. Tutte e tre le frecce tratteggiate convergeno in questa singola casella della pipeline di compilazione, a indicare che ogni commit nella funzionalità/8150 branch attiva un'esecuzione della pipeline di convalida della distribuzione ci.

Il file di definizione di compilazione include un trigger che filtra in base al nome del ramo e al percorso di origine:

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

Quando si usa questo approccio, ogni team può avere una propria pipeline di compilazione. Solo il codice sottoposto a check-in nella cartella /src/shipping/delivery attiva la compilazione di Delivery Service. Il push dei commit in un ramo che corrisponde al filtro attiva una compilazione CI. A questo punto nel flusso di lavoro, la compilazione CI esegue alcune verifiche minime del codice:

  1. Compilare il codice.
  2. Eseguire gli unit test.

L'obiettivo è mantenere brevi i tempi di compilazione in modo che lo sviluppatore possa ottenere feedback rapido. Quando la funzionalità è pronta per essere integrata nel branch main, lo sviluppatore apre una PR. Questa operazione attiva un'altra compilazione CI che esegue alcuni controlli aggiuntivi:

  1. Compilare il codice.
  2. Eseguire gli unit test.
  3. Eseguire test di sicurezza delle applicazioni statiche (SAST) nel codice sorgente.
  4. Creare l'immagine del contenitore di runtime.
  5. Eseguire analisi della vulnerabilità nell'immagine.

Diagramma che mostra

Il diagramma mostra due linee orizzontali dei rami Git e, sotto di esse, una pipeline di build. Nella parte superiore è presente il ramo principale, rappresentato come linea orizzontale. Sotto di esso, il ramo feature/8150 corre parallelamente e presenta tre puntini che rappresentano i commit. All’estremità destra del ramo feature/8150, una freccia tratteggiata collega un punto del ramo principale. Quel punto è contrassegnato con un altro punto etichettato PR, a indicare che è stata aperta una pull request verso main. Dal punto della PR nel branch principale, una freccia tratteggiata punta verso il basso a una casella denominata Build pipeline, che contiene il nome della pipeline ci-delivery-full. Questa riga illustra che l'apertura di una pull request dal branch di funzionalità verso main attiva la pipeline ci-delivery-full, che esegue la serie estesa di controlli CI.

Note

In Azure Repos, uno dei servizi in Azure DevOps, è possibile definire criteri per proteggere i rami. Ad esempio, il criterio potrebbe richiedere una build CI completata con successo e un'approvazione da parte di un approvatore prima di eseguire il merge nel ramo main.

Compilazione CI/CD completa

Quando il team è pronto per distribuire una nuova versione del servizio di distribuzione, il responsabile della versione crea un ramo dal ramo principale, usando questo modello di denominazione: release/<microservice name>/<semver>. Ad esempio: release/delivery/v1.0.2.

Diagramma che mostra un ramo di versione che attiva una pipeline di compilazione seguita da una pipeline di versione.

La creazione di questo ramo attiva una compilazione CI completa che esegue tutti i passaggi precedenti e questi passaggi:

  1. Carica l'immagine del contenitore in Container Registry. L'immagine è etichettata con il numero di versione nel nome del ramo.
  2. Eseguire helm package per creare il pacchetto del grafico Helm per il servizio. Il grafico viene anche contrassegnato con un numero di versione.
  3. Inviare il pacchetto Helm nel registro di container.

Se la compilazione ha esito positivo, attiva un processo di distribuzione (CD) usando una pipeline di versione Azure Pipelines. Questa pipeline contiene i passaggi seguenti:

  1. Distribuire il chart Helm in un ambiente QA.
  2. Un responsabile dà l'approvazione prima che il pacchetto venga spostato nell'ambiente di produzione. Vedere Release deployment control using approvals (Controllo della distribuzione della versione tramite approvazioni).
  3. Assegna nuovamente un tag all'immagine Docker per il namespace di produzione in Container Registry. Ad esempio, se il tag corrente è myrepo.azurecr.io/delivery:v1.0.2, il tag di produzione è myrepo.azurecr.io/prod/delivery:v1.0.2.
  4. Distribuire il chart Helm nell'ambiente di produzione.

Anche in un monorepo, definire l'ambito di queste attività in singoli microservizi in modo che i team possano distribuirli in modo indipendente. Il processo include alcuni passaggi manuali: l'approvazione delle PR, la creazione dei rami di rilascio e l'approvazione dei deployment nel cluster di produzione. I team del carico di lavoro possono automatizzare questi passaggi se vogliono.

Isolamento degli ambienti

I servizi vengono distribuiti in più ambienti, inclusi gli ambienti per lo sviluppo, i test di fumo, i test di integrazione, i test di carico e la produzione. Per questi ambienti è necessario un certo livello di isolamento. In Kubernetes è possibile scegliere tra isolamento fisico e isolamento logico. L'isolamento fisico si distribuisce su cluster distinti. L'isolamento logico si basa su namespace e policy.

È consigliabile creare un cluster di produzione dedicato insieme a un cluster separato per gli ambienti di sviluppo/test. Usare l'isolamento logico per separare gli ambienti all'interno del cluster di sviluppo/prova. I servizi distribuiti nel cluster di sviluppo/prova non avranno accesso agli archivi dati che contengono dati aziendali.

Per applicare l'isolamento all'interno di un cluster, seguire questa procedura:

Autenticazione e autorizzazione

Usare l'autenticazione senza segreti laddove possibile, sia per le pipeline che distribuiscono i microservizi che per i carichi di lavoro distribuiti da tali pipeline:

  • Federazione delle identità dei carichi di lavoro per le pipeline: per Azure Pipelines, usare una connessione al servizio di federazione delle identità dei carichi di lavoro per autenticarsi in Azure senza archiviare segreti di entità servizio a lungo termine. Per GitHub Actions, configurare OIDC per ottenere la stessa autenticazione senza segreto.
  • ID dei carichi di lavoro di Microsoft Entra per i carichi di lavoro distribuiti: configurare i microservizi distribuiti dalla pipeline per usare ID dei carichi di lavoro di Microsoft Entra anziché inserire credenziali tramite manifesti, valori Helm o segreti Kubernetes. L'ID del carico di lavoro esegue la federazione degli account del servizio Kubernetes con Microsoft Entra ID in modo che i pod possano eseguire l'autenticazione ai servizi Azure (ad esempio Azure Key Vault, Registro Contenitori o Azure SQL) senza che la pipeline gestisca segreti.

Gestione dei segreti

Non incorporare mai segreti (stringhe di connessione, chiavi API, password di database) direttamente nel codice sorgente, dockerfile, file di valori Helm o definizioni di pipeline. Invece:

Importante

Evitare di archiviare credenziali di lunga durata (segreti client, certificati o password) in variabili della pipeline, variabili di ambiente o segreti Kubernetes. Usa invece identità gestite e credenziali federate per ridurre l'onere della rotazione delle credenziali e la superficie di attacco.

Processo di costruzione

Quando possibile, creare un pacchetto del processo di compilazione in un contenitore Docker. Questa configurazione consente di compilare artefatti di codice usando Docker senza configurare un ambiente di compilazione in ogni computer di compilazione. Un processo di build containerizzato semplifica la scalabilità della pipeline di integrazione continua aggiungendo nuovi agenti di build. Inoltre, qualsiasi sviluppatore del team può compilare il codice eseguendo il contenitore di compilazione.

Usando compilazioni multistage in Docker, è possibile definire l'ambiente di compilazione e l'immagine di runtime in un singolo Dockerfile. Ad esempio, il Dockerfile seguente compila un'applicazione .NET 10:

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:10.0 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/build --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/publish

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

Questo Dockerfile definisce diverse fasi di compilazione. Si noti che la fase denominata base usa l'immagine di runtime .NET 10 ASP.NET, mentre la fase denominata build usa l'SDK completo .NET 10. La build fase compila il progetto .NET. Tuttavia, il contenitore di runtime finale viene compilato da base, che contiene solo il runtime ed è notevolmente inferiore all'immagine completa dell'SDK.

Importante

A partire da .NET 8, le immagini del contenitore .NET basate su Linux ufficiali includono un utente non radice denominato app. L'istruzione USER app nel Dockerfile esegue il contenitore come utente senza privilegi, seguendo il principio dei privilegi minimi. Le immagini container di ASP.NET Core hanno anch’esse cambiato la porta di ascolto predefinita da 80 a 8080.

Creazione di un test runner

Un'altra procedura consigliata consiste nell'eseguire unit test nel contenitore. Ad esempio, il codice seguente mostra parte di un Dockerfile che compila un runner di test:

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

Uno sviluppatore può usare questo Dockerfile per eseguire i test in locale:

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

La pipeline CI deve anche eseguire i test come parte del passaggio di verifica della compilazione.

Questo file usa il comando Docker ENTRYPOINT , non il comando Docker RUN , per eseguire i test.

  • Se si usa il RUN comando , i test vengono eseguiti ogni volta che si compila l'immagine. Se si utilizza ENTRYPOINT, i test vengono eseguiti solo se abilitati esplicitamente. Vengono eseguiti solo quando si fa riferimento in modo esplicito alla fase testrunner.
  • Un test non superato non causa l'esito negativo del comando Docker build . Questo comportamento consente di distinguere gli errori di compilazione del contenitore dagli errori di test.
  • I risultati dei test possono essere salvati in un volume montato.

Procedure consigliate per i contenitori

Ecco alcune altre procedure consigliate da considerare per i contenitori:

  • Definire convenzioni a livello di organizzazione per tag del contenitore, controllo delle versioni e convenzioni di denominazione per le risorse distribuite nel cluster, ad esempio pod e servizi. L'uso di queste convenzioni può semplificare la diagnosi dei problemi di distribuzione.
  • Durante il ciclo di sviluppo e test, il processo CI/CD compila molte immagini del contenitore. Solo alcune di queste immagini sono candidate per il rilascio e solo alcuni di questi candidati vengono promossi alla produzione. Disporre di una strategia di controllo delle versioni chiara in modo da sapere quali immagini sono attualmente distribuite nell'ambiente di produzione e possono eseguire facilmente il rollback a una versione precedente, se necessario.
  • Distribuire sempre tag di versione del contenitore specifici, non latest.
  • Usare i namespace in Container Registry per isolare le immagini approvate per la produzione da quelle ancora in fase di test. Non spostare un'immagine nello spazio dei nomi di produzione finché non si è pronti per distribuirla nell'ambiente di produzione. La combinazione di questa procedura con il controllo delle versioni semantiche delle immagini del contenitore può ridurre le probabilità di distribuire accidentalmente una versione non approvata per il rilascio.
  • Seguire il principio dei privilegi minimi eseguendo i contenitori come utente non privilegiato. In Kubernetes, usa Pod Security Standards con Pod Security admission (che ha sostituito le Pod Security Policies deprecate in Kubernetes 1.25) per imporre restrizioni, ad esempio impedendo di eseguire i container come utente root. Usare il profilo restricted per i carichi di lavoro di produzione.
  • Usare immagini di base minime o distroless (ad esempio, immagini basate su Alpine, immagini di base Azure Linux o immagini distroless, oppure immagini .NET chiseled) per ridurre la superficie di attacco delle immagini del container.
  • Per i registri Premium, configurare un criterio di conservazione del Registro Container per eliminare i manifesti senza tag. Per rimuovere i tag in base all'età o al nome, pianificare un'attività di Container Registry che esegua acr purge. Mantenere le immagini a cui fanno riferimento le distribuzioni attive e i piani di rollback.

Grafici Helm

È consigliabile usare Helm per gestire la costruzione e il deployment di servizi. Le funzionalità Helm seguenti supportano una pipeline CI/CD:

  • Un singolo microservizio viene spesso definito da più oggetti Kubernetes. Helm consente di creare un pacchetto di questi oggetti in un singolo grafico Helm.
  • È possibile distribuire un grafico usando un singolo comando Helm anziché una serie di comandi kubectl.
  • I grafici sono versionati esplicitamente. Usare Helm per rilasciare una versione, visualizzare le versioni ed eseguire il rollback a una versione precedente. Helm usa il controllo delle versioni semantiche per tenere traccia degli aggiornamenti e delle revisioni.
  • I chart Helm usano modelli per evitare la duplicazione di informazioni, ad esempio etichette e selettori, in molti file.
  • Helm può gestire le dipendenze tra i grafici.
  • È possibile archiviare i grafici in un repository Helm, ad esempio Registro Contenitori, e integrarli nella pipeline di compilazione.

Per altre informazioni, vedere Usare Registro Container come repository Helm per i grafici delle applicazioni.

Un singolo microservizio potrebbe richiedere più file di configurazione kubernetes. Per aggiornare un servizio, potrebbe essere necessario modificare tutti questi file per aggiornare selettori, etichette e tag di immagine. Helm considera questi file come un singolo pacchetto denominato grafico e semplifica l'aggiornamento dei file YAML usando le variabili. Helm usa un linguaggio modello (basato sui modelli Go) che consente di scrivere file di configurazione YAML con parametri.

Ad esempio, ecco una parte di un file YAML che definisce una distribuzione:

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

È possibile notare che il nome della distribuzione, le etichette e la specifica del contenitore usano tutti i parametri del modello, forniti in fase di distribuzione. Ad esempio, dalla riga di comando:

helm install <release-name> oci://<registry>/<repository>/<package-chart-name> --version <desiredVersion> \
     --set image.tag=0.1.0 \
     --set image.repository=package \
     --set dockerregistry=$ACR_SERVER \
     --namespace backend

Anche se una pipeline CI/CD può installare un grafico direttamente in Kubernetes, creare un archivio grafico (file con estensione tgz) ed eseguire il push del grafico in un repository Helm, ad esempio Registro Container. Per altre informazioni, vedere Creare un pacchetto e distribuire grafici Helm (attività HelmDeploy).

Revisions

I chart Helm hanno sempre un numero di versione che deve seguire il versionamento semantico. Un grafico può anche avere un oggetto appVersion. Questo campo è facoltativo e non deve essere correlato alla versione del grafico. Alcuni team potrebbero voler eseguire la versione delle applicazioni separatamente dagli aggiornamenti ai grafici. Un approccio più semplice consiste nell'usare un numero di versione, quindi esiste una relazione 1:1 tra la versione del grafico e la versione dell'applicazione. In questo modo, è possibile archiviare un grafico per versione e distribuire facilmente la versione desiderata:

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

Un'altra procedura consigliata consiste nel fornire un'annotazione della causa della modifica nel modello di distribuzione:

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

Questa annotazione consente di visualizzare il campo della causa delle modifiche per ogni revisione usando il kubectl rollout history comando . Nell'esempio precedente, la causa della modifica viene fornita come parametro del grafico Helm.

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

È anche possibile usare il helm list comando per visualizzare la cronologia delle revisioni:

helm list -n backend
NAME              NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
delivery-v0.1.0   backend     1           2024-04-07 00:25:30.000000 +0000 UTC    deployed    delivery-v0.1.0     v0.1.0

Azure Pipelines

Azure Pipelines, un servizio in Azure DevOps, ha due tipi di pipeline: pipeline di compilazione e pipeline di versione. La pipeline di compilazione esegue il processo di integrazione continua e crea artefatti di compilazione. Per un'architettura di microservizi in Kubernetes, questi artefatti sono le immagini del contenitore e i grafici Helm che definiscono ogni microservizio. La pipeline di rilascio esegue il processo di CD che distribuisce un microservizio in un cluster.

In base al flusso di integrazione continua descritto in precedenza in questo articolo, una pipeline di build può essere costituita dalle seguenti attività.

  1. Crea il contenitore del test runner utilizzando l'attività Docker.
  2. Eseguire i test richiamando docker run sul contenitore del test runner usando l'attività Docker.
  3. Pubblica i risultati del test usando l'attività PublishTestResults. Per altre informazioni, vedere Creare un'immagine.
  4. Eseguire SAST nel codice sorgente.
  5. Creare il contenitore di runtime usando docker build in locale e l'attività Docker oppure usando le compilazioni di Container Registry e l'attività AzureCLI. Generare una fattura software di materiali (SBOM) per l'immagine, ad esempio usando lo strumento SBOM Microsoft e pubblicarlo come artefatto della pipeline associato al digest dell'immagine o collegarlo all'immagine in Registro Contenitori.
  6. Eseguire l'analisi delle vulnerabilità delle immagini del contenitore (ad esempio, usando Microsoft Defender per contenitori o uno strumento non Microsoft come Trivy) per rilevare le vulnerabilità note prima della pubblicazione dell'immagine.
  7. Eseguire il push dell'immagine del contenitore nel Container Registry, o in un altro registro contenitori, tramite l'attività Docker o AzureCLI.
  8. Firmare l'immagine di cui è stato eseguito il push tramite digest non modificabile per garantire l'integrità e l'autenticità. Per Azure Pipelines, seguire le linee guida per la firma con Notation.
  9. Crea il pacchetto del chart Helm usando l'attività HelmDeploy.
  10. Eseguire il push del pacchetto Helm al Container Registry (o a un altro repository Helm) tramite l'attività HelmDeploy.

L'output della pipeline CI è un'immagine del contenitore pronta per la produzione e un grafico Helm aggiornato per il microservizio. A questo punto, la pipeline di rilascio può assumere il controllo. È disponibile una pipeline di versione univoca per ogni microservizio. La pipeline di rilascio è configurata per avere un'origine di attivazione impostata sulla pipeline CI che ha pubblicato l'artefatto. Questa pipeline consente di distribuire ogni microservizio in modo indipendente. Il flusso di rilascio esegue i seguenti passaggi:

  1. Distribuire il chart Helm negli ambienti di sviluppo/QA/staging. È possibile usare il helm upgrade comando con il --install flag per supportare la prima installazione e gli aggiornamenti successivi.
  2. Attendere che un approvatore esprima la sua approvazione o rifiuti la distribuzione.
  3. Riassegna il tag all'immagine del container per il rilascio.
  4. Pubblica il tag di rilascio nel registro dei contenitori.
  5. Distribuire il grafico Helm nel cluster di produzione. Usare Ratify con Criteri di Azure per convalidare le firme di immagine in fase di ammissione e configurare separatamente un criterio delle immagini consentite per limitare le immagini a registri attendibili.

Note

Per consentire ad AKS di estrarre immagini da Container Registry senza segreti separati per il pull delle immagini, usare l'integrazione tra AKS e Container Registry per un registro che usa RBAC a livello di registro. Per i registri abilitati per il controllo degli accessi basato sugli attributi (ABAC), questa integrazione non è supportata. Assegnare invece il ruolo Container Registry Repository Reader all'identità gestita da kubelet del cluster.

Per altre informazioni sulla creazione di una pipeline di versione, vedere Pipeline di versione, versioni bozza e opzioni di rilascio.

Il diagramma seguente illustra il processo CI/CD end-to-end descritto in questo articolo:

Diagramma della pipeline CI/CD completa.

Il diagramma mostra l'intera pipeline CI/CD, dal commit dello sviluppatore fino alla distribuzione in produzione. A sinistra inizia con uno sviluppatore che esegue il push di un commit in un repository Git. Il repository Git attiva la prima pipeline di integrazione continua. La pipeline CI contiene sei passaggi sequenziali: codice di compilazione, esecuzione di unit test, immagine di compilazione, immagine push, pacchetto Helm e grafico push. Ognuno dei primi tre passaggi ha una casella di output corrispondente a destra: il codice di compilazione produce artefatti di codice, l'esecuzione di unit test produce risultati di test e l'immagine di compilazione produce un'immagine del contenitore. Il passaggio Push image carica l'immagine nel Registro Contenitori. Il passaggio del pacchetto Helm genera un file di archivio grafico. La fase Push chart pubblica il chart in un repository Helm. Una seconda pipeline di integrazione continua si trova sotto la prima. Contiene cinque passaggi sequenziali: distribuzione in QA, test di integrazione, riassegnazione del tag all'immagine, pubblicazione dell'immagine e distribuzione in produzione. Dal passaggio Distribuzione in QA, una linea etichettata Helm upgrade conduce a un cluster Kubernetes etichettato test/QA cluster. A sinistra, sotto lo sviluppatore, parte una linea dall'icona dell'approvatore QA alla fase Distribuisci in produzione. Questa riga è contrassegnata come approvazione. Dalla fase Distribuzione in produzione, una linea denominata Helm upgrade conduce a una seconda icona del cluster Kubernetes etichettata cluster di produzione.

Alternativa a GitHub Actions

Se il team usa GitHub per il controllo del codice sorgente, GitHub Actions fornisce una piattaforma CI/CD equivalente. Oltre ai flussi di lavoro iniziali e all'autenticazione OIDC menzionati in precedenza, considerate queste funzionalità specifiche di GitHub quando la destinazione è AKS:

  • Ambienti e regole di protezione. Se il piano di GitHub e la visibilità del repository li supportano, usare gli ambienti GitHub con revisori, timer di attesa e rami di distribuzione necessari per implementare i controlli di approvazione.
  • Scansione dei container. Usa le azioni del marketplace di GitHub Actions per Trivy, Microsoft Defender per DevOps o strumenti simili per la scansione delle immagini dei contenitori direttamente nel tuo flusso di lavoro.

Osservabilità e monitoraggio

Implementare l'osservabilità nell'intera pipeline CI/CD e nell'ambiente di runtime:

  • Monitoraggio della pipeline. Tenere traccia delle durate di compilazione, dei test superati, della frequenza di distribuzione e delle percentuali di errore. Azure DevOps offre analisi predefinite. GitHub Actions possono usare dashboard di terze parti.
  • Monitoraggio del runtime. Usa il servizio gestito di Monitoraggio di Azure per Prometheus e Grafana con gestione Azure per monitorare lo stato di integrità del cluster AKS e le metriche del carico di lavoro.
  • Telemetria dell'applicazione. Instrumentare i microservizi con Monitoraggio di Azure Application Insights per la traccia distribuita, la registrazione delle richieste e il rilevamento delle dipendenze.
  • Creazione di avvisi. Configurare gli avvisi per gli errori di distribuzione, i riavvii dei pod, le percentuali di errore elevate e la saturazione delle risorse per abilitare la risposta rapida agli eventi imprevisti.

allineamento del framework Well-Architected

Quando progetti la pipeline CI/CD per i microservizi su Kubernetes, considera i pilastri dell'Azure Well-Architected Framework:

Pilastro Considerations
Affidabilità Strategie di rollback automatizzate, probe di integrità nelle distribuzioni, strategie di rilascio blu-verde o canary, budget di interruzione dei pod.
Security Autenticazione senza segreti (Workload ID, OIDC), firma delle immagini, sicurezza della catena di fornitura, RBAC a privilegi minimi, criteri di rete.
Ottimizzazione costi Dimensionamento corretto degli agenti di build, uso di runner autogestiti temporanei, implementazione di criteri di conservazione delle immagini di Container Registry e uso di pool di nodi spot solo per carichi di lavoro non di produzione tolleranti alle interruzioni.
Eccellenza operativa GitOps per distribuzioni dichiarative, Infrastructure as Code, Pipeline as Code (YAML), osservabilità e automazione dei runbook.
efficienza delle prestazioni Fasi della pipeline parallele, memorizzazione nella cache di compilazione (memorizzazione nella cache dei livelli Docker, memorizzazione nella cache delle dipendenze), scalabilità automatica orizzontale dei pod.

Contributori

Microsoft mantiene questo articolo. I seguenti collaboratori hanno scritto questo articolo.

Autore principale:

  • Ray Kao | Principal Solutions Engineer

Per visualizzare i profili LinkedIn non pubblici, accedere a LinkedIn.

Passaggi successivi