SP6MI

Krótkofalarstwo & DevOps

Django + Docker

W wielkim skrócie jak uruchomić deweloperską wersję aplikacji Django w kontenerze docker’a

Wymagania

Kod przetestowany pod najnowszym Ubuntu, Docker version 27.1.1, build 6312585, Python 3.10, Django 5.1. W moim przypadku, docker działa na wydzielonym hoście w sieci lokalnej z adresem 192.168.0.73.

Aplikacja Django

Pierwszym krokiem jest przygotowanie środowiska, w moim przypadku venv na bazie Python’a 3.10

mkdir Projekty
cd Projekty
python -m venv .env
source .env/bin/activate

Mając aktywne środowisko możemy przystąpić do instalacji zależności oraz tworzenia projektu django (pakiety sqlalchemy i gunicorn są opcjonalne na tym etapie)

cat <<EOF > requirements.txt
django
sqlalchemy
gunicorn
EOF

pip install --no-cache-dir -r requirements.txt

Teraz tworzenie projektu

django-admin startproject docker_test

powyższe polecenie tworzy sam projekt, który niespecjalnie jest w stanie coś zrobić, ale i na tym etapie możemy sprawdzić czy serwer testowy uruchomi się poprawnie i będziemy mogli zobaczyć powitalną stronę projektu django.

Teraz wystarczy otworzyć w dowolnej przeglądarce adres 127.0.0.1:8000 aby zobaczyć stronę

cd docker_test
python manage.py runserver

Docker

Skoro mamy działającą podstawową funkcjonalność django zajmijmy się konteneryzacją i dockerem. Poniżej przedstawię najprostszą działającą konfigurację z pominięciem docker compose, nginix, certyfikatów czy połączeń SSL. Do celów edukacyjnych wystarczy na dobry początek.

Pamiętaj nie stosuj tych rozwiązań w kodzie produkcyjnym

Na wstępie stwórzmy plik Dockerfile.

FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

Opis pliku w wielkim skrócie:

  • FROM python:3.11: Specyfikacja obrazu bazowego dla obrazu dockerowego.
  • WORKDIR /app: Ustawia katalog roboczy wewnątrz dockera na /app. Folder jest tworzony, jeśli nie istnieje, to wewnątrz tego folderu będą wykonywane wszystkie następne polecenia.
  • COPY requirements.txt .: Kopiuje requirements.txt z folderu projektu do /app.
  • RUN pip install --no-cache-dir -r requirements.txt: Instaluje zależności pythonowe bazując na zawartości pliku requirements.txt
  • COPY . .: Kopiuje cały folder projektu do folderu /app w obrazie dockera
  • EXPOSE 8000: Informuje dockera, że aplikacja będzie nasłuchiwać na porcie 8000. Jednak nie udostępnia tego portu do hosta
  • CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]: Finalnie instrukcja domyślnego polecenia, kiedy kontener jest uruchamiany.

Zanim zbudujemy i uruchomimy kontener musimy jeszcze zmienić jedną wartość w konfiguracji projektu django. W pliku settings.py w sekcji ALLOWED_HOSTS musimy podać jako element listy '*', także linia powinna wyglądać następująco

PAMIĘTAJCIE TAKA WARTOŚĆ MOŻE BYĆ UŻYWANA TYLKO DO CELÓW DEVELOPERSKICH/TESTOWYCH

# Adres 192.168.0.73 jest adresem mojego mini serwera na którym mam dockera,
# w Waszym przypadku będzie to inny adres, powinno również działać
# jak lista będzie zawierać jeden element '*'
ALLOWED_HOSTS = ['192.168.0.73', '127.0.0.1', 'localhost']

Zakładając, że plik Dockerfile jest w tym samym folderze co utworzony przez nas projekt django, możemy wykonać teraz polecenie i zbudować obraz

# Budowanie obrazu dockera
docker build -t docker_test .

#Uruchamianie kontenera
docker run -d -p 8000:8000 docker_test

Teraz wystarczy otworzyć w przeglądarce adres hosta dockera (w moim przypadku 192.168.0.73:800 i powinniśmy otrzymać w odpowiedzi działającą stronę django

Podsumowanie

W sieci znajduje się mnóstwo opisów jak uzyskać ten sam efekt, niestety większość z nich dokłada sporą ilość dodatkowych (moim zdaniem zbędnych na początkowym etapie) funkcjonalności i operacji do wykonania. Następnym krokiem, który postaram się opisać jest połączenie aplikacji django w kontenerze z bazą danych hostowaną przez inny kontener, oraz użycie nginx.

Jeszcze jedna uwaga, za każdym razem jak zmieni się kod django, należy przebudować obraz dockera i ponownie go uruchomić.