16 Min. Lesezeit

Lernziele

Am Ende dieses Moduls werden Sie in der Lage sein:

  • Einen GitHub Actions-Workflow erstellen, der einen Container baut, ihn in die IONOS CLOUD Container Registry hochlädt und bei jedem Push auf `main` in Managed Kubernetes bereitstellt
  • Eine äquivalente GitLab CI-Pipeline mit IONOS CLOUD-spezifischen Build-, Push- und Deploy-Stufen konfigurieren
  • Terraform in CI/CD mit `plan` bei Pull Requests und `apply` bei Merge ausführen und dabei `IONOS_TOKEN` sowie andere Secrets sicher verwalten
  • Bereitstellungsstrategien und Rollbacks mit `kubectl rollout` und Terraform State Recovery implementieren
  • Wiederverwendbare Terraform-Module aus der TaskBoard-Infrastruktur extrahieren, um eine Team-Modulbibliothek aufzubauen

Einheit 3.3: CI/CD-Pipelines für IONOS CLOUD

Einführung

Sie haben TaskBoard containerisiert, die Images in die IONOS CLOUD Container Registry hochgeladen und manuell in Managed Kubernetes bereitgestellt. Das Ausführen von docker push und kubectl apply vom Laptop aus skaliert nicht auf ein Team und übersteht auch nicht den Moment, in dem Sie vergessen, welches Image-Tag in der Produktion läuft. In dieser Einheit verdrahten Sie den gesamten Ablauf so, dass git push der einzige manuelle Schritt ist. Ein Commit löst einen Build aus, das Image landet in der Container Registry mit dem Git-SHA als Tag, und das neue Tag wird im Cluster ausgerollt.

Sie unterwerfen auch die Infrastruktur derselben Disziplin. Terraform plan wird bei jedem Pull Request ausgeführt, damit Reviewer den Diff sehen, bevor sich etwas ändert, und apply wird nur nach dem Merge ausgeführt. Zwei IONOS CLOUD-Einschränkungen prägen jede Pipeline, die Sie hier schreiben: Die API ist asynchron, daher müssen Deploys auf die Bereitschaft warten, statt sie vorauszusetzen. Und die Authentifizierung der Container Registry erfolgt ausschließlich über tokenbasiertes docker login, ohne RBAC und ohne teamweise Repositories, sodass die Zugangsdaten in CI-Secrets gespeichert werden.

1. Pipeline-Design für IONOS CLOUD

Eine CI/CD-Pipeline auf IONOS CLOUD gliedert sich in zwei getrennte Abläufe, die denselben Job nicht teilen sollten. Anwendungänderungen folgen build -> test -> push image -> deploy to Kubernetes. Infrastrukturänderungen folgen plan -> apply. Wenn beide vermischt werden, kann ein Tippfehler in einem Kubernetes-Manifest eine dringende Infrastrukturkorrektur blockieren, und eine langsame terraform apply verzögert jede Anwendungsbereitstellung.

Der Anwendungsablauf endet mit kubectl apply oder, genauer gesagt, mit einer kontrollierten Aktualisierung des Image-Tags für eine bestehende Deployment. Der Infrastrukturablauf endet mit terraform apply für Ihre IONOS CLOUD-Ressourcen. Beide Abläufe authentifizieren sich bei IONOS CLOUD, verwenden jedoch unterschiedliche Zugangsdaten: Der Anwendungsablauf benötigt ein Container Registry-Token und eine kubeconfig, während der Infrastrukturablauf ein IONOS_TOKEN-Bearer-Token für die Cloud API benötigt.

1.1 Images mit dem Git-SHA kennzeichnen

Stellen Sie niemals :latest bereit. Ein veränderliches Tag macht Rollbacks mehrdeutig und unterbricht die Verknüpfung zwischen einem laufenden Pod und dem Commit, der ihn erzeugt hat. Kennzeichnen Sie jedes Image mit dem unveränderlichen Git-SHA, damit die laufende Revision stets nachvollziehbar ist.

# Derive an immutable tag from the commit
REGISTRY="taskboard.cr.de-fra.ionos.com"
SHA=$(git rev-parse --short HEAD)
IMAGE="${REGISTRY}/taskboard-api:${SHA}"

