{}const=>[]async()letfn</>var
EntwicklungGrundlagen

CI/CD leicht erklärt: Auto-Deploy in einem Abend

Eine einfache Erklärung von CI/CD und ein fertiges Beispiel für die automatische Bereitstellung über GitHub Actions.

К

Kodik

Autor

4 Min. Lesezeit

Was ist CI/CD und warum brauchen Sie es?

  • CI (Continuous Integration) — jede Änderung wird automatisch gesammelt und getestet.

  • CD (Continuous Delivery/Deployment) - Nach dem Erfolg rollen wir ohne Hände auf den Stand / Prod.

Vorteile: weniger manuelle Fehler, schnelle Releases, Transparenz für das Team und vorhersehbare Rollouts. 🧘‍♂️

🔥 100.000+ Schüler sind bereits bei uns

Genug Theorie gelesen?
Zeit zu coden!

Kodik — eine App, in der du durch Praxis programmieren lernst. KI-Mentor, interaktive Lektionen, echte Projekte.

🤖 KI 24/7
🎓 Zertifikate
💰 Kostenlos
🚀 Jetzt starten
Heute beigetreten

Server: Grundausbildung (VPS)

# 1) Docker und Compose-Plugin (Ubuntu)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

# 2) Katalog der Anlage
sudo mkdir -p /opt/myapp && sudo chown -R $USER:$USER /opt/myapp
cd /opt/myapp

# 3) .env (auf dem Server, nicht committen)
cat > .env << 'ENV'
PORT=3000
ENV

# 4) docker-compose.yml
cat > docker-compose.yml << 'YAML'
services:
  web:
    image: registry.example.com/myapp:latest
    env_file: .env
    ports:
      - "80:3000"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
      timeout: 3s
      retries: 5
YAML

# 5) Erster Start (bisher ohne CI)
docker compose pull && docker compose up -d

Dockerfile (Mindestbeispiel für Node/PNPM)

# Dockerfile
FROM node:20-alpine AS deps
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm i --frozen-lockfile

FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/dist dist
COPY package.json ./
RUN corepack enable && corepack prepare pnpm@latest --activate && pnpm i --prod --frozen-lockfile
EXPOSE 3000
CMD ["node", "dist/server.js"]

GitHub-Aktionen: Image-Build und SSH-Bereitstellung

Fügen Sie .github/workflows/deploy.yml zum Repository hinzu:

name: CI/CD Deploy

on:
  push:
    branches: [ "main" ]

permissions:
  contents: read
  packages: write

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

      - name: Set up Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to registry
        uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY_URL }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASSWORD }}

      - name: Build & push image
        uses: docker/build-push-action@v6
        with:
          push: true
          context: .
          tags: ${{ secrets.REGISTRY_URL }}/${{ secrets.IMAGE_NAME }}:latest

      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1.0.0
        with:
          host:     ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key:      ${{ secrets.SERVER_SSH_KEY }}
          script: |
            set -e
            cd /opt/myapp
            docker compose pull
            docker compose up -d
            docker image prune -f

Geheimnisse: REGISTRY_URL, REGISTRY_USER, REGISTRY_PASSWORD, IMAGE_NAME, SERVER_HOST, SERVER_USER, SERVER_SSH_KEY.

GitLab CI: Alternative

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

variables:
  IMAGE: $CI_REGISTRY_IMAGE:latest

build:
  stage: build
  image: docker:27.0
  services: [ "docker:27.0-dind" ]
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
    - docker build -t $IMAGE .
    - docker push $IMAGE
  artifacts:
    expire_in: 1 week
    when: on_success
    paths: []

deploy:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
  script:
    - ssh -o StrictHostKeyChecking=no $DEPLOY_USER@$DEPLOY_HOST "
        set -e
        cd /opt/myapp &&
        docker compose pull &&
        docker compose up -d &&
        docker image prune -f
      "
  only:
    - main

Keine Ausfallzeiten und Rückgänge

  • Zero‑downtime: restart: unless-stopped + healthcheck + up -d - der neue Container startet, der alte wird gelöscht.

  • Release-Tags: zusätzlich zu :latest push :v1.4.2 — einfacheres Rollback.

  • Rollback: Schalten Sie das Tag in docker-compose.yml und wiederholen Sie pull/up -d.

  • Blaues/grünes Schema (vereinfacht): halten Sie zwei Dienste web_blue und web_green, balancieren Sie den Datenverkehr über Nginx.

Minimale Pipeline-Überprüfungen

# Beispiel für einen Schritt mit Tests in GitHub Actions
- name: Install deps & test
  run: |
    npm ci
    npm run test -- --ci

Schwelle für das „Abend“-CI: Unit-Tests ausführen, Build kompilieren, Linter (ESLint/flake8) durchlaufen, Typen (tsc/mypy) überprüfen.

Überwachung und Protokollierung

  • Fügen Sie /health und /metrics (Prometheus-Format) zum Dienst hinzu.

  • Protokollsammlung: docker logs → Loki/ELK; Statuscode-/Latenzalarm.

  • In CI - Artefakte mit Test- und Linter-Berichten, um Regressionen zu sehen.

Geheimnisse und Sicherheit

  • Geheimnisse nur in Secrets/Variables CI; .env — auf dem Server.

  • Deaktivieren Sie die SSH-Anmeldung mit Passwort, lassen Sie die Anmeldung mit Schlüssel aktiv, beschränken Sie die Ports.

  • Speichern Sie private Schlüssel nicht im Repository, auch nicht in verschlüsselter Form.

🧯 Typische Probleme und schnelle Lösungen

Symptom

Ursache

Fix

CI fällt bei der Montage

Wenig RAM/Timeout

Cache-Layer, leichtere Image-Basis, Timeout erhöhen

Die Anwendung wird nicht gestartet

Port/ENV/Migration

Überprüfen Sie .env, docker logs, healthcheck, führen Sie Migrationen aus

Langsames Deploy

Schweres Bild

Mehrstufig, alpine, .dockerignore, Caching von Abhängigkeiten

„Es funktioniert bei mir“

Verschiedene Versionen von Node/Python

Versionen in Docker fixieren, Lock-Dateien verwenden

Festplatte voll

Alte Bilder/Container

docker system prune -f, Protokollrotation

Im Anhang „Kodik – Programmieren lernen“ – kurze Lektionen und Miniprojekte. Bei uns ist es interessant!

Und wir haben auch einen aktiven Telegram-Kanal, wo wir coole Ideen diskutieren, Erfahrungen teilen und Aufgaben gemeinsam analysieren — Lernen wird nicht nur nützlich, sondern auch unterhaltsam.

Ergebnis

CI/CD ist keine „große Magie“, sondern eine Reihe einfacher Schritte. Image-Build, Push in die Registry, Neustart des Dienstes auf VPS — und Sie haben schnelle, wiederholbare Releases ohne manuelle Routine. Fangen Sie noch heute an, und morgen wird das Team vergessen, wie ein „manueller Deploy“ aussah.

Worauf werden Sie den Autodeploy drehen - GitHub Actions oder GitLab CI?

🎯Hör auf zu zögern

Artikel gefallen?
Zeit zum Üben!

Bei Kodik liest du nicht nur — du schreibst sofort Code. Theorie + Praxis = echte Skills.

Sofortige Praxis
🧠KI erklärt Code
🏆Zertifikat

Keine Registrierung • Keine Karte