Zum Inhalt springen

CI/CD mit GitHub Actions

Der klassische Weg, aus der CI auf Kubernetes zu deployen: eine Admin-kubeconfig in ein Repository-Secret kopieren und hoffen, dass sie nie leakt. Dieses Credential ist cluster-admin, lebt jahrelang, wird in Forks und Artefakte kopiert – und lässt sich nicht widerrufen, ohne den Cluster neu zu schlüsseln.

PaaSbox ist für ein besseres Muster gebaut: Der API-Key ist das dauerhafte Secret; kubeconfigs sind Wegwerfware. Dein Workflow hält einen widerrufbaren API-Key, holt sich damit zu Beginn jedes Laufs eine kurzlebige Admin-kubeconfig – mit einer TTL, die zum Job passt –, deployt und lässt das Credential von selbst ablaufen.

Lege in der Console einen API-Key an (siehe Teams und API-Keys) – er wird einmalig angezeigt, sieht aus wie pbx_live_… und lässt sich jederzeit widerrufen. Für CI lohnt sich ein eigenes Machine-User-Konto, damit Pipeline-Aktionen im Aktivitätslog klar zuzuordnen sind.

Speichere ihn als Repository-Secret, z. B. PAASBOX_API_KEY (GitHub → Settings → Secrets and variables → Actions).

Ein vollständiger Deploy-Workflow – Credential holen, Manifeste anwenden, Rollout prüfen:

name: deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
env:
TEAM: my-team
CLUSTER: production
steps:
- uses: actions/checkout@v4
- name: Fetch a short-lived kubeconfig
run: |
curl -sf -X POST \
-H "Authorization: Token ${{ secrets.PAASBOX_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"ttlSeconds": 1800}' \
"https://console.paasbox.com/api/v1/teams/$TEAM/clusters/$CLUSTER/kubeconfig/" \
| jq -r .kubeconfig > "$RUNNER_TEMP/kubeconfig"
chmod 600 "$RUNNER_TEMP/kubeconfig"
echo "KUBECONFIG=$RUNNER_TEMP/kubeconfig" >> "$GITHUB_ENV"
- name: Deploy
run: kubectl apply -k deploy/overlays/production
- name: Wait for the rollout
run: kubectl -n myapp rollout status deploy/web --timeout=180s

Dreißig Minuten Gültigkeit (ttlSeconds: 1800) reichen für einen Deploy-Job locker; über das Feld expiresAt in der Antwort können längere Pipelines bei Bedarf mittendrin erneuern. Die API-Referenz dokumentiert den Endpoint.

Enthält dein Release einen unveränderlichen Migrations-Job – wie im Django-SaaS-Guide –, passt derselbe Löschen-dann-anwenden-Schritt zwischen Holen und Rollout:

- name: Run migrations
run: |
kubectl -n myapp delete job myapp-migrate --ignore-not-found
kubectl apply -f deploy/overlays/production/migrate-job.yaml
kubectl -n myapp wait --for=condition=complete job/myapp-migrate --timeout=300s

Es lohnt sich, explizit zu machen, was dir dieses Muster bringt:

  • Leaks laufen ab. Eine kubeconfig, die versehentlich in einem Log landet, in einem Artefakt gecacht wird oder auf einem Runner liegen bleibt, ist innerhalb einer Stunde wertlos – eine gespeicherte ist cluster-admin, bis es jemandem auffällt.
  • Widerrufen ist ein Klick – und trifft nicht deinen Cluster. Einen geleakten API-Key zu rotieren ist sofort erledigt, im Self-Service. Ein langlebiges Cluster-Credential zu rotieren heißt, den Cluster neu zu schlüsseln.
  • Jede Ausstellung wird protokolliert. Jeder Abruf landet im Aktivitätslog deines Teams – mit Akteur, Zeitpunkt und TTL. „Was hat um 02:00 Uhr deployt?“ hat eine Antwort.
  • Offboarding bleibt sauber. Person entfernen, ihre Keys widerrufen – nichts, was sie je exportiert hat, funktioniert über die TTL hinaus. Die ganze Geschichte steht in Zugriff auf deinen Cluster.
  • Lade die kubeconfig nie als Artefakt hoch und gib sie nie per cat in einem Step aus – sie ist kurzlebig, nicht öffentlich.
  • Bemiss die TTL am Job, nicht nach „sicherheitshalber mehr“. 30–60 Minuten decken fast jeden Deploy ab.
  • Ein Key pro Pipeline (Staging vs. Produktion, pro Repo), damit Widerrufe chirurgisch bleiben und der Audit-Trail lesbar ist.
  • Pinne Image-Tags (sha-…, nicht latest), damit die CI genau das deployt, was sie gebaut hat.

Dasselbe Muster funktioniert in jedem CI-System – GitLab CI, Forgejo Actions, Jenkins –, denn es ist nur curl und kubectl: Key halten, frisch holen, deployen, ablaufen lassen.