docker build -t "${IMAGE}" ./api
docker push "${IMAGE}"

Der Registry-Hostname folgt dem Muster {registry-name}.cr.{location-with-dash}.ionos.com, beispielsweise tue1608es.cr.es-vit.ionos.com. Der Hostname wird erst zugewiesen, nachdem die Registry den Zustand „Running“ erreicht hat, und ist bis dahin leer. Daher muss eine Pipeline, die eine neue Registry bereitstellt, den Hostname aus der Terraform-Ausgabe lesen, anstatt ihn hart zu kodieren.

1.2 Trennung der Repositories für Anwendung und Infrastruktur

Bewahren Sie Terraform in einem Infrastruktur-Repository auf und die Kubernetes-Manifeste sowie den Anwendungscode in einem Anwendungs-Repository. Das Infrastruktur-Repository wird bei Merge angewendet; das Anwendungs-Repository baut und deployt bei Push. Diese Trennung hält den Auswirkungsbereich einer fehlerhaften Änderung klein und ermöglicht es, verschiedenen Teams unterschiedliche Zugriffsrechte zu erteilen.

taskboard-app/          # build, push, kubectl deploy
  api/Dockerfile
  k8s/deployment.yaml
  .github/workflows/deploy.yml
taskboard-infra/        # terraform plan/apply
  main.tf
  modules/
  .github/workflows/terraform.yml

2. GitHub Actions für IONOS CLOUD

Ein GitHub Actions Workflow für den Anwendungsfluss hat drei logische Stufen in einem einzelnen Job: Build und Test, docker login und push, dann Deployment auf Managed Kubernetes. Die IONOS CLOUD spezifischen Teile sind der Registry Login (tokenbasiert) und die Abholung der kubeconfig.

2.1 Speichern von IONOS CLOUD Secrets

Tokens gehören niemals in das Repository. Speichern Sie das Container Registry Token und die kubeconfig als Repository- oder Umgebungs-Secrets. Das Container Registry Token Passwort wird nur einmal bei der Erstellung angezeigt, daher sofort erfassen und in CI speichern. Ein Registry Token kann dauerhaft oder temporär mit einem expiryDate sein, und bei Ablauf wird das Token gelöscht und nicht deaktiviert, was bedeutet, dass ein abgelaufenes Token in CI den docker login vollständig scheitern lässt, anstatt stillschweigend zu degradieren.

Secret Name Inhalte Verwendet von
CR_USERNAME Container Registry Token Name docker login
CR_PASSWORD Container Registry Token Passwort (einmalig angezeigt) docker login
KUBECONFIG base64-kodierte kubeconfig aus Terraform Output kubectl
IONOS_TOKEN Cloud API Bearer Token Terraform / ionosctl

2.2 Der Deployment Workflow

# .github/workflows/deploy.yml
name: deploy-taskboard
on:
  push:
    branches: [main]

env:
  REGISTRY: taskboard.cr.de-fra.ionos.com
  IMAGE_NAME: taskboard-api

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set image tag
        run: echo "TAG=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV"

      - name: Run tests
        run: |
          cd api
          pip install -r requirements.txt
          pytest

      - name: Log in to IONOS CLOUD Container Registry
        run: echo "${{ secrets.CR_PASSWORD }}" | docker login "$REGISTRY" \
             -u "${{ secrets.CR_USERNAME }}" --password-stdin

      - name: Build and push image
        run: |
          docker build -t "$REGISTRY/$IMAGE_NAME:$TAG" ./api
          docker push "$REGISTRY/$IMAGE_NAME:$TAG"

      - name: Configure kubectl
        run: |
          mkdir -p "$HOME/.kube"
          echo "${{ secrets.KUBECONFIG }}" | base64 -d > "$HOME/.kube/config"

      - name: Deploy to Managed Kubernetes
        run: |
          kubectl set image deployment/taskboard-api \
            api="$REGISTRY/$IMAGE_NAME:$TAG"
          kubectl rollout status deployment/taskboard-api --timeout=180s

