← Zurück zum Blog
GitLabCI/CDDjangoDocker28. März 2026· 15 min Lesezeit

GitLab CI/CD für Django-Projekte: komplette Pipeline aufsetzen

Inhalt
  1. Grundstruktur der Pipeline
  2. Test-Stage
  3. Code-Qualität: Linting und Type-Checking
  4. Docker-Build-Stage
  5. Deployment-Stage
  6. Umgebungsvariablen und Secrets
  7. Optimierungen für schnelle Pipelines

CI/CD ist einer der größten Qualitätshebel in der Softwareentwicklung. Ich baue GitLab-Pipelines seit vielen Jahren und zeige dir hier eine kampferprobte Konfiguration für Django-Projekte.

Grundstruktur der Pipeline

# .gitlab-ci.yml
image: python:3.12-slim

variables:
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
  POSTGRES_DB: test_db
  POSTGRES_USER: postgres
  POSTGRES_PASSWORD: postgres
  DATABASE_URL: "postgres://postgres:postgres@postgres:5432/test_db"

cache:
  paths:
    - .cache/pip
    - venv/

stages:
  - test
  - quality
  - build
  - deploy

before_script:
  - python -m venv venv
  - source venv/bin/activate
  - pip install -r requirements.txt -q

Test-Stage

test:unit:
  stage: test
  services:
    - postgres:16-alpine
    - redis:7-alpine
  variables:
    REDIS_URL: "redis://redis:6379/0"
  script:
    - pytest
        --cov=myapp
        --cov-report=term-missing
        --cov-report=xml
        --cov-fail-under=80
        -v
  coverage: '/TOTAL.*\s+(\d+%)$/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
    expire_in: 1 week

test:migrations:
  stage: test
  services:
    - postgres:16-alpine
  script:
    - python manage.py migrate --check  # Fehlschlag wenn Migrations fehlen
    - python manage.py migrate
    - python manage.py check --deploy

Code-Qualität: Linting und Type-Checking

quality:lint:
  stage: quality
  script:
    - pip install ruff mypy -q
    - ruff check myapp/          # Linting
    - ruff format --check myapp/ # Format-Check
    - mypy myapp/ --ignore-missing-imports
  allow_failure: false

quality:security:
  stage: quality
  script:
    - pip install bandit safety -q
    - bandit -r myapp/ -ll      # Security-Scan
    - safety check              # Bekannte Vulnerabilities in Dependencies
  allow_failure: true  # Warnung, kein Fehler

Docker-Build-Stage

build:docker:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  variables:
    DOCKER_TLS_CERTDIR: "/certs"
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build
        --cache-from $CI_REGISTRY_IMAGE:latest
        --build-arg BUILDKIT_INLINE_CACHE=1
        -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
        -t $CI_REGISTRY_IMAGE:latest
        .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - docker push $CI_REGISTRY_IMAGE:latest
  only:
    - main
    - develop

Deployment-Stage

deploy:staging:
  stage: deploy
  image: alpine:latest
  before_script:
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - mkdir -p ~/.ssh && chmod 700 ~/.ssh
    - ssh-keyscan $STAGING_HOST >> ~/.ssh/known_hosts
  script:
    - ssh deploy@$STAGING_HOST "
        docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA &&
        docker-compose -f /srv/myapp/docker-compose.prod.yml up -d --no-deps web &&
        docker exec myapp_web python manage.py migrate --no-input
      "
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

deploy:production:
  stage: deploy
  extends: .deploy_template
  environment:
    name: production
    url: https://example.com
  when: manual  # Manueller Trigger für Produktion!
  only:
    - main

Umgebungsvariablen und Secrets

Secrets gehören nie in die .gitlab-ci.yml. Nutze GitLab CI/CD Variables (unter Settings → CI/CD → Variables):

Optimierungen für schnelle Pipelines

# Parallele Jobs für mehr Speed
test:parallel:
  stage: test
  parallel:
    matrix:
      - TEST_MODULE: [articles, users, orders, payments]
  script:
    - pytest myapp/$TEST_MODULE/ -v

# Nur relevante Jobs bei Feature-Branches
.only_changes: &only_changes
  only:
    changes:
      - "myapp/**/*"
      - "requirements*.txt"

test:unit:
  <<: *only_changes
  stage: test
  script:
    - pytest
Yevhen Chubchyk
Yevhen Chubchyk
Senior Python / Django Entwickler · Freelancer seit 2016 · 20+ Jahre IT-Erfahrung. Kunden: Siemens Healthineers, Engie, natureOffice u.a.