DevOps & CI/CD Patterns
CI/CD and container orchestration patterns for the EUCORA platform.
Quick Reference
| Technology | Pattern |
|---|
| CI/CD | GitHub Actions |
| Containers | Docker Compose (dev), Kubernetes (prod) |
| Quality Gates | Pre-commit hooks + CI enforcement |
| Coverage | ≥90% enforced |
| Linting | Zero warnings tolerance |
GitHub Actions Workflows
Workflow Structure
yaml
1# .github/workflows/code-quality.yml
2name: Code Quality
3
4on:
5 push:
6 branches: [main, develop]
7 pull_request:
8 branches: [main]
9
10jobs:
11 backend-tests:
12 runs-on: ubuntu-latest
13
14 services:
15 postgres:
16 image: postgres:16
17 env:
18 POSTGRES_DB: test_db
19 POSTGRES_USER: test
20 POSTGRES_PASSWORD: test
21 ports:
22 - 5432:5432
23 options: >-
24 --health-cmd pg_isready
25 --health-interval 10s
26 --health-timeout 5s
27 --health-retries 5
28
29 steps:
30 - uses: actions/checkout@v4
31
32 - name: Set up Python
33 uses: actions/setup-python@v5
34 with:
35 python-version: '3.12'
36 cache: 'pip'
37
38 - name: Install dependencies
39 run: pip install -r requirements.txt
40
41 - name: Run tests with coverage
42 run: pytest --cov --cov-fail-under=90 --cov-report=xml
43 env:
44 DATABASE_URL: postgres://test:test@localhost:5432/test_db
45
46 - name: Upload coverage
47 uses: codecov/codecov-action@v4
48 with:
49 files: coverage.xml
50 fail_ci_if_error: true
51
52 frontend-tests:
53 runs-on: ubuntu-latest
54
55 steps:
56 - uses: actions/checkout@v4
57
58 - name: Set up Node
59 uses: actions/setup-node@v4
60 with:
61 node-version: '20'
62 cache: 'npm'
63 cache-dependency-path: frontend/package-lock.json
64
65 - name: Install dependencies
66 run: npm ci
67 working-directory: frontend
68
69 - name: TypeScript check
70 run: npx tsc --noEmit
71 working-directory: frontend
72
73 - name: ESLint (zero warnings)
74 run: npm run lint -- --max-warnings 0
75 working-directory: frontend
76
77 - name: Run tests
78 run: npm test -- --coverage
79 working-directory: frontend
Quality Gate Enforcement
yaml
1# Quality gate job - blocks merge if failed
2quality-gate:
3 runs-on: ubuntu-latest
4 needs: [backend-tests, frontend-tests, security-scan]
5
6 steps:
7 - name: Check all jobs passed
8 run: |
9 echo "All quality gates passed ✅"
10 echo "- Backend tests: ${{ needs.backend-tests.result }}"
11 echo "- Frontend tests: ${{ needs.frontend-tests.result }}"
12 echo "- Security scan: ${{ needs.security-scan.result }}"
Docker Compose
Development Configuration
yaml
1# docker-compose.dev.yml
2version: '3.8'
3
4services:
5 web:
6 build:
7 context: .
8 dockerfile: Dockerfile.dev
9 ports:
10 - "8000:8000"
11 volumes:
12 - ./backend:/app
13 - static_volume:/app/staticfiles
14 environment:
15 - DEBUG=True
16 - DATABASE_URL=postgres://user:pass@db:5432/eucora
17 - REDIS_URL=redis://redis:6379/0
18 depends_on:
19 db:
20 condition: service_healthy
21 redis:
22 condition: service_healthy
23 healthcheck:
24 test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
25 interval: 30s
26 timeout: 10s
27 retries: 3
28
29 db:
30 image: postgres:16
31 volumes:
32 - postgres_data:/var/lib/postgresql/data
33 environment:
34 POSTGRES_DB: eucora
35 POSTGRES_USER: user
36 POSTGRES_PASSWORD: pass
37 healthcheck:
38 test: ["CMD-SHELL", "pg_isready -U user -d eucora"]
39 interval: 10s
40 timeout: 5s
41 retries: 5
42
43 redis:
44 image: redis:7-alpine
45 healthcheck:
46 test: ["CMD", "redis-cli", "ping"]
47 interval: 10s
48 timeout: 5s
49 retries: 3
50
51 celery-worker:
52 build:
53 context: .
54 dockerfile: Dockerfile.dev
55 command: celery -A config worker -l info
56 volumes:
57 - ./backend:/app
58 environment:
59 - DATABASE_URL=postgres://user:pass@db:5432/eucora
60 - REDIS_URL=redis://redis:6379/0
61 depends_on:
62 - web
63 - redis
64
65 celery-beat:
66 build:
67 context: .
68 dockerfile: Dockerfile.dev
69 command: celery -A config beat -l info
70 volumes:
71 - ./backend:/app
72 depends_on:
73 - celery-worker
74 deploy:
75 replicas: 1 # Singleton pattern
76
77volumes:
78 postgres_data:
79 static_volume:
Production Configuration
yaml
1# docker-compose.prod.yml
2version: '3.8'
3
4services:
5 web:
6 image: eucora/backend:${TAG:-latest}
7 deploy:
8 replicas: 3
9 resources:
10 limits:
11 cpus: '1'
12 memory: 1G
13 reservations:
14 cpus: '0.5'
15 memory: 512M
16 update_config:
17 parallelism: 1
18 delay: 10s
19 failure_action: rollback
20 healthcheck:
21 test: ["CMD", "curl", "-f", "http://localhost:8000/health/"]
22 interval: 30s
23 timeout: 10s
24 retries: 3
25 start_period: 40s
Pre-Commit Hooks
Configuration
yaml
1# .pre-commit-config.yaml
2repos:
3 # Python
4 - repo: https://github.com/astral-sh/ruff-pre-commit
5 rev: v0.3.0
6 hooks:
7 - id: ruff
8 args: [--fix]
9 - id: ruff-format
10
11 - repo: https://github.com/pre-commit/mirrors-mypy
12 rev: v1.8.0
13 hooks:
14 - id: mypy
15 additional_dependencies: [types-all]
16
17 # JavaScript/TypeScript
18 - repo: https://github.com/pre-commit/mirrors-eslint
19 rev: v8.56.0
20 hooks:
21 - id: eslint
22 args: [--max-warnings, '0']
23 files: \.[jt]sx?$
24
25 # Security
26 - repo: https://github.com/Yelp/detect-secrets
27 rev: v1.4.0
28 hooks:
29 - id: detect-secrets
30 args: ['--baseline', '.secrets.baseline']
31
32 # General
33 - repo: https://github.com/pre-commit/pre-commit-hooks
34 rev: v4.5.0
35 hooks:
36 - id: trailing-whitespace
37 - id: end-of-file-fixer
38 - id: check-yaml
39 - id: check-json
40 - id: check-merge-conflict
41 - id: no-commit-to-branch
42 args: [--branch, main]
Installation
bash
1# Install pre-commit
2pip install pre-commit
3
4# Install hooks
5pre-commit install
6
7# Run on all files
8pre-commit run --all-files
Dockerfile Patterns
Multi-Stage Build
dockerfile
1# Dockerfile
2# Stage 1: Build
3FROM python:3.12-slim as builder
4
5WORKDIR /app
6
7COPY requirements.txt .
8RUN pip wheel --no-cache-dir --no-deps --wheel-dir /wheels -r requirements.txt
9
10# Stage 2: Production
11FROM python:3.12-slim
12
13ENV PYTHONDONTWRITEBYTECODE=1 \
14 PYTHONUNBUFFERED=1
15
16WORKDIR /app
17
18# Install system deps
19RUN apt-get update && apt-get install -y --no-install-recommends \
20 libpq5 \
21 && rm -rf /var/lib/apt/lists/*
22
23# Install Python deps
24COPY --from=builder /wheels /wheels
25RUN pip install --no-cache /wheels/*
26
27# Copy app
28COPY backend/ .
29
30# Create non-root user
31RUN adduser --disabled-password --gecos '' appuser
32USER appuser
33
34EXPOSE 8000
35
36CMD ["gunicorn", "config.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "4"]
Development Dockerfile
dockerfile
1# Dockerfile.dev
2FROM python:3.12-slim
3
4ENV PYTHONDONTWRITEBYTECODE=1 \
5 PYTHONUNBUFFERED=1
6
7WORKDIR /app
8
9# Install system deps
10RUN apt-get update && apt-get install -y --no-install-recommends \
11 libpq-dev gcc curl \
12 && rm -rf /var/lib/apt/lists/*
13
14COPY requirements.txt requirements-dev.txt ./
15RUN pip install -r requirements-dev.txt
16
17EXPOSE 8000
18
19CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Quality Gates Checklist
CI Pipeline Must Enforce
☐ Backend tests pass (pytest)
☐ Frontend tests pass (vitest)
☐ Coverage ≥90% (pytest-cov, vitest --coverage)
☐ TypeScript check passes (tsc --noEmit)
☐ ESLint zero warnings (--max-warnings 0)
☐ Python linting passes (ruff)
☐ Security scan passes (trivy, detect-secrets)
☐ SPDX compliance check passes
Pre-Commit Must Block
☐ Trailing whitespace
☐ Merge conflicts
☐ Invalid YAML/JSON
☐ Secrets in code
☐ Direct commits to main
☐ Type errors (mypy)
☐ Linting errors (ruff, eslint)
Commands Reference
bash
1# Docker Compose
2docker compose -f docker-compose.dev.yml up -d
3docker compose -f docker-compose.dev.yml logs -f web
4docker compose -f docker-compose.dev.yml exec web python manage.py migrate
5docker compose -f docker-compose.dev.yml down -v
6
7# Pre-commit
8pre-commit install
9pre-commit run --all-files
10pre-commit autoupdate
11
12# Testing with coverage
13pytest --cov --cov-fail-under=90 --cov-report=html
14npm test -- --coverage
15
16# Build and push
17docker build -t eucora/backend:latest .
18docker push eucora/backend:latest
Anti-Patterns
| ❌ FORBIDDEN | ✅ CORRECT |
|---|
| Skipping CI checks | All checks must pass |
| Coverage < 90% | Enforce ≥90% in CI |
--no-verify commits | Pre-commit hooks mandatory |
| Secrets in Dockerfile | Use build args or vault |
| Root user in container | Create non-root user |
| No health checks | Always define health checks |