kubectl set image aktualisiert nur das Feld „image" im vorhandenen Deployment, was einen rollenden Update auslöst, ohne das gesamte Manifest erneut anzuwenden. Der Schritt kubectl rollout status blockiert, bis der Rollout abgeschlossen ist oder das Timeout ausgelöst wird. Dies ist der korrekte Weg, um ein fehlgeschlagenes Deployment als fehlgeschlagene Pipeline anzuzeigen. Die kubeconfig selbst stammt aus dem Managed Kubernetes-Cluster: Sie wird entweder aus den Cluster-Einstellungen heruntergeladen oder, in einer automatisierten Pipeline, aus der Terraform-Ausgabe gelesen (dies wird in Einheit 3.2 behandelt) und der base64-kodierte Wert wird als Secret KUBECONFIG gespeichert.

3. GitLab CI für IONOS CLOUD

GitLab CI drückt denselben Ablauf als diskrete Stufen in .gitlab-ci.yml aus. Die IONOS CLOUD-spezifischen Aspekte sind identisch: tokenbasiertes Docker-Login zum Registry und ein kubeconfig für den Cluster. GitLab stellt einen Docker-in-Docker-Dienst zum Erstellen von Images innerhalb der Pipeline bereit.

3.1 Pipeline-Stufen

# .gitlab-ci.yml
stages: [test, build, deploy]

variables:
  REGISTRY: taskboard.cr.de-fra.ionos.com
  IMAGE_NAME: taskboard-api

test:
  stage: test
  image: python:3.12
  script:
    - cd api && pip install -r requirements.txt && pytest

build:
  stage: build
  image: docker:24
  services: [docker:24-dind]
  script:
    - export TAG=$CI_COMMIT_SHORT_SHA
    - echo "$CR_PASSWORD" | docker login "$REGISTRY" -u "$CR_USERNAME" --password-stdin
    - docker build -t "$REGISTRY/$IMAGE_NAME:$TAG" ./api
    - docker push "$REGISTRY/$IMAGE_NAME:$TAG"

deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - echo "$KUBECONFIG_B64" | base64 -d > /tmp/kubeconfig
    - export KUBECONFIG=/tmp/kubeconfig
    - kubectl set image deployment/taskboard-api api="$REGISTRY/$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
    - kubectl rollout status deployment/taskboard-api --timeout=180s
  only: [main]

Speichern Sie CR_USERNAME, CR_PASSWORD und KUBECONFIG_B64 als maskierte, geschützte CI/CD-Variablen in den GitLab-Projekteinstellungen. Geschützte Variablen werden nur Pipelines zur Verfügung gestellt, die auf geschützten Branches ausgeführt werden. Dadurch werden Produktionszugangsdaten aus Feature-Branch-Pipelines ferngehalten. CI_COMMIT_SHORT_SHA ist das GitLab-Äquivalent zum git-SHA-Tag und bietet dieselbe Garantie für ein unveränderliches Tag wie im GitHub Actions-Beispiel.

4. Terraform in CI/CD

Änderungen an der Infrastruktur verdienen eine Überprüfung, bevor sie IONOS CLOUD-Ressourcen betreffen, da terraform apply abrechenbare Ressourcen erstellt und diese auch zerstören kann. Das Standardmuster führt terraform plan bei jedem Pull Request aus und postet den Plan als PR-Kommentar. Anschließend wird terraform apply erst nach dem Merge auf main ausgeführt. So erhalten die Reviewer die genaue Differenz, und niemand kann ungeprüfte Änderungen anwenden.

4.1 Plan bei PR, Apply bei Merge

# .github/workflows/terraform.yml
name: terraform
on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

env:
  IONOS_TOKEN: ${{ secrets.IONOS_TOKEN }}

jobs:
  plan:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform plan -no-color -out=tfplan
      - run: terraform show -no-color tfplan > plan.txt
      - uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const plan = fs.readFileSync('plan.txt', 'utf8');
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '```\n' + plan.slice(0, 60000) + '\n```'
            });

  apply:
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform apply -auto-approve

