π Was ist CI/CD?
π Definitionβ
CI/CD steht fΓΌr Continuous Integration (Kontinuierliche Integration) und Continuous Deployment (Kontinuierliches Deployment), eine Entwicklungsmethodik, die Code-Γnderungen automatisch testet und bereitstellt. CI erstellt und testet Code automatisch bei jeder ZusammenfΓΌhrung, wΓ€hrend CD getesteten Code automatisch in Produktionsumgebungen bereitstellt. Dies ermΓΆglicht eine schnellere Fehlererkennung und kΓΌrzere Bereitstellungszyklen.
π― Verstehen durch Analogienβ
Fabrikautomatisierungslinieβ
Traditionelle Entwicklung (Manuell)
Entwickler 1 β Code schreiben
Entwickler 2 β Code schreiben
Entwickler 3 β Code schreiben
β
Eine Woche spΓ€ter
β
Teamleiter fΓΌhrt manuell zusammen
β
Konflikte auftreten! π±
β
Manuelles Testen
β
Fehler gefunden! π±
β
Manuelles Deployment
β
Deployment fehlgeschlagen! π±
CI/CD (Automatisiert)
Entwickler 1 β Code pushen β Auto-Test β
β Auto-Deploy π
Entwickler 2 β Code pushen β Auto-Test β
β Auto-Deploy π
Entwickler 3 β Code pushen β Auto-Test β β Sofortige Benachrichtigung!
(Probleme sofort erkannt und behoben)
Essenslieferungβ
Manuelles Deployment = Direkte Lieferung
1. Essen zubereiten (Entwicklung)
2. Verpackung prΓΌfen (Testen)
3. Adresse bestΓ€tigen (Konfiguration)
4. Fahren und liefern (Deployment)
5. KundenbestΓ€tigung (Verifizierung)
β ZeitaufwΓ€ndig, fehleranfΓ€llig
CI/CD = Automatisches Liefersystem
1. Essen zubereiten (Entwicklung)
2. Automatische Verpackung (Auto-Build)
3. Automatische QualitΓ€tsprΓΌfung (Auto-Test)
4. Roboter-Automatiklieferung (Auto-Deployment)
5. Echtzeit-Tracking (Monitoring)
β Schnell und prΓ€zise
βοΈ Funktionsweiseβ
1. CI/CD-Pipelineβ
Code Push
β
βββββββββββββββββββββββββββββββ
β CI: Kontinuierliche β
β Integration β
β β
β 1. Code auschecken β
β 2. AbhΓ€ngigkeiten installierenβ
β 3. Lint-PrΓΌfung β
β 4. Build β
β 5. Unit-Tests β
β 6. Integrationstests β
β β
β β
Alle erfolgreich β
β β Beliebiger Fehler β Stop β
βββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββ
β CD: Kontinuierliches β
β Deployment β
β β
β 1. In Staging deployen β
β 2. E2E-Tests β
β 3. In Produktion deployen β
β 4. Health Check β
β 5. Benachrichtigungen sendenβ
βββββββββββββββββββββββββββββββ
β
π Deployment abgeschlossen!
2. Traditioneller Ansatz vs CI/CDβ
Traditioneller Ansatz
βββββββββββββββββββββββββββββββββββββββ
β Montag β
β - Entwickler A: Feature 1 β
β - Entwickler B: Feature 2 β
β - Entwickler C: Fehler beheben β
βββββββββββββββββββββββββββββββββββββββ€
β Dienstag-Donnerstag β
β - Individuelle Entwicklung fortsetzenβ
β - Konfliktrisiko steigt π° β
βββββββββββββββββββββββββββββββββββββββ€
β Freitag (Integrationstag) β
β - Allen Code zusammenfΓΌhren β
β - Ganzen Tag Konflikte l ΓΆsen π± β
β - Tests ausfΓΌhren β Viele Fehler β
β - Γberstunden bis Wochenende π β
βββββββββββββββββββββββββββββββββββββββ
CI/CD-Ansatz
βββββββββββββββββββββββββββββββββββββββ
β Jeden Tag, jeden Commit β
β β
β Entwickler A: Code pushen β
β β Auto-Test β
β
β β Auto-Deploy π β
β β In 3 Minuten in Produktion β
β β
β Entwickler B: Code pushen β
β β Auto-Test β β
β β Sofortige Benachrichtigung β
β β Sofort beheben (5 Min) β
β β
β - Konflikte minimiert β
β - Schnelle Fehlererkennung β
β - PΓΌnktlich Feierabend π β
βββββββββββββββββββββββββββββββββββββββ
3. CI/CD-Komponentenβ
ββββββββββββββββββββββββββββββββββββββββ
β Versionskontrolle β
β Git, GitHub, GitLab β
βββββββββββββββββ¬βββββββββββββββββββββββ
β Push
ββββββββββββββββββββββββββββββββββββββββ
β CI-Server β
β GitHub Actions, Jenkins, CircleCI β
β - Code auschecken β
β - Automatischer Build β
β - Automatische Tests β
βββββββββββββββββ¬βββββββββββββββββββββββ
β Pass
ββββββββββββββββββββββββββββββββββββββββ
β Artefakt-Repository β
β Docker Hub, npm Registry β
βββββββββββββββββ¬βββββββββββββββββββββββ
β Deploy
ββββββββββββββββββββββββββββββββββββββββ
β Deployment β
β AWS, Heroku, Vercel, Netlify β
βββββββββββββββββ¬βββββββββββββββββββββββ
β Monitor
ββββββββββββββββββββββββββββββββββββββββ
β Monitoring β
β Sentry, DataDog, CloudWatch β
ββββββββββββββββββββββββββββββββββββββββ
π‘ Praxisbeispieleβ
GitHub Actions Grundbeispielβ
# .github/workflows/ci.yml
# CI/CD-Pipeline fΓΌr Node.js-Projekt
name: CI/CD Pipeline
# Trigger: Bei Push zu main oder PR-Erstellung
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
# Umgebungsvariablen
env:
NODE_VERSION: '18'
# Job-Definitionen
jobs:
# ========== Job 1: Tests ==========
test:
name: Tests und Lint
runs-on: ubuntu-latest # Auf Ubuntu ausfΓΌhren
steps:
# 1. Code auschecken
- name: Code auschecken
uses: actions/checkout@v3
# 2. Node.js einrichten
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm' # npm-Cache verwenden
# 3. AbhΓ€ngigkeiten installieren
- name: AbhΓ€ngigkeiten installieren
run: npm ci # Schneller und stabiler als npm install
# 4. Lint-PrΓΌfung
- name: Lint ausfΓΌhren
run: npm run lint
# 5. Unit-Tests
- name: Tests ausfΓΌhren
run: npm test
# 6. Code-Abdeckung
- name: Abdeckung hochladen
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
# ========== Job 2: Build ==========
build:
name: Build
needs: test # Nur ausfΓΌhren wenn test erfolgreich
runs-on: ubuntu-latest
steps:
- name: Code auschecken
uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: AbhΓ€ngigkeiten installieren
run: npm ci
# Produktions-Build
- name: Produktions-Build
run: npm run build
env:
NODE_ENV: production
# Build-Artefakte hochladen
- name: Build-Artefakte hochladen
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
retention-days: 7
# ========== Job 3: Deployment ==========
deploy:
name: Produktions-Deployment
needs: build # Nur ausfΓΌhren wenn build erfolgreich
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # Nur main-Branch deployen
steps:
- name: Code auschecken
uses: actions/checkout@v3
# Build-Artefakte herunterladen
- name: Build-Artefakte herunterladen
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/
# Auf Vercel deployen
- name: Auf Vercel deployen
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
# Slack-Benachrichtigung
- name: Slack-Benachrichtigung
if: always() # UnabhΓ€ngig von Erfolg/Misserfolg ausfΓΌhren
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Deployment ${{ job.status }}!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Docker Build und Deploymentβ
# .github/workflows/docker.yml
# Docker Image Build und Deployment
name: Docker CI/CD
on:
push:
branches: [ main ]
tags:
- 'v*' # AusfΓΌhren bei Tags wie v1.0.0
env:
DOCKER_IMAGE: myapp
DOCKER_REGISTRY: docker.io
jobs:
docker:
name: Docker Build und Push
runs-on: ubuntu-latest
steps:
- name: Code auschecken
uses: actions/checkout@v3
# Docker-Metadaten einrichten
- name: Docker-Metadaten extrahieren
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
# Docker Buildx einrichten (Multi-Plattform-Build)
- name: Docker Buildx einrichten
uses: docker/setup-buildx-action@v2
# Bei Docker Hub anmelden
- name: Bei Docker Hub anmelden
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
# Docker Image bauen und pushen
- name: Docker Image bauen und pushen
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # GitHub Actions Cache verwenden
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64 # Multi-Plattform
# Deployment (Per SSH auf Server zugreifen und Container neu starten)
- name: Server-Deployment
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}:latest
docker stop myapp || true
docker rm myapp || true
docker run -d \
--name myapp \
-p 3000:3000 \
--restart unless-stopped \
${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}:latest
docker system prune -af
Pull Request automatische Validierungβ
# .github/workflows/pr.yml
# Bei PR-Erstellung automatisch validieren
name: Pull Request Check
on:
pull_request:
types: [ opened, synchronize, reopened ]
jobs:
# ========== Code-QualitΓ€tsprΓΌfung ==========
lint:
name: Lint und Format Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: AbhΓ€ngigkeiten installieren
run: npm ci
# ESLint
- name: ESLint ausfΓΌhren
run: npm run lint
# Prettier
- name: Prettier-PrΓΌfung
run: npm run format:check
# TypeScript-Typ-PrΓΌfung
- name: TypeScript-Typ-PrΓΌfung
run: npm run type-check
# ========== Tests ==========
test:
name: Tests
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20] # Tests auf mehreren Node-Versionen
steps:
- uses: actions/checkout@v3
- name: Node.js ${{ matrix.node-version }} einrichten
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: AbhΓ€ngigkeiten installieren
run: npm ci
- name: Tests ausfΓΌhren
run: npm test -- --coverage
- name: Test-Ergebnisse hochladen
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.node-version }}
path: coverage/
# ========== SicherheitsprΓΌfung ==========
security:
name: SicherheitsprΓΌfung
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
# npm audit
- name: npm-SicherheitsprΓΌfung
run: npm audit --audit-level=moderate
# Snyk-Sicherheitsscan
- name: Snyk-Sicherheitsscan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# ========== Performance-Tests ==========
performance:
name: Performance-Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: AbhΓ€ngigkeiten installieren
run: npm ci
- name: Build
run: npm run build
# Lighthouse CI
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
http://localhost:3000
uploadArtifacts: true
# ========== PR-Kommentar ==========
comment:
name: PR-Kommentar
needs: [lint, test, security]
runs-on: ubuntu-latest
if: always()
steps:
- name: PR-Kommentar erstellen
uses: actions/github-script@v6
with:
script: |
const statuses = {
lint: '${{ needs.lint.result }}',
test: '${{ needs.test.result }}',
security: '${{ needs.security.result }}'
};
let message = '## π€ CI-PrΓΌfungsergebnis\n\n';
for (const [job, status] of Object.entries(statuses)) {
const emoji = status === 'success' ? 'β
' : 'β';
message += `${emoji} **${job}**: ${status}\n`;
}
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});
Zeitplanbasierte Aufgabenβ
# .github/workflows/scheduled.yml
# RegelmΓ€Γig ausgefΓΌhrte Aufgaben
name: Scheduled Tasks
on:
schedule:
# TΓ€glich um 9 Uhr (UTC 0 Uhr)
- cron: '0 0 * * *'
workflow_dispatch: # Manuelle AusfΓΌhrung auch mΓΆglich
jobs:
# ========== AbhΓ€ngigkeitsaktualisierungsprΓΌfung ==========
dependency-check:
name: AbhΓ€ngigkeitsaktualisierungen prΓΌfen
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
# npm outdated prΓΌfen
- name: Veraltete Pakete prΓΌfen
run: npm outdated || true
# Dependabot-Alternative
- name: Aktualisierbare Pakete prΓΌfen
run: |
npx npm-check-updates
# ========== Backup ==========
backup:
name: Datenbank-Backup
runs-on: ubuntu-latest
steps:
- name: Datenbank sichern
run: |
# In der Praxis Datenbank-Backup-Skript ausfΓΌhren
echo "Datenbank wird gesichert..."
# Auf S3 hochladen
- name: Backup auf S3 hochladen
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: S3-Upload
run: |
aws s3 cp backup.sql s3://my-backups/$(date +%Y%m%d).sql
# ========== Performance-Monitoring ==========
performance-monitor:
name: Performance-Monitoring
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Lighthouse ausfΓΌhren
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
https://myapp.com
uploadArtifacts: true
# Bei Performance-Degradation Slack-Benachrichtigung
- name: Performance-Degradation-Benachrichtigung
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
text: 'β οΈ Website-Performance ist gesunken!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Multi-Umgebungs-Deploymentβ
# .github/workflows/multi-env.yml
# Deployment nach Umgebung: Entwicklung, Staging, Produktion
name: Multi-Environment Deployment
on:
push:
branches:
- develop # Entwicklungsumgebung
- staging # Staging-Umgebung
- main # Produktionsumgebung
jobs:
deploy:
name: Deployment
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: AbhΓ€ngigkeiten installieren
run: npm ci
# Build je nach Umgebung
- name: Build
run: npm run build
env:
NODE_ENV: ${{
github.ref == 'refs/heads/main' && 'production' ||
github.ref == 'refs/heads/staging' && 'staging' ||
'development'
}}
# Entwicklungsumgebungs-Deployment
- name: Entwicklungsumgebungs-Deployment
if: github.ref == 'refs/heads/develop'
run: |
echo "Auf Entwicklungsumgebung deployen..."
# Entwicklungsserver-Deployment-Befehl
env:
API_URL: https://api-dev.myapp.com
# Staging-Umgebungs-Deployment
- name: Staging-Umgebungs-Deployment
if: github.ref == 'refs/heads/staging'
run: |
echo "Auf Staging-Umgebung deployen..."
# Staging-Server-Deployment-Befehl
env:
API_URL: https://api-staging.myapp.com
# Produktionsumgebungs-Deployment
- name: Produktionsumgebungs-Deployment
if: github.ref == 'refs/heads/main'
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: task-definition.json
service: myapp-service
cluster: production-cluster
wait-for-service-stability: true
env:
API_URL: https://api.myapp.com
# Health Check nach Deployment
- name: Health Check
run: |
sleep 30 # 30 Sekunden warten
URL=${{
github.ref == 'refs/heads/main' && 'https://myapp.com' ||
github.ref == 'refs/heads/staging' && 'https://staging.myapp.com' ||
'https://dev.myapp.com'
}}
STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL/health)
if [ $STATUS -eq 200 ]; then
echo "β
Health Check erfolgreich"
else
echo "β Health Check fehlgeschlagen: $STATUS"
exit 1
fi
# Deployment-Erfolg-Benachrichtigung
- name: Deployment-Benachrichtigung
if: success()
uses: 8398a7/action-slack@v3
with:
status: success
text: |
π Deployment abgeschlossen!
Umgebung: ${{ github.ref_name }}
Commit: ${{ github.sha }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
π€ HΓ€ufig gestellte Fragenβ
F1. Was sind die Vorteile der EinfΓΌhrung von CI/CD?β
A:
β
Hauptvorteile:
1. Schnellere Fehlererkennung
Traditionell: Nach einer Woche entdeckt
CI/CD: Innerhalb von 5 Minuten entdeckt
β 90% Reduzierung der Behebungskosten
2. VerkΓΌrzte Deployment-Zeit
Traditionell: 2 Stunden manuelles Deployment
CI/CD: 5 Minuten automatisches Deployment
β Mehrere Deployments pro Tag mΓΆglich
3. Verbesserte Code-QualitΓ€t
- Automatische Lint- und Tests
- Automatisierte Code-Review
- Weniger Fehler
4. ErhΓΆhte EntwicklerproduktivitΓ€t
- Manuelle Aufgaben eliminieren
- Wiederholende Arbeit automatisieren
- Nur auf Entwicklung konzentrieren
5. ErhΓΆhte StabilitΓ€t
- Automatische Tests
- Automatisches Rollback
- Konsistenter Deployment-Prozess
6. Verbesserte Zusammenarbeit
- Code-Konflikte minimieren
- Schnelles Feedback
- Transparenter Prozess
Praxisfall:
Unternehmen A: Vor CI/CD
- Deployment: 1x pro Monat
- Deployment-Zeit: 4 Stunden
- Fehlerquote: 30%
- Fehlererkennungszeit: Durchschnittlich 3 Tage
Unternehmen A: Nach CI/CD
- Deployment: 10x pro Tag
- Deployment-Zeit: 5 Minuten
- Fehlerquote: 5%
- Fehlererkennungszeit: Durchschnittlich 10 Minuten
F2. GitHub Actions vs Jenkins vs CircleCI?β
A:
// ========== GitHub Actions ==========
Vorteile:
- Perfekte GitHub-Integration
- Kostenlos (ΓΆffentliche Repos, 2000 Min/Monat kostenlos)
- Einfache Einrichtung (YAML-Dateien)
- Verschiedene Actions im Marketplace
Nachteile:
- GitHub-abhΓ€ngig
- Komplexe Workflows eingeschrΓ€nkt
Am besten fΓΌr:
- GitHub verwenden
- Einfaches CI/CD
- Schneller Start erforderlich
Beispiel:
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm test
// ========== Jenkins ==========
Vorteile:
- Am Γ€ltesten und ausgereiftesten
- Umfangreiches Plugin-Γkosystem
- VollstΓ€ndige Anpassung
- Self-hosted (keine Kosten)
Nachteile:
- Komplexe Einrichtung
- Veraltete UI
- Wartung erforderlich
- Steile Lernkurve
Am besten fΓΌr:
- On-Premises-Umgebung
- Komplexe Pipelines
- Legacy-System-Integration
// ========== CircleCI ==========
Vorteile:
- Schnelle Build-Geschwindigkeit
- Hervorragende Docker-UnterstΓΌtzung
- Starke Parallelisierung
- Intuitive UI
Nachteile:
- Kostenpflichtig (eingeschrΓ€nktes kostenloses Tier)
- Nur GitHub/GitLab-UnterstΓΌtzung
Am besten fΓΌr:
- Leistung kritisch
- Intensive Docker-Nutzung
- Parallele Tests erforderlich
// ========== Vergleichstabelle ==========
Merkmal | GitHub Actions | Jenkins | CircleCI
---------------|----------------|---------|----------
Preis | Kostenlos(begr.)| Kostenlos| Bezahlt
Einrichtung | Einfach | Schwer | Mittel
Leistung | Mittel | Hoch | Hoch
Integration | GitHub perfekt | Generisch| Generisch
Wartung | Nicht nΓΆtig | NΓΆtig | Nicht nΓΆtig
Docker | Mittel | Gut | Sehr gut
Empfehlung:
- Kleines Team, GitHub nutzen β GitHub Actions
- GroΓes Team, komplexe Anforderungen β Jenkins
- Leistung kritisch, Budget vorhanden β CircleCI
F3. Wie verwaltet man geheime SchlΓΌssel (Secrets)?β
A:
# ========== GitHub Secrets Einrichtung ==========
# Repository β Settings β Secrets and variables β Actions
# Verwendung
- name: Deployment
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: npm run deploy
# ========== Umgebungsspezifische Secrets ==========
# Repository β Settings β Environments
# Produktionsumgebung
environment: production
env:
API_URL: ${{ secrets.PROD_API_URL }}
# Staging-Umgebung
environment: staging
env:
API_URL: ${{ secrets.STAGING_API_URL }}
# ========== Sicherheits-Best Practices ==========
# β
Gutes Beispiel
- name: Deployment
env:
# Von Secrets abrufen
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
run: |
# Umgebungsvariablen verwenden
aws s3 sync dist/ s3://my-bucket
# β Schlechtes Beispiel
- name: Deployment
run: |
# Im Code hartkodiert (absolut verboten!)
export AWS_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
# ========== .env-Datei erstellen ==========
- name: .env-Datei erstellen
run: |
cat << EOF > .env
API_URL=${{ secrets.API_URL }}
DATABASE_URL=${{ secrets.DATABASE_URL }}
JWT_SECRET=${{ secrets.JWT_SECRET }}
EOF
# ========== Docker Secrets ==========
- name: Docker Build
env:
DOCKER_BUILDKIT: 1
run: |
docker build \
--secret id=api_key,env=API_KEY \
--secret id=db_url,env=DATABASE_URL \
-t myapp .
# Dockerfile
# syntax=docker/dockerfile:1
FROM node:18
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) npm install
# ========== Vault verwenden (Fortgeschritten) ==========
- name: Secrets von HashiCorp Vault abrufen
uses: hashicorp/vault-action@v2
with:
url: https://vault.mycompany.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/production api_key | API_KEY ;
secret/data/production db_url | DATABASE_URL
F4. Was passiert, wenn Tests fehlschlagen?β
A:
# ========== Standardverhalten: Pipeline stoppen ==========
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Tests ausfΓΌhren
run: npm test
# Bei Test-Fehler β hier stoppen
# Folgende Schritte werden nicht ausgefΓΌhrt
deploy:
needs: test # Wird nur ausgefΓΌhrt wenn test erfolgreich
runs-on: ubuntu-latest
steps:
- name: Deployment
run: npm run deploy
# Bei test-Fehler wird dieser Schritt nicht ausgefΓΌhrt β
# ========== Bei Fehler trotzdem fortsetzen ==========
- name: Tests ausfΓΌhren
run: npm test
continue-on-error: true # Bei Fehler fortsetzen
# β οΈ Nicht empfohlen
# ========== Bedingte AusfΓΌhrung ==========
- name: Benachrichtigung bei Fehler
if: failure() # Nur wenn vorheriger Schritt fehlgeschlagen
uses: 8398a7/action-slack@v3
with:
status: failure
text: 'β Test fehlgeschlagen!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
- name: Bei Erfolg deployen
if: success() # Nur wenn alle Schritte erfolgreich
run: npm run deploy
- name: Immer ausfΓΌhren
if: always() # UnabhΓ€ngig von Erfolg/Misserfolg
run: npm run cleanup
# ========== Wiederholungsversuche ==========
- name: Instabile Tests (Wiederholungsversuche)
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: npm run test:e2e
# ========== Fehlerbehandlungsbeispiel ==========
- name: Tests
id: test
run: npm test
- name: Issue erstellen bei Test-Fehler
if: failure() && steps.test.outcome == 'failure'
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'β Test fehlgeschlagen',
body: 'Tests sind fehlgeschlagen. ΓberprΓΌfung erforderlich.',
labels: ['bug', 'ci']
});
# ========== Rollback ==========
- name: Deployment
id: deploy
run: npm run deploy
- name: Bei Deployment-Fehler Rollback
if: failure() && steps.deploy.outcome == 'failure'
run: |
echo "Deployment fehlgeschlagen! Rollback zur vorherigen Version..."
npm run rollback
F5. Wie kann man Kosten senken?β
A:
# ========== Caching nutzen ==========
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm' # npm-Caching (50% schnellerer Build)
- name: AbhΓ€ngigkeiten cachen
uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# ========== Bedingte AusfΓΌhrung ==========
on:
push:
branches: [ main ]
paths: # Nur bei Γnderung bestimmter Dateien ausfΓΌhren
- 'src/**'
- 'package.json'
# Bei README.md-Γnderung nicht ausfΓΌhren β Kostenersparnis
# ========== Gleichzeitige AusfΓΌhrung begrenzen ==========
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # Vorherige AusfΓΌhrung abbrechen
# β Verhindert unnΓΆtige doppelte AusfΓΌhrungen
# ========== Self-hosted Runner ==========
# Eigenen Server verwenden (kostenlos)
jobs:
build:
runs-on: self-hosted # Verbraucht keine GitHub Actions-Minuten
steps:
- run: npm run build
# ========== Nur kurze Jobs ausfΓΌhren ==========
- name: GeΓ€nderte Dateien prΓΌfen
id: changes
uses: dorny/paths-filter@v2
with:
filters: |
frontend:
- 'frontend/**'
backend:
- 'backend/**'
- name: Frontend-Tests
if: steps.changes.outputs.frontend == 'true'
run: npm run test:frontend
# Nur bei Frontend-Γnderung ausfΓΌhren β Zeitersparnis
- name: Backend-Tests
if: steps.changes.outputs.backend == 'true'
run: npm run test:backend
# ========== Kostenbeispiel ==========
# GitHub Actions Free Tier:
# - Γffentliche Repos: Unbegrenzt
# - Private Repos: 2000 Minuten/Monat
# Vor Optimierung:
# - VollstΓ€ndige Tests bei jedem Commit (20 Min)
# - 10x Push pro Tag
# - Monatliche Nutzung: 10 Γ 20 Γ 30 = 6000 Min
# - Γberkosten: (6000 - 2000) Γ $0.008 = $32
# Nach Optimierung:
# - 10 Min durch Caching gespart
# - Nur geΓ€nderte Teile testen
# - Durchschnittliche Build-Zeit 5 Min
# - Monatliche Nutzung: 10 Γ 5 Γ 30 = 1500 Min
# - Kosten: $0 (innerhalb Free Tier)
# β $32/Monat gespart!
π NΓ€chste Schritteβ
Nachdem Sie CI/CD verstanden haben, lernen Sie diese Themen:
- Was ist Git? (Noch zu schreiben) - Grundlagen der Versionskontrolle
- Was ist Docker? (Noch zu schreiben) - Containerisiertes Deployment
- Was ist TDD? (Noch zu schreiben) - Testgetriebene Entwicklung
Ausprobierenβ
# ========== 1. Mit GitHub Actions beginnen ==========
# 1) Workflow-Datei im Repository erstellen
mkdir -p .github/workflows
cat > .github/workflows/ci.yml << 'EOF'
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js einrichten
uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm test
EOF
# 2) Commit und Push
git add .github/workflows/ci.yml
git commit -m "Add CI workflow"
git push
# 3) Actions-Tab auf GitHub ansehen
# β Den automatisch laufenden Workflow sehen!
# ========== 2. Lokal testen (act) ==========
# Mit act GitHub Actions lokal testen
# act installieren (macOS)
brew install act
# Workflow ausfΓΌhren
act push
# Nur spezifischen Job ausfΓΌhren
act -j test
# ========== 3. Beispiele fΓΌr Deployment-Automatisierung ==========
# Vercel-Deployment
npm install -g vercel
vercel login
vercel --prod
# Netlify-Deployment
npm install -g netlify-cli
netlify login
netlify deploy --prod
# Heroku-Deployment
heroku login
git push heroku main
π¬ Zusammenfassungβ
CI/CD ist ein unverzichtbares Werkzeug in der modernen Entwicklung:
- CI: Code-Γnderungen automatisch testen und integrieren
- CD: Getesteten Code automatisch deployen
- Vorteile: Schnelles Feedback, erhΓΆhte StabilitΓ€t, gesteigerte ProduktivitΓ€t
- Tools: GitHub Actions, Jenkins, CircleCI, etc.
Konzentrieren Sie sich auf die Entwicklung und deployen Sie schneller mit Automatisierung! π