Inicjalizacja projektu Django w kontenerze Docker-a
Listopad 28, 2023 | #docker , #django , #python
010100
001100
100000
Jeśli chcesz szybko zainicjować nowy projekt Django od razu w kontenerze to możesz skorzystać z przepisu, który znajdziesz na awesome-compose/official-documentation-samples/django/ W moim artykule podążam za przedstawionymi tam instrukcjami ale jest kilka różnic.
- Użyłem [[Wykorzystanie miejsca na dysku w pracy z Docker#Główne typy obrazów Docker, biorąc pod uwagę ich wielkość|lekkich obrazów alpine]] do utworzenia kontenerów z projektem Django oraz Postgresql
- Dodałem użytkownika, który nie jest root-em (non root user)
Utwórzmy nowy katalog na potrzeby projektu Django ./project_django
i wejdźmy do niego.
W katalogu projektu utworzymy kilka plików i katalogów. Docelowo struktura projektu będzie wyglądała następująco
project_django/
├── app/
│ ├── manage.py
│ └── project_name/
├── assets/
│ ├── static/
│ └── media/
├── .env
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
Utwórzmy pliki i katalogi
touch .env Dockerfile requirements.txt docker-compose.yml
mkdir ./app && mkdir -p ./assets/static && mkdir -p ./assets/media
Plik .env
zawiera kilka zmiennych przechowujących wrażliwe dane. Wyjątkiem jest tu USER_UID
przechowujący identyfikator bieżącego użytkownika hosta. Zmienna ta jest nam potrzebna po to aby użytkownik w kontenerze Docker-a mógł zapisywać pliki w podmontowanych katalogach hosta.
Wartość UID można odczytać w systemie linuks wywołując
id -u
USER_UID=1000
# Django
# ------------------------------------------------------------------------------
DJANGO_SECRET_KEY=change-me
# PostgreSQL
# ------------------------------------------------------------------------------
POSTGRES_DB=dbname
POSTGRES_USER=dbuser
POSTGRES_PASSWORD=dbpass
Plik Dockerfile
FROM python:3.12.1-alpine3.19
# Zmienne środowiskowe wymagane przez Django
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Zdefiniowanie zmiennej przechowującej
# ścieżkę do katalogu domowego
ENV HOME=/src
# Domyślna nazwa użytkownika i grupy oraz wartości UID i GID
# Można je nadpisać przekazując odpowiednie parametry
ARG USERNAME=default
ARG GROUPNAME=$USERNAME
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Utworzenie grupy i użytkownika o tej samej nazwie
RUN addgroup -g ${USER_GID} ${GROUPNAME} \
&& adduser -D ${USERNAME} -G ${GROUPNAME} -u ${USER_UID} -h ${HOME} \
&& mkdir -p /etc/sudoers.d \
&& echo "${USERNAME} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${USERNAME} \
&& chmod 0440 /etc/sudoers.d/${USERNAME}
# Instalacja zależności wymaganych przez Postgresql
RUN apk update \
&& apk add --no-cache \
build-base \
musl-dev \
postgresql-dev \
python3-dev \
&& pip install --upgrade pip
# Ustawienie katalogu roboczego na katalog domowy użytkownika
WORKDIR ${HOME}
# Skopiowanie pliku z zależnościami python i ich instalacha
COPY ./requirements.txt ${HOME}/requirements.txt
RUN pip install -r requirements.txt
# Skopiowanie kodu aplikacji do katalogu domowego
COPY ./app ${HOME}
# Utworzenie katalogów na pliki statyczne i media oraz
# zmiana właściciela a tym samym uprawnień do wszystkich plików
# w katalogu domowym i plików statycznych
RUN mkdir -p /assets/static \
&& mkdir -p /assets/collected_static \
&& mkdir -p /assets/media \
&& chown -R ${USERNAME}:${GROUPNAME} ${HOME} \
&& chown -R ${USERNAME}:${GROUPNAME} /assets
# Ustawienie użytkownika
USER ${USERNAME}
Plik requirements.txt
Django>=5.0
psycopg2
Plik docker-compose.yml
version: '3.8'
services:
postgres:
image: postgres:16.1-alpine3.19
command: postgres -c log_statement=all
volumes:
- postgres_volume:/var/lib/postgresql/data
networks:
- internal_network
ports:
- "5432:5432"
env_file:
- ./.env
django:
build:
context: .
args:
USER_UID: ${USER_UID:-1000}
depends_on:
- postgres
command: python manage.py runserver 0.0.0.0:8000
networks:
- internal_network
ports:
- "8000:8000"
env_file:
- ./.env
environment:
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
volumes:
- ./app:/src
- ./assets/static:/assets/static
- ./assets/media:/assets/media
volumes:
postgres_volume:
networks:
internal_network:
Katalog ./app
na hoście jest podpięty pod katalog /src
wewnątrz kontenera. To w nim znajdą się pliki projektu, który zaraz zostanie wygenerowany.
Są też zbindowane dwa katalogi hosta z plikami statycznymi i mediami
Utworzenie projektu Django
docker compose run --rm django django-admin startproject project_name .
Powyższa instrukcja zbudowała obraz na podstawie pliku Dockerfile
i stworzyła na jego podstawie kontener, w którym została odpalona komenda Django tworząca nowy projekt. W katalogu projektu zostały utworzone pliki projektu tj. plik manage.py
i katalog project_name
wraz z zawartością.
Ponieważ zdefiniowaliśmy użytkownika (non root
) z uprawnieniami bieżącego użytkownika hosta nie musimy zmieniać uprawnień wygenerowanych plików.
Zmiany w konfiguracji projektu Django
Django oferuje ogromne możliwości konfiguracji, ale ten artykuł nie jest o setupowaniu Django - więc zmienimy tylko dwie rzeczy,
- Konfigurację bazy danych w
./app/project_name/settings.py
w projekcie Django. W końcu zdecydowaliśmy się na Postgresa
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ.get('POSTGRES_DB', ''),
'USER': os.environ.get('POSTGRES_USER', ''),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD', ''),
'HOST': os.environ.get('POSTGRES_HOST', ''),
'PORT': int(os.environ.get('POSTGRES_PORT', '')),
}
}
- Ustawienia dotyczące plików statycznych i mediów.
w pliku ./app/project_name/settings.py
# Path /assets/static
STATICFILES_DIRS = (BASE_DIR.parent / "assets/static",)
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
)
# Path /assets/collect_static
STATIC_ROOT = BASE_DIR.parent / "assets/collected_static"
STATIC_URL = "static/"
# Path /assets/media
MEDIA_ROOT = BASE_DIR.parent / "assets/media"
MEDIA_URL = "/media/"
I w pliku ./app/project_name/urls.py
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Uruchomienie projektu Django
Po uruchomieniu sprawdzamy czy w logach nie ma błędów.
docker compose up
Jeśli projekt działa pod adresem localhost:8000 oznacza to, że mamy poprawnie zainicjowany w kontenerze Docker nowy project Django, z którym od razu możemy pracować.
Upewnijmy się jeszcze, że katalogi ze plikami statycznymi i mediami zostały poprawnie podmontowane. W tym celu dodaj do katalogu ./assets/media
jakiś obrazek np. o nazwie example.jpg
i sprawdź czy jest widoczny pod adresem localhost:8000/media/example.jpg. Analogicznie zrób ze static-ami.