Der IONOS CLOUD Terraform Provider authentifiziert sich über die Umgebungsvariable IONOS_TOKEN, sodass das Übergeben des Bearer-Tokens als Umgebungsvariable alles ist, was der Provider-Block benötigt. Der Provider fragt die asynchronen Operationen von IONOS CLOUD intern ab, sodass terraform apply blockiert, bis jede Ressource ihren bereitgestellten Zustand erreicht hat, bevor er fortfährt. Das bedeutet, dass die Pipeline keine eigenen Readiness-Loops für Terraform-verwaltete Ressourcen benötigt.

4.2 Remote State für CI/CD

Lokaler State funktioniert in CI/CD nicht, da jeder Runner mit einem sauberen Checkout startet. Verwenden Sie das S3-kompatible IONOS CLOUD Object Storage Backend, damit jeder Pipeline-Lauf denselben State liest und schreibt und State-Locking verhindert, dass zwei parallele Applies ihn beschädigen.

terraform {
  backend "s3" {
    bucket                      = "taskboard-tfstate"
    key                         = "infra/terraform.tfstate"
    region                      = "de"
    endpoints = { s3 = "https://s3-eu-central-1.ionoscloud.com" }
    skip_credentials_validation = true
    skip_region_validation      = true
    skip_requesting_account_id  = true
  }
}

Object Storage verwendet die Authentifizierung mit Access Key und Secret Key, nicht Bearer-Tokens, daher sind die Backend-Anmeldedaten von IONOS_TOKEN getrennt. Stellen Sie sie der Pipeline als Secrets AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY bereit, die das S3-Backend automatisch liest.

5. Deployment-Strategien und Rollback

Die Standard-Deployment-Strategie von Kubernetes ist RollingUpdate, die Pods schrittweise ersetzt, damit der Service während eines Deploys verfügbar bleibt. Für Workloads, die nicht zwei Versionen gleichzeitig ausführen können, verwenden Sie Recreate, die alle alten Pods beendet, bevor neue gestartet werden, was zu einer kurzen Unterbrechung führt.

5.1 Konfiguration der Strategie

apiVersion: apps/v1
kind: Deployment
metadata:
  name: taskboard-api
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels: { app: taskboard-api }
  template:
    metadata:
      labels: { app: taskboard-api }
    spec:
      imagePullSecrets:
        - name: cr-pull-secret
      containers:
        - name: api
          image: taskboard.cr.de-fra.ionos.com/taskboard-api:abc1234
          readinessProbe:
            httpGet: { path: /healthz, port: 8080 }
            initialDelaySeconds: 5

maxUnavailable: 0 stellt sicher, dass während des Rollouts keine Kapazität verloren geht, und readinessProbe stellt sicher, dass der Traffic nur Pods erreicht, die einen gesunden Status melden. Der Eintrag imagePullSecrets verweist auf das Token der Container Registry, da der Cluster Bilder mit denselben tokenbasierten Zugangsdaten abruft, die Ihre Pipeline zum Hochladen verwendet hat. Canary- und Blue-Green-Releases sind mit parallelen Deployments und Traffic Shifting möglich oder mit einem GitOps-Tool wie ArgoCD, das in Einheit 5.3 als Muster behandelt wird und nicht hier.

5.2 Zurückrollen

Wenn ein Deployment fehlschlägt, rollen Sie die Anwendung mit kubectl rollout undo zurück. Dieser Befehl stellt das Deployment auf seine vorherige Revision wieder her, ohne etwas neu zu bauen.

# Inspect revision history
kubectl rollout history deployment/taskboard-api

# Roll back to the immediately previous revision
kubectl rollout undo deployment/taskboard-api

# Roll back to a specific revision
kubectl rollout undo deployment/taskboard-api --to-revision=4

Da jedes Bild mit seinem git-SHA markiert ist, können Sie auch deterministisch mit kubectl set image auf ein bekanntes, einwandfreies Tag zurückrollen. Bei der Infrastruktur bedeutet Rollback, den fehlerhaften Commit zurückzusetzen und terraform apply erneut auszuführen, wodurch die aktiven Ressourcen in den committeden Zustand zurückversetzt werden. Falls der Zustand selbst beschädigt ist, stellen Sie ihn aus einer versionierten Kopie im Object Storage-Backend wieder her.

