Wdrożenie aplikacji Django – Docker i CI/CD

Kacper Sieradziński
Kacper Sieradziński
6 maja 2025Edukacja4 min czytania

Wdrożenie aplikacji Django do środowiska produkcyjnego to coś więcej niż samo uruchomienie python manage.py runserver. To proces, który wymaga odpowiedniego podejścia do konfiguracji serwera, bazy danych, cache'owania, plików statycznych i bezpieczeństwa. Na szczęście — Docker i CI/CD pozwalają zautomatyzować i uprościć cały ten proces.

Obraz główny Wdrożenie aplikacji Django – Docker i CI/CD

Dlaczego Docker?

Docker pozwala uruchamiać aplikacje w lekkich, odizolowanych kontenerach. Dzięki temu masz identyczne środowisko w fazie developmentu, testów i produkcji.

Bez Dockera

Problemy, z którymi spotykasz się bez Dockera:

  • różne wersje bibliotek i Pythona między developerami,
  • błędy „u mnie działa",
  • problemy z zależnościami i konfiguracją systemu.

Z Dockerem

Korzyści z używania Dockera:

  • powtarzalne środowisko,
  • prosty deployment,
  • łatwe skalowanie i integracja z CI/CD.

Docker rozwiązuje problem „u mnie działa" poprzez enkapsulację całego środowiska aplikacji w kontenerze, który działa identycznie na każdym komputerze.

Konfiguracja Docker dla Django

Zacznij od stworzenia pliku Dockerfile w katalogu projektu:

Dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 # Dockerfile FROM python:3.12-slim ENV PYTHONUNBUFFERED=1 WORKDIR /app COPY requirements.txt /app/ RUN pip install --no-cache-dir -r requirements.txt COPY . /app/ CMD ["gunicorn", "app.wsgi:application", "--bind", "0.0.0.0:8000"]

Ten obraz:

  • bazuje na oficjalnym Pythonie (obraz python:3.12-slim jest lekki i bezpieczny),
  • instaluje zależności z requirements.txt,
  • uruchamia aplikację przez Gunicorn — produkcyjny serwer WSGI (zamiast wbudowanego serwera deweloperskiego Django).

Flaga --no-cache-dir zmniejsza rozmiar obrazu, a PYTHONUNBUFFERED=1 zapewnia, że logi są wyświetlane w czasie rzeczywistym.

docker-compose – cały ekosystem

Większość projektów Django wymaga nie tylko aplikacji, ale też bazy danych, cache'a i serwera statycznych plików. docker-compose.yml pozwala uruchomić wszystkie te usługi jednym poleceniem:

YAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 version: '3.9' services: web: build: . command: gunicorn app.wsgi:application --bind 0.0.0.0:8000 volumes: - .:/app ports: - "8000:8000" depends_on: - db - redis environment: - DEBUG=False - DATABASE_URL=postgres://django:secret@db:5432/django_db db: image: postgres:15 environment: POSTGRES_USER: django POSTGRES_PASSWORD: secret POSTGRES_DB: django_db volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis:7 volumes: postgres_data:

Uruchom wszystko komendą:

Bash
1 docker-compose up --build

I gotowe — masz lokalne środowisko z PostgreSQL, Redisem i Django. Flag --build wymusza przebudowę obrazów, co jest przydatne po zmianach w Dockerfile.

Zmienna konfiguracja (dotenv i secrets)

Nie trzymaj haseł w kodzie. Zamiast tego używaj pliku .env:

INI
1 2 3 4 DEBUG=False SECRET_KEY=your-secret-key-here DATABASE_URL=postgres://django:secret@db:5432/django_db REDIS_URL=redis://redis:6379/0

I załaduj je w settings.py np. przez bibliotekę python-decouple:

Bash
1 pip install python-decouple

W settings.py:

Python
1 2 3 4 5 6 7 8 9 10 11 from decouple import config SECRET_KEY = config('SECRET_KEY') DEBUG = config('DEBUG', cast=bool, default=False) DATABASE_URL = config('DATABASE_URL') # Parsowanie DATABASE_URL dla Django import dj_database_url DATABASES = { 'default': dj_database_url.config(default=DATABASE_URL) }

Pamiętaj, aby dodać .env do .gitignore, aby nie commitować wrażliwych danych do repozytorium. W środowisku produkcyjnym używaj zmiennych środowiskowych serwera lub zarządzanych sekretów (np. AWS Secrets Manager, HashiCorp Vault).

Wdrożenie produkcyjne (Gunicorn + Nginx)

W środowisku produkcyjnym Django powinno być uruchamiane za pomocą Gunicorn (aplikacja) i Nginx (reverse proxy). Gunicorn obsługuje wiele workerów równolegle, co zapewnia lepszą wydajność niż serwer deweloperski Django.

Konfiguracja Nginx

Przykładowa konfiguracja Nginx (nginx.conf):

