Jak rozwijać aplikację Django w lokalnym środowisku Kubernetes z użyciem Minikube
Styczeń 1, 2024 | #django , #localhost , #kubernetes , #python
010001
000010
110001
Kubernetes jest obecnie chyba najbardziej popularnym systemem do automatyzacji wdrażania, skalowania i zarządzania aplikacjami kontenerowymi. Jest duże prawdopodobieństwo, że aplikacja nad którą pracujesz - niezależnie od technologii - zostanie wdrożona właśnie z użyciem K8s dlatego warto poświęcić mu trochę czasu. Nie pełniąc roli DevOps-a być może nie będziesz bezpośrednio odpowiedzialny za wdrażanie serwisów na serwerze produkcyjnym ale twoje oprogramowanie musi być na to gotowe, a opanowanie tej technologi z pewnością ułatwi debugowanie i optymalizację i da Ci większą swobodę w poruszaniu się po środowiskach developerskich i stagingowych. Dlatego dzisiaj pokarzę jak wdrożyć aplikację Django na komputerze lokalnym z użyciem Minikube i co można z tym więcej zrobić.
Przygotowanie Kubernetes do pracy na localhost
Instalacja minikube i kubectl
Klaster Kubernetes jest też wbudowany w Docker Desktop (także Docker Desktop for Linux), ja jednak pracuję na Linuksie z czystym Docker Engine więc zdecydowałem się na użycie Minikube, który zresztą ma większe możliwości od wersji wbudowanej w Docker Desktop.
Instalacja jest różna w zależności od systemu operacyjnego, a poza tym dość prosta dlatego odsyłam do oficjalnej dokumentacji minikube. Podobnie z narzędziem kubectl
, które na Ubuntu można zainstalować choćby z pakietów snap
sudo snap inastall kubectl
W dalszej części zakładam, że zainstalowano Minikube i kubectl oraz, że Minikube jest wystartowane.
Dodanie modułu Ingress
Ingress to taki mechanizm w Kubernetes zapewniający zewnętrzny dostęp do usług w klastrze - routing. Ponieważ może on być realizowany za pośrednictwem różnorodnych kontrolerów Ingress - w tym NGINX Ingress Controller, Traefik, HAProxy Ingress, Istio Gateway itp. - użytkownicy mogą wybrać kontroler, który najlepiej odpowiada ich wymaganiom. W różnych środowiskach różnie się instaluje kontroler Ingress na szczęście w Minikube wystarczy go aktywować
minikube addons enable ingress
i upewnić się, że jest włączony
minikube addons list
Praca Kubernetes z lokalnymi obrazami Docker-a
Przygotowując aplikacje do publikacji na produkcji najpierw buduje się obrazy Docker-a a następnie wysyła do rejestru skąd są pobierane przez Kubernetes i wdrażane. Na localhost
chcemy pominąć ten krok i używać obrazu wygenerowanego lokalnie. Aby Kubernetes był w stanie odnaleźć ten obraz a Pod
, w definicji którego odwołano się do lokalnie zbudowanego obrazu nie przyjął po uruchomieniu statusu ImagePullBackOff
musimy zrobić dwie rzeczy.
Docker w Minikube
Gdy używasz Minikube - Kubernetes i Docker - w zależności od użytego sterownika - działają wewnątrz wirtualnej maszyny lub kontenera (minikube start --driver=docker
). Aby korzystać z lokalnych obrazów Docker-a bez ich wypychania do zdalnego rejestru, możesz ustawić swoje środowisko Docker tak, aby wskazywało na Docker w Minikube:
eval $(minikube docker-env)
Następnie, gdy zbudujesz obraz za pomocą docker build
, będzie on dostępny dla klastra Kubernetes w Minikube.
Uwaga!
Jeśli w środowisku Minikube uruchomisz kontener Docker-a z podmontowanym katalogiem hosta to takie bindowanie nie zadziała ponieważ kontener ten jest uruchomiony w maszynie wirtualnej lub wewnątrz innego kontenera.
Nie ma to natomiast wpływu na kopiowanie plików lub katalogów w trakcie budowania obrazu.
Aby cofnąć to ustawienie wystarczy zamknąć terminal albo wywołać
eval $(minikube docker-env -u)
SameNode Policy
Jeśli aplikacja działa w środowisku testowym lub deweloperskim i jest tylko jeden węzeł, można skorzystać z opcji instruującej Kubernetes aby szukał obrazu tylko na lokalnym węźle. W tym celu w definicji Pod
lub Deployment
- jak w tym przypadku trzeba dodać instrukcję imagePullPolicy: IfNotPresent
(patrz niżej), co spowoduje, że Kubernetes użyje lokalnego obrazu, jeśli jest on dostępny, i nie będzie próbował go pobrać z rejestru, chyba że go nie znajdzie.
Budowanie obrazu z projektem Django
Przykłady najlepiej obrazują przedstawiane zagadnienie zatem przejdźmy do konkretów.
W tym celu utwórz nowy projekt Django wraz z bazą danych Postgresql. Posłuży za przykład aplikacji, która zostanie wdrożona w klastrze Kubernetes.
Po utworzeniu nowego projektu Django według podanej wyżej instrukcji wraz ze zmianami, które wprowadzimy w tym artykule docelowo struktura projektu będzie wyglądać tak:
project_django/
├── app/
│ ├── manage.py
│ └── project_name/
├── assets/
│ ├── static/
│ └── media/
├── manifests/
│ ├── django-deployment.yml
│ ├── django-svc.yml
│ ├── ingress.yml
│ ├── postgres-deployment.yml
│ ├── postgres-pvc.yml
│ ├── postgres-svc.yml
│ └── media/
├── .env
├── docker-compose.override.yml
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
Zanim zbudujemy obraz aplikacji Django na podstawie pliku docker-compose.yml
uzupełnimy go o nazwę obrazu jaką chcemy mu nadać. W tym celu utworzymy plik docker-compose.override.yml
touch docker-compose.override.yml
version: '3.8'
services:
django:
image: projectdjango:1.0.0
Budujemy obraz
# nie zapomnij o wcześniejszym wykonaniu `eval $(minikube docker-env)`
docker compose build django
Polecenie to odczyta zarówno docker-compose.yml
, jak i docker-compose.override.yml
, łącząc ich konfiguracje.
Na liście obrazów oprócz obrazów k8s powinniśmy zobaczyć też nasz własny.
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
projectdjango 1.0.0 f54c2a958c4a 9 seconds ago 782MB
Teraz możemy przejść do Kubernetesa
Wrażanie projektu Django na lokalnym klastrze Kubernetes-a
Konwersja pliku .env
na sekrety Kubernetes
Z racji tego, że klaster Kubernetes może obejmować kilka maszyn fizycznych lub wirtualnych, czytanie zmiennych środowiskowych z pliku .env
mija się z celem. Dlatego też dane konfiguracyjne trzyma się w ConfigMap
a dane wrażliwe w Secret
. O ile zarówno jedne jak i drugie typy obiektów można utworzyć ręcznie, o tyle w przypadku sekretów tworzenie manifestu z wrażliwymi danymi i zapisanie go w repozytorium byłoby ewidentnym naruszeniem bezpieczeństwa. Dlatego najprostszym sposobem konwersji .env
bezpośrednio na Kubernetes Secret
jest użycie komendy
kubectl create secret generic projectdjango-secret --from-env-file=.env
i sprawdzenie czy udało się wygenerować Secret
kubectl get secret projectdjango-secret -o yaml
Manifesty Kubernetes wdrażające Django i Postgresql
mkdir ./manifests && \
touch ./manifests/postgres-pvc.yml \
./manifests/postgres-deployment.yml \
./manifests/postgres-svc.yml \
./manifests/django-deployment.yml \
./manifests/django-svc.yml \
./manifests/ingress.yml
Plik ./manifests/postgres-pvc.yml
Dane w Kubernetes - podobnie jak w Dockerze - przechowywane są w woluminach (Volumens
) nie mniej jest to mechanizm nieco bardziej skomplikowany niż w Dockerze. Poniżej zdefiniowano żądanie o magazyn danych (PersistentVolumeClaim
, PVC) - o pojemności 244Mi (mebibajtów) co daje w zaokrągleniu około 256MB (megabajtów). Żądanie PVC
jest zwykle powiązane z magazynem ( PersistentVolume
, PV). Rodzaj tego magazynu zależy od parametru storageClassName
, którego nie ma w przykładzie poniżej ponieważ korzysta on po prostu ze standardowego ustawienia.
W środowisku Minikube, dynamiczne tworzenie wolumenów PersistentVolume
, jest zazwyczaj skonfigurowane domyślnie. Oznacza to, że wystarczy utworzyć żądanie PersistentVolumeClaim
, a Minikube automatycznie stworzy odpowiedni PersistentVolume
dla tego PVC, jeśli nie istnieje już dostępny PV, który spełniałby wymagania PVC.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: projectdjango-pg-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 244Mi
Plik ./manifests/postgres-deployment.yml
Etykieta postgres
połączy Pod
-a i ReplicaSet
, które zostaną automatycznie utworzone po zastosowaniu Deployment
-u, a także serwis przedstawiony niżej. Wartości zmiennych środowiskowych przechowujących dane wrażliwe są pobierane z wcześniej wygenerowanego obiektu Secret
. Na końcu został użyty zadeklarowany wyżej wolumin na dane bazy Postgresql.
apiVersion: apps/v1
kind: Deployment
metadata:
name: projectdjango-pg-deployment
spec:
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16.1-alpine3.19
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: POSTGRES_DB
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: POSTGRES_PASSWORD
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: projectdjango-pg-pvc
Powyżej
Plik ./manifests/postgres-svc.yml
Usługa (Service
) umożliwia dostęp do Pod
-a poprzez sieć. Dzięki niemu aplikacja Django będzie miała połączenie z bazą danych.
apiVersion: v1
kind: Service
metadata:
name: projectdjango-pg-service
spec:
selector:
app: postgres
ports:
- protocol: TCP
port: 5432
targetPort: 5432
Plik ./manifests/django-deployment.yml
W tym pliku należy przede wszystkim zwrócić uwagę na to, że kontener zostanie utworzony na podstawie lokalnego obrazu projectdjango:1.0.0
przez co koniecznym było dodanie też instrukcji imagePullPolicy: IfNotPresent
żeby Kubernetes był wstanie odnaleźć ścieżkę do tego obrazu. Jako wartość zmiennej środowiskowej POSTGRES_HOST
została podana nazwa serwisu dającego dostęp do Postgres-a. W chwili wystartowania Pod
-a wywoływana jest komenda uruchamiająca serwer developerski Django. Na produkcji Django serwowane jest za pośrednictwem Gunicorn-a, uWSGI albo inny serwr wsgi, ale na potrzeby dewelopmentu to wystarczy.
apiVersion: apps/v1
kind: Deployment
metadata:
name: projectdjango-dj-deployment
spec:
selector:
matchLabels:
app: django
template:
metadata:
labels:
app: django
spec:
containers:
- name: django
image: projectdjango:1.0.0
imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args: ["-c", "python manage.py runserver 0.0.0.0:8000"]
ports:
- containerPort: 8000
env:
- name: DJANGO_SECRET_KEY
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: DJANGO_SECRET_KEY
- name: POSTGRES_HOST
value: projectdjango-pg-service
- name: POSTGRES_PORT
value: "5432"
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: POSTGRES_DB
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: projectdjango-secret
key: POSTGRES_PASSWORD
Plik ./manifests/django-svc.yml
Podobnie jak Postgres także Django jest wyeksponowane w sieci. Service
z Deployment
"połączony" jest etykietą django
.
apiVersion: v1
kind: Service
metadata:
name: projectdjango-dj-service
spec:
selector:
app: django
ports:
- protocol: TCP
port: 8000
targetPort: 8000
Plik ./manifests/ingress.yml
W Kubernetes, Ingress to mechanizm, który umożliwia zarządzanie dostępem do usług (Services
) w klastrze poprzez definiowanie reguł routingu na poziomie warstwy aplikacji. Ingress działa jako kontroler, który zarządza ruchem HTTP i HTTPS do aplikacji wewnątrz klastra na podstawie reguł zdefiniowanych w zasobach Ingress.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: projectdjango-ingress
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: projectdjango-dj-service
port:
number: 8000
Aplikacja manifestów Kubernetes
Aplikujemy wszystkie manifesty znajdujące się w katalogu ./manifests
kubectl apply -f ./manifests/
I sprawdzamy co zostało utworzone
kubectl get all
NAME READY STATUS RESTARTS AGE
pod/projectdjango-dj-deployment-675b5bdfc8-bv4z5 1/1 Running 0 10s
pod/projectdjango-pg-deployment-6f5f94df79-zs7xg 1/1 Running 0 10s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 24d
service/projectdjango-dj-service ClusterIP 10.103.145.97 <none> 8000/TCP 10s
service/projectdjango-pg-service ClusterIP 10.106.200.113 <none> 5432/TCP 10s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/projectdjango-dj-deployment 1/1 1 1 10s
deployment.apps/projectdjango-pg-deployment 1/1 1 1 10s
NAME DESIRED CURRENT READY AGE
replicaset.apps/projectdjango-dj-deployment-675b5bdfc8 1 1 1 10s
replicaset.apps/projectdjango-pg-deployment-6f5f94df79 1 1 1 10s
Sprawdź czy został utworzony PVC
i PV
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
projectdjango-pg-pvc Bound pvc-de72bf3c-bcff-43cf-80b2-bdb1dc3c9eb1 1Gi RWO standard 24s
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-de72bf3c-bcff-43cf-80b2-bdb1dc3c9eb1 1Gi RWO Delete Bound default/projectdjango-pg-pvc standard 117s
Sprawdzamy czy Ingress otrzymał już adres IP
kubectl get ingress projectdjango-ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
projectdjango-ingress nginx * 192.168.49.2 80 53s
Jeśli w polu ADDRESS
jest pusta wartość należy poczekać i ponowić sprawdzenie gdyż nadanie IP chwilę trwa.
Otwórz przeglądarkę i pod adresem http://192.168.49.2/
(w Twoim przypadku to oczywiście może być inny adres IP) powinieneś zobaczyć odpalony projekt Django.
Praca z Django w Kubernetes
Jeśli korzystałeś z mojego przykładowego projektu to przywitał Cię błąd konfiguracji Django Invalid HTTP_HOST header
. Jest to łatwe do naprawienia ale pracochłonne ponieważ każda zmiana w plikach wiąże się z koniecznością wykonania paru dodatkowych czynności.
Wprowadzanie zmian w kodzie aplikacji
Po zmianie w pliku ./app/project_name/settings.py
obejmującej modyfikację zmiennej ALLOWED_HOSTS = ["*"]
Powinniśmy jeszcze
Wdrażanie zmian w kodzie
Zmienić numer wersji obrazu w pliku
docker-compose.override.yml
oraz w pliku./manifests/django.yml
na1.0.1
Przebudować obraz
docker compose build django
Zaaplikować zmiany
kubectl apply -f ./manifests/django.yml
Taka procedura jest jak najbardziej właściwa. Na koniec jeszcze warto śledzić postęp aktualizacji.
kubectl rollout status deployment/projectdjango-dj-deployment
Nie mniej w trakcie developmentu nie jest to najwygodniejsze rozwiązanie.
Aktualizacja podów poprzez ich usunięcie
Alternatywnie możemy pominąć modyfikowania tagu obrazu i wykonać następujące kroki
Przebudować obraz
docker compose build django
Sprawdzić nazwy pod-ów
kubectl get pods NAME READY STATUS RESTARTS AGE projectdjango-dj-deployment-77f896db7d-swcnk 1/1 Running 0 19s projectdjango-pg-deployment-6f5f94df79-mxsp7 1/1 Running 0 135m
Usunąć pod-a z Django
kubectl delete pod projectdjango-dj-deployment-77f896db7d-swcnk
Na miejsce starego poda automatycznie zostanie utworzony nowy ale będzie on bazował już na nowo wygenerowanym obrazie nawet jak nie zmienimy mu tag-a
To wciąż nie jest wygodne rozwiązanie.
Montowanie plików hosta
W Docker Compose jest proste rozwiązanie na tego typu okoliczność polegające na utworzeniu woluminu typu bind czyli inaczej mówiąc podmontowaniu katalogu z kodem pod katalog wewnątrz kontenera. W ten sposób każda zmiana w kodzie jest natychmiast odzwierciedlona w kontenerze. W Minikube też mamy taką możliwość ale wymaga ona nieco pracy poniważ, jak już wiemy kontenery Kubernetesa są zamknięte w maszynie wirtualnej lub w kontenerze Dockera.
Użyjemy do tego hostPath (lokalne woluminy), które pozwalają na montowanie katalogów bezpośrednio z hosta VM. Jest to prostsze niż konfiguracja NFS czy Cloud Storage (patrz niżej), ale działa tylko z Minikube i nie jest zalecane dla środowisk produkcyjnych. Na komputerze lokalnym jest to jednak rozwiązanie wygodne i elastyczne i użyjemy go zarówno do podmontowania kodu aplikacji, ale też jako sposób na współdzielenie plików statycznych i mediów.
Uwaga!
W Kubernetes, do przechowywania plików wspólnych dla wszystkich podów, takich jak np. media w projekcie Django, zazwyczaj korzysta się z wolumenów. Istnieje kilka podejść, które można wykorzystać w zależności od potrzeb i środowiska. Zazwyczaj definiuje się Persistent Volume (PV), który wskazuje na fizyczne miejsce przechowywania danych (np. Network File Systems (NFS), cloud storage jak AWS S3, Google Cloud Storage, Azure Blob Storage) oraz Persistent Volume Claim (PVC) czyli żądanie dostępu do tych zasobów.
Mamy zatem do wykonania dwie akcje:
- Podmontowanie katalogu hosta do katalogu wewnątrz Minikube
- Podmontowanie katalogu Minikube do kontenera wewnątrz
Pod-a
Montowanie katalogu hosta do katalogu wewnątrz Minikube
Najpierw musimy wejść do VM Minikube
minikube ssh
Wewnątrz Minikube tworzymy katalogi i ustawiamy im prawa do zapisu i odczytu. W środowisku lokalnym możemy sobie pozwolić na nadanie uprawnień 777.
mkdir -p /home/docker/project_django/app \
&& mkdir -p /home/docker/project_django/assets/static \
&& mkdir -p /home/docker/project_django/assets/collected_static \
&& mkdir -p /home/docker/project_django/assets/media
sudo chmod -R 777 /home/docker/project_django
W nowym oknie terminala montujemy katalog w którym znajduje się kod naszej aplikacji Django
minikube mount ./app:/home/docker/project_django/app
Jeśli pojawi się błąd z połączeniem może to być spowodowane ustawieniami zapory sieciowej (firewall) na hoście, która blokuje połączenie.
❌ Exiting due to GUEST_MOUNT_COULD_NOT_CONNECT: mount could not connect: /bin/bash -c "sudo mount -t 9p -o dfltgid=$(grep ^docker: /etc/group | cut -d: -f3),dfltuid=$(id -u docker),msize=262144,port=34869,trans=tcp,version=9p2000.L 192.168.49.1 /home/docker/project_django/app": Process exited with status 32
W moim przypadku był to port 34869, który Minikube używa do montowania.
sudo ufw allow 34869
sudo ufw status
Otworzyłem ten port i ponowiłem próbę zamontowania katalogu.
minikube mount --port=34869 ./app:/home/docker/project_django/app
📁 Mounting host path ./app into VM as /home/docker/project_django/app ...
▪ Mount type: 9p
▪ User ID: docker
▪ Group ID: docker
▪ Version: 9p2000.L
▪ Message Size: 262144
▪ Options: map[]
▪ Bind Address: 192.168.49.1:34869
🚀 Userspace file server: ufs starting
✅ Successfully mounted ./app to /home/docker/project_django/app
📌 NOTE: This process must stay alive for the mount to be accessible ...
Proces montowania jest tak długo podtrzymywany, jak długo terminal w którym to wykonaliśmy jest otwarty i nie wciśniemy kombinacji klawiszy Ctl + C
.
Możemy ponownie wejść do Minikube i sprawdzić czy montowanie się powiodło
ls /home/docker/project_django/app
Uwaga!
Po utworzeniu katalogu /home/docker/project_django/app
w Minikube dobrym pomysłem - jeszcze przed podmontowaniem katalogu ./app
z hosta - jest po prostu skopiowanie tam plików z tego katalogu.
scp -r -i ~/.minikube/machines/minikube/id_rsa \
./app docker@$(minikube ip):/home/docker/project_django
Dzięki czemu będziemy mogli wystartować projekt w Kubernetes nawet jak nie podmontujemy katalogu hosta. Inaczej pod z aplikacją Django wysypie się i zobaczymy nic nie mówiący Error
. Będziemy musieli domyślić się, że nie ma plików projektu i serwer Django nie może wystartować. Dostaniemy projekt przed zmianami ale to jest lepsze niż nic nie mówiący błąd.
Montowanie katalogu Minikube do kontenera wewnątrz Pod-a
Należy zmodyfikować manifest Deployment-u kontenera z aplikacją Django ./manifests/django-deployment.yml
.
Znaczną część kodu została wykropkowana aby lepiej było widać co zostało dodane do manifestu
apiVersion: apps/v1
kind: Deployment
metadata:
name: projectdjango-dj-deployment
spec:
selector:
...
template:
...
spec:
containers:
- name: django
...
volumeMounts:
- name: code-volume
mountPath: /src
- name: media-storage
mountPath: /assets/media
- name: static-storage
mountPath: /assets/static
- name: collected-static-storage
mountPath: /assets/collected_static
volumes:
- name: code-volume
hostPath:
path: /home/docker/project_django/app
type: Directory
- name: media-storage
hostPath:
path: /home/docker/project_django/assets/media
type: Directory
- name: static-storage
hostPath:
path: /home/docker/project_django/assets/static
type: Directory
- name: collected-static-storage
hostPath:
path: /home/docker/project_django/assets/collected_static
type: Directory
Po rozszerzeniu manifestu Deployment-u i modyfikacji ustawień projektu Django koniecznym jest jeszcze zastosowanie zmian.
kubectl apply -f ./manifests
Teraz po usunięciu gwiazdki z ustawienia ALLOWED_HOSTS = ["*"]
i przeładowaniu widoku w przeglądarce (http://192.168.49.2/
) powinniśmy natychmiast ponownie zobaczyć błąd zgłaszany przez Django tak jak i każdą inną zmianę.
Co do plików statycznych i mediów to wrócimy do nich za chwilę.
Wykonywanie operacji bezpośrednio w kontenerze
Do kontenerów wewnątrz pod-ów Kubernetesa można wejść. Należy jedynie sprawdzić nazwę poda, który nas interesuje.
kubectl exec -it projectdjango-dj-deployment-77f896db7d-qbb7p -- sh
Będąc w kontenerze możemy w nim wykonać migracje Django python manage.py migrate
ale też przekopiować do jednego katalogu wszystkie pliki statyczne Django, co pozwoli nam sprawdzić czy pliki trafiły do podmontowanego katalogu.
python manage.py collectstatic
128 static files copied to '/collected_static'.
Po wyjściu z kontenera wchodzimy ponownie do Minikube minikube ssh
i sprawdzamy czy pliki znajdują się tam, gdzie się ich spodziewamy.
ls /home/docker/project_django/assets/collected_static/
Po skopiowaniu jednego z obrazków do katalogu z mediami
cp /home/docker/project_django/assets/collected_static/admin/img/icon-alert.svg \
/home/docker/project_django/assets/media
Mamy też możliwość sprawdzenia czy plik ten zobaczymy w przeglądarce http://192.168.49.2/media/icon-alert.svg
.
Podsumowanie
Rozwój aplikacji w Kubernetes na komputerze lokalnym nie jest może najwygodniejszym sposobem pracy nie mniej pozwala:
- lepiej poznać środowisko K8s i oswoić się z nim,
- dostosować projekt do wymagań Kubernetes,
- radzić sobie z problemami, z którymi można się później spotkać na produkcji.
Przedstawiony w tym artykule proof of concept nie wyczerpuje tematu. Jeśli chcesz wdrożyć w Minikube bardziej rozbudowany projekt Django z Celery i frontendem w Vue.js, być może pomocny okaże się artykuł "Setting up a Django project in Kubernetes with minikube" Briana Caffey.
Z kolei Alex Garnett na łamach DigitalOcean w artykule How To Use minikube for Local Kubernetes Development and Testing uczy jak monitorować i testować aplikacje.
Reset
Na koniec krótko jeszcze o czyszczeniu lub resetowaniu klastra Minikube
Możemy zdecydować się na usunięcie po prostu całego klastra
minikube delete
Jeśli jednak nie chcemy tego robić mamy kilka kroków do wykonania
kubectl delete -f ./manifests/
kubectl get all
kubectl get pvc
kubectl get ingress
kubectl get secret
Ostanie z poleceń ujawniło że sekrety nie zostały usunięte. Dlatego musimy to zrobić ręcznie.
kubectl delete projectdjango-secret
Pozostają jeszcze obiekty Docker-a do usunięcia
docker compose down -v
docker rmi projectdjango:1.0.0