6. Aufbau einer Terraform-Modulbibliothek

Sobald die Infrastruktur von TaskBoard funktioniert, extrahieren Sie die wiederkehrenden Muster in Module, damit der nächste Dienst nicht bei Null beginnt. Ein Modul fasst verwandte Ressourcen hinter Eingabevariablen zusammen und stellt Ausgaben bereit, wodurch ein ausführlicher Stack in wenige Zeilen Aufrufcode umgewandelt wird.

6.1 Modulstruktur

# modules/k8s-service/variables.tf
variable "name"        { type = string }
variable "node_count"  { type = number, default = 2 }
variable "k8s_version" { type = string, default = "1.34" }

# modules/k8s-service/main.tf
resource "ionoscloud_k8s_cluster" "this" {
  name        = var.name
  k8s_version = var.k8s_version
}

resource "ionoscloud_k8s_node_pool" "this" {
  name        = "${var.name}-pool"
  k8s_cluster_id = ionoscloud_k8s_cluster.this.id
  node_count  = var.node_count
  # ... cores, ram, availability_zone, etc.
}

# modules/k8s-service/outputs.tf
output "cluster_id" { value = ionoscloud_k8s_cluster.this.id }

Die unterstützten Kubernetes-Versionen sind 1.34, 1.33, 1.32 und 1.31. Daher sollte eine bekannte, funktionierende Version in den Modulstandardwerten festgelegt und Aufrufenden ermöglicht werden, diese zu überschreiben. Node-Pools können Servertypen mit Dedicated Core oder vCPU nutzen. Ein Node-Pool hat ein hartes Maximum von 100 Nodes und ein empfohlenes Maximum von 20. Prüfen Sie daher node_count gegen diese Grenzen, anstatt einen Tippfehler zu tolerieren, der einen überdimensionierten Pool provisioniert.

6.2 Verwenden des Moduls

module "taskboard" {
  source     = "./modules/k8s-service"
  name       = "taskboard-prod"
  node_count = 3
}

output "taskboard_cluster" {
  value = module.taskboard.cluster_id
}

Versionieren Sie Ihr Modul-Repository mit Git-Tags und verweisen Sie auf ein bestimmtes Tag in source, damit eine nachgelagerte Änderung am Modul einen vorhandenen Stack nicht stillschweigend verändert. So verwandelt ein Team eine funktionierende Bereitstellung in eine wiederverwendbare Bibliothek.

Schnellreferenz für die API

Wichtige Endpunkte, die von CI/CD-Pipelines auf IONOS CLOUD verwendet werden:

Methode Endpunkt Beschreibung
POST /containerregistries/registries/{id}/tokens Erstellen eines Registry-Tokens für CI
GET /k8s/{clusterId}/kubeconfig Abrufen der kubeconfig für Deployment
GET /k8s/{clusterId}/nodepools Auflisten der Node-Pools eines Clusters
GET /requests/{requestId}/status Abfragen der asynchronen Operation bis DONE
DELETE /containerregistries/registries/{id}/repositories/{name} Löschen eines Repositories (Name URL-codiert)

Basis-URL: https://api.ionos.com/cloudapi/v6 Authentifizierung: Authorization: Bearer <token>

Code Lab

Ziel: Erstellen einer GitHub Actions Pipeline, die TaskBoard bei jedem Push auf main baut, hochlädt und auf Managed Kubernetes deployt.

Voraussetzungen:

  • IONOS CLOUD Konto mit API Token (IONOS_TOKEN)
  • Eine bestehende Container Registry und ein Managed Kubernetes Cluster (aus den Einheiten 3.1 und 3.2)
  • Ein GitHub Repository für die TaskBoard Anwendung
  • docker, kubectl und ionosctl lokal installiert

Schritt 1: Erstellen eines Registry Tokens für CI

ionosctl container-registry token create \
  --registry-id "$REGISTRY_ID" --name ci-deploy

Erwartete Ausgabe:

TokenId    Name        Status   ExpiryDate
a1b2c3d4   ci-deploy   enabled  -
Password: <shown once - copy it now>

Schritt 2: Secrets in GitHub speichern

gh secret set CR_USERNAME --body "ci-deploy"
gh secret set CR_PASSWORD --body "<password from step 1>"
gh secret set KUBECONFIG  --body "$(ionosctl k8s kubeconfig get \
  --cluster-id "$CLUSTER_ID" | base64 -w0)"

Erwartete Ausgabe:

✓ Set secret CR_USERNAME
✓ Set secret CR_PASSWORD
✓ Set secret KUBECONFIG

Schritt 3: Workflow-Datei hinzufügen Committe .github/workflows/deploy.yml aus Abschnitt 2.2 in das Repository. Erwartete Ausgabe:

[main 9f3c1ab] add deploy workflow
 1 file changed, 38 insertions(+)

Schritt 4: Pipeline auslösen

git commit --allow-empty -m "trigger deploy"
git push origin main

Erwartete Ausgabe:

To github.com:you/taskboard-app.git
   8d2e1f0..9f3c1ab  main -> main

Schritt 5: Ausführung beobachten

gh run watch

Erwartete Ausgabe:

✓ build-and-deploy succeeded
  ✓ Build and push image
  ✓ Deploy to Managed Kubernetes

Schritt 6: Rollout auf dem Cluster überprüfen

kubectl get deployment taskboard-api -o wide

Erwartete Ausgabe:

NAME            READY   IMAGE
taskboard-api   3/3     taskboard.cr.de-fra.ionos.com/taskboard-api:9f3c1ab

Prüfliste:

  • [ ] Das Image mit dem git-SHA-Tag existiert in der Container Registry
  • [ ] Das Deployment-Image entspricht dem gepushten Tag
  • [ ] kubectl rollout status meldete Erfolg in der Pipeline
  • [ ] Ein zweiter Push erzeugt ein neues SHA-Tag und ein sauberes Rolling Update

Aufräumarbeiten:

gh secret delete CR_USERNAME CR_PASSWORD KUBECONFIG
ionosctl container-registry token delete --registry-id "$REGISTRY_ID" --token-id "$TOKEN_ID"

Häufige Fehler

Fehler von Entwicklerinnen und Entwicklern, die bei der Nutzung von CI/CD auf IONOS CLOUD vermieden werden sollten:

  1. Das Registry-Hostname hartkodieren, bevor das Registry den Zustand „Running“ erreicht hat

    • Problem: Die Pipeline schlägt bei docker login mit einem DNS-Auflösungsfehler für einen leeren Hostnamen fehl.
    • Ursache: Der Registry-Hostname wird erst zugewiesen, nachdem das Registry den Zustand „Running“ erreicht hat. Ein neu bereitgestelltes Registry hat daher noch keinen Hostnamen.
    • Lösung: Den Hostnamen aus der Terraform-Ausgabe lesen, statt ihn hart zu kodieren, und den Push-Job daran koppeln, dass das Registry bereit ist:
    output "registry_hostname" { value = ionoscloud_container_registry.this.hostname }
    
  2. Erwartung, dass ein Kubernetes LoadBalancer Service ein echter externer Load Balancer ist

    • Problem: Die Durchsatzrate erreicht ein Plateau und die Quell-IP jeder Anfrage wird als clusterinterne Adresse angezeigt, wodurch Ratenbegrenzungen und Audit-Protokolle beeinträchtigt werden.
    • Ursache: Ein LoadBalancer Service auf Managed Kubernetes provisioniert keinen externen LB. IONOS CLOUD reserviert eine statische öffentliche IP und weist sie einem Worker-Node als sekundäre IP zu. kube-proxy NATet den Traffic zum Pod, wodurch der Durchsatz an der öffentlichen Obergrenze dieses einzelnen Nodes begrenzt wird und die Quell-IP verloren geht.
    • Lösung: Setzen Sie externalTrafficPolicy: Local, um die Quell-IP zu erhalten, und setzen Sie vor den Service einen separat provisionierten Managed ALB oder verteilen Sie den Traffic über mehrere LB-IPs, um den Durchsatz eines einzelnen Nodes zu überschreiten:
    spec:
      type: LoadBalancer
      externalTrafficPolicy: Local
    
  3. Ausführen von Terraform mit lokalem State in CI/CD

    • Problem: Jeder Pipeline-Lauf beginnt mit leerem State, daher versucht terraform apply, Ressourcen neu zu erstellen, die bereits existieren, und meldet Fehler bei doppelten Namen.
    • Ursache: CI-Runner checken einen sauberen Arbeitsbereich ohne State-Datei aus, und es ist kein gemeinsamer Backend konfiguriert.
    • Lösung: Konfigurieren Sie das S3-kompatible Object Storage-Backend, damit alle Läufe denselben State teilen, und stellen Sie Access Key und Secret Key als Pipeline-Secrets bereit:
    export AWS_ACCESS_KEY_ID="$IONOS_S3_KEY"
    export AWS_SECRET_ACCESS_KEY="$IONOS_S3_SECRET"
    terraform init
    

