Text size
Ausprobiert & getestet7 Min. Lesezeit

Meine CI/CD-Pipeline, von der Verpflichtung bis zur Produktion

Bauen, testen, scannen, einsetzen, überprüfen. Eine komplette Pipeline, die Sie kopieren können.

My CI/CD pipeline, from commit to production
KI-generierte Illustration

Wenn Sie zehn DevOps-Ingenieure bitten, eine CI/CD-Pipeline zu zeichnen, erhalten Sie zehn verschiedene Zeichnungen. Aber unterhalb haben gute Rohrleitungen die gleiche Form. Sie geben schnell Feedback, erkennen Probleme frühzeitig und machen die Bereitstellung langweilig.

Hier ist die Pipeline, die ich für einen typischen containerisierten Web-Service benutzen würde, Schritt für Schritt, mit einem Arbeitsbeispiel in GitHub Actions.

Die Phasen und der Grund

  1. Lint- und Einheitstests. Zuerst schnell überprüfen. Wenn diese scheitern, gibt es keinen Sinn, sonst etwas zu tun.
  2. Bauen Sie. Erstellen Sie das Container-Image einmal, mit dem SHA-Commit-Tag.
  3. Scannen Sie. Überprüfen Sie Abhängigkeiten, das Bild und den Infrastrukturcode auf bekannte Probleme.
  4. Integrationstests. Testen Sie das gebaute Bild mit seinen realen Abhängigkeiten.
  5. Veröffentlichen. Schicken Sie das Bild ins Register, unterschrieben.
  6. Auf die Bühne. Automatisch bei jeder Überführung auf Main.
  7. Überprüfen Sie. Rauchprüfungen gegen Inszenierung.
  8. Einsatz in der Produktion. Das gleiche Artefakt, nach Genehmigung oder automatisch, mit allmählichem Einsatz.
  9. Überprüfen Sie nochmal. Beobachten Sie die Messwerte und kehren Sie zurück, wenn es schlimmer wird.

Das wichtigste Prinzip liegt im zweiten Schritt: Einmal bauen, überall das gleiche Artefakt einsetzen. Nie wieder für die Produktion. Was du getestet hast, ist das, was du verschiffst.

Eine gute Pipeline macht das Richtige automatisch und das Risiko sichtbar.

Das vollständige Beispiel

Eine verkleinerte Version von dem, wie das hier in GitHub Actions aussieht:

name: ci-cd

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read

env:
  IMAGE: ghcr.io/my-org/shop-api

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<sha> # v4
      - uses: actions/setup-go@<sha> # v5
        with:
          go-version-file: go.mod
          cache: true
      - run: go vet ./...
      - run: go test ./... -race -coverprofile=coverage.out

  build:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write          # for keyless signing
    outputs:
      digest: ${{ steps.push.outputs.digest }}
    steps:
      - uses: actions/checkout@<sha> # v4
      - uses: docker/setup-buildx-action@<sha> # v3
      - uses: docker/login-action@<sha> # v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - id: push
        uses: docker/build-push-action@<sha> # v6
        with:
          push: ${{ github.event_name == 'push' }}
          tags: ${{ env.IMAGE }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
      - name: Scan image
        uses: aquasecurity/trivy-action@<sha>
        with:
          image-ref: ${{ env.IMAGE }}:${{ github.sha }}
          severity: HIGH,CRITICAL
          ignore-unfixed: true
          exit-code: "1"

  deploy-staging:
    if: github.event_name == 'push'
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - run: echo "Update the staging GitOps repo to ${{ github.sha }}"
      - run: ./scripts/smoke-test.sh https://staging.example.com

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production      # requires approval in repo settings
    steps:
      - run: echo "Update the production GitOps repo to ${{ github.sha }}"

(Ersetzen <sha> mit festgegründeten commit-SHAs, wie in meinem Beitrag zum Sperren von GitHub-Aktionen beschrieben.)

Ein paar Details, die es wert sind, beachtet zu werden:

  • Umwelt (staging, production) können Genehmigungen verlangen und ihre eigenen Geheimnisse bewahren.
  • Bereitstellung aktualisiert ein GitOps-Repo Anstatt zu rufen kubectl - Ich bin direkt hier. Argo CD oder Flux wendet die Änderung an, die die Anmeldeinformationen von CI fernhält.
  • Pull-Anfragen laufen Tests und bauen Aber nicht drücken oder einsetzen.

Ich mache es schnell.

Langsame Pipelines machen die Entwickler vertrauenslos. Ein paar Gewohnheiten lassen die Dinge schnell laufen:

  • Erst die schnellsten Kontrollen . und parallel.
  • Cache-Abhängigkeiten und Docker-Ebenen (die cache-from / cache-to die oben stehenden Zeilen).
  • Nur das laufen lassen, was sich geändert hat. in Monorepos mit Pfadfiltern.
  • Konzentrieren Sie sich auf die Integrationstests. Testen Sie die wichtigen Pfade, nicht alles.
  • Ziel weniger als zehn Minuten Von "Push" zu "Ready to merge".

Wie ich zurückrollte

Ein Rollback sollte so einfach wie ein Einsatz sein und geübt werden:

  • Mit GitOps ist ein Rollback ein Rückkehrverpflichtung in der Bereitstellungsplattform. Argo CD und Flux wenden sie wie jede andere Änderung an.
  • Schrittweise Lieferung Tools wie Argo Rollouts oder Flagger können automatisch rückgängig gemacht werden, wenn die Kennzahlen schlechter werden.
  • Datenbankänderungen müssen rückwärtskompatibel sein (erweitern und kontrahieren), so dass das Zurückrollen der App das neue Schema nicht bricht.
  • Merkmale der Flagge Sie können eine kaputte Funktion ausschalten, ohne sie überhaupt neu zu verteilen.

Also, was ist das Minimum?

Wenn Ihre Pipeline nichts anderes tut, dann lassen Sie es dies tun: Führen Sie Tests an jeder Pull-Anfrage durch, erstellen Sie ein Bild pro Kommit, scannen Sie es, bereitstellen Sie genau dieses Bild automatisch zur Inszenierung und fördern Sie das gleiche Bild zur Produktion. Alles andere ist eine Verbesserung.

Meine Meinung: Bauen Sie einmal, testen Sie früh, setzen Sie überall dasselbe ein und wissen Sie immer, wie Sie zurückkehren.

Desly