NGINX
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 server { listen 80; server_name example.com; location /static/ { alias /app/static/; } location /media/ { alias /app/media/; } location / { proxy_pass http://web:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

Docker Compose z Nginx

Dodaj nowy serwis do docker-compose.yml:

YAML
1 2 3 4 5 6 7 8 9 10 11 nginx: image: nginx:latest ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf - ./static:/app/static - ./media:/app/media depends_on: - web

W produkcji użyj HTTPS — skonfiguruj certyfikaty SSL (np. przez Let's Encrypt i Certbot). Nginx obsługuje również kompresję, cache'owanie i ochronę przed podstawowymi atakami.

CI/CD – automatyzacja wdrażania

Ręczne wdrażanie to przeszłość. Z pomocą GitHub Actions, GitLab CI lub Jenkins możesz w pełni zautomatyzować proces wdrożeniowy. CI/CD pipeline automatycznie uruchamia testy, sprawdza jakość kodu i wdraża aplikację po każdym pushu do repozytorium.

Przykład GitHub Actions

Przykład .github/workflows/deploy.yml:

YAML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 name: Django CI/CD on: push: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: 3.12 - name: Install dependencies run: | pip install -r requirements.txt - name: Run tests run: | python manage.py test - name: Run linting run: | pip install flake8 black flake8 . black --check . deploy: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - name: Checkout uses: actions/checkout@v4 - name: Deploy with Docker run: | docker-compose -f docker-compose.prod.yml build docker-compose -f docker-compose.prod.yml up -d

Ten pipeline:

  • pobiera kod z repozytorium,
  • instaluje zależności,
  • uruchamia testy jednostkowe,
  • sprawdza jakość kodu (linting),
  • automatycznie wdraża aplikację (tylko jeśli testy przeszły).

W prawdziwym projekcie dodaj też etapy dla staging environment, rollback w przypadku błędów oraz powiadomienia o statusie wdrożenia.

Dobre praktyki przy wdrażaniu Django

Przy wdrażaniu aplikacji Django warto pamiętać o kilku kluczowych zasadach:

  1. Oddziel środowiska — osobne konfiguracje dla dev, staging, prod. Używaj osobnych plików .envdocker-compose dla każdego środowiska.

  2. Używaj .env — nigdy nie trzymaj haseł, kluczy API i tokenów w repozytorium. Wszystkie wrażliwe dane powinny być w zmiennych środowiskowych.

  3. Kompresuj i serwuj statyczne pliki przez CDN — użyj collectstatic i skonfiguruj CDN (CloudFront, Cloudflare) dla lepszej wydajności. Django oferuje WhiteNoise jako prostszą alternatywę.

  4. Monitoruj błędy — np. przez Sentry, który automatycznie zbiera i raportuje błędy z aplikacji. To pozwala szybko reagować na problemy w produkcji.

  5. Automatyzuj testy i linting przed każdym merge'em — blokuj merge, jeśli testy nie przechodzą lub kod nie spełnia standardów jakości.

  6. Twórz backupy bazy danych automatycznie — użyj cron + pg_dump (dla PostgreSQL) lub narzędzi cloud (AWS RDS automatyczne backupy). Testuj również proces przywracania z backupu.

  7. Używaj migracji bazodanowych — zawsze stosuj migracje w procesie wdrożenia (python manage.py migrate). Rozważ rollback plan na wypadek problemów.

Skalowanie i dalsza automatyzacja

Kiedy aplikacja rośnie, potrzebujesz bardziej zaawansowanych narzędzi:

  1. Docker Swarm lub Kubernetes — do zarządzania kontenerami w klastrze. Umożliwiają automatyczne skalowanie, load balancing i wysoką dostępność.

  2. GitOps — np. ArgoCD do zarządzania infrastrukturą jako kod. Zmiany w repozytorium automatycznie synchronizują się z środowiskiem produkcyjnym.

  3. Monitoring i alerty — Prometheus + Grafana do monitorowania metryk aplikacji i infrastruktury. Ustaw alerty dla krytycznych metryk (CPU, pamięć, błędy).

  4. Load balancer — NGINX lub Traefik jako load balancer przed wieloma instancjami aplikacji. Zapewnia równomierne obciążenie i odporność na awarie.

  5. Auto-scaling — automatyczne dodawanie nowych instancji aplikacji w zależności od obciążenia (np. Kubernetes HPA lub AWS Auto Scaling).

Podsumowanie

Docker i CI/CD to standard w nowoczesnym wdrażaniu aplikacji Django. Pozwalają zachować spójność środowisk, automatyzować testy i deployment, minimalizować błędy oraz wdrażać nowe wersje aplikacji szybciej i bezpieczniej. Zacznij od prostego Dockerfile i pipeline'u CI, a z czasem rozbuduj go o staging, testy integracyjne i automatyczne release'y. Pamiętaj, że wdrożenie to proces iteracyjny — zaczynaj od prostych rozwiązań i ulepszaj je w miarę rozwoju projektu.