Zusammenfassung

Sie können den gesamten Build-Test-Deploy-Zyklus nun aus einer einzelnen git push steuern. Die Anwendungspipeline baut einen Container, kennzeichnet ihn mit dem git SHA, meldet sich mit einem tokenbasierten docker login bei der IONOS CLOUD Container Registry an, schiebt das Image hoch und rollt es mit einem readiness-gesteuerten kubectl set image und kubectl rollout status in Managed Kubernetes aus. Die Infrastrukturpipeline hält Terraform ehrlich, indem sie bei Pull Requests plant und erst bei Merge anwendet, gestützt durch einen gemeinsamen Zustand in Object Storage. Wenn etwas schiefgeht, bringen kubectl rollout undo und ein zurückgenommener Terraform-Commit Sie in einen bekannten, funktionierenden Zustand zurück, und Ihre extrahierte Modulbibliothek bedeutet, dass der nächste Dienst diese Muster wiederverwendet, statt sie neu zu erfinden.

Wichtige Punkte:

  • Trennen Sie den Anwendungsfluss (build -> test -> push -> deploy) vom Infrastrukturfluss (plan -> apply); teilen Sie niemals einen Job zwischen ihnen
  • Kennzeichnen Sie jedes Image mit dem unveränderlichen git SHA, niemals mit :latest, damit die laufende Revision immer nachverfolgbar ist und Rollbacks deterministisch sind
  • Container Registry Tokens werden einmalig bei der Erstellung angezeigt und bei Ablauf gelöscht; speichern Sie sie als CI-Geheimnisse und ziehen Sie Images mit denselben tokenbasierten Zugangsdaten
  • Führen Sie terraform plan bei PRs und terraform apply bei Merge aus, mit gemeinsamem S3-kompatiblem Zustand in Object Storage und IONOS_TOKEN als Geheimnis
  • Rollen Sie Anwendungen mit kubectl rollout undo zurück und Infrastruktur, indem Sie den Commit zurücknehmen und erneut anwenden

Wichtige Begriffe:

  • Unveränderliches Tag: Ein Container-Image-Tag, das aus dem git SHA abgeleitet wird und sich nie ändert, wodurch jeder laufende Pod mit dem exakten Commit verknüpft wird, der ihn gebaut hat.
  • Rolling Update: Die Standard-Kubernetes-Deployment-Strategie, die Pods inkrementell ersetzt, damit der Dienst während eines Deploys verfügbar bleibt.
  • Plan bei PR: Das Terraform-CI-Muster, bei dem terraform plan bei Pull Requests ausgeführt und der Diff zur Überprüfung gepostet wird, bevor ein apply erfolgt.
  • Remote State Backend: Ein gemeinsamer Terraform-Zustandspeicher (S3-kompatibles Object Storage auf IONOS CLOUD), der es jedem CI-Lauf ermöglicht, denselben Zustand mit Sperren zu lesen und zu schreiben.
  • imagePullSecret: Ein Kubernetes-Secret, das Container Registry Token-Zugangsdaten enthält, damit der Cluster private Images ziehen kann.

Nächste Schritte

Weiter lernen: Einheit 3.4: Wissensprüfung - Container und CI/CD

Verwandte Themen: