Deploying Django with Kubernetes
Introduction Link to heading
Kubernetes is a great platform to run your applications on. There are plenty of blogs out there that go into why Kubernetes is great, so go read some if you haven’t already. One of the many great fits is a Django application. Here, we’ll run through the very basics.
We’ll deploy this demonstration to Google Cloud Platform as this provides a good foundation to spin up a Kubernetes cluster and required ancillaries. All of the kubectl
commands are ambiguous to where you’ve installed Kubernetes.
Prerequisites Link to heading
First, pull the demo repository. This contains some manifest templates, a couple of Dockerfiles
and a simple Django guestbook, written by Bill Prin, who was influential in me this post.
git clone https://github.com/joedborg/django-kubernetes-demo.git
You’ll need to have kubectl
and gcloud
installed. You’ll also need a GKE
account if you want to follow this guide step-by-step; you can do this here.
Linux Link to heading
snap install kubectl --classic
See here for instructions
on installing gcloud
.
Mac Link to heading
Assuming you have Homebrew installed.
brew install kubectl
brew install google-cloud-sdk
Setting up GKE Link to heading
Update Link to heading
Make sure gcloud
is up-to-date.
gcloud components update
Create a Project Link to heading
If you’ve not already setup one, we need to create a project. We must call it something unique. For
this blog, I’ll call it guestbook-jb
.
If you’ve never used to gcloud
before, you need to initialise it. You can
follow the steps to create a new project.
gcloud init
Otherwise, do the following.
gcloud projects create guestbook-jb
Then we need to set it as the project ID.
gcloud config set project guestbook-jb
Start a Cluster Link to heading
Now that we have gcloud
setup, we can start a Kubernetes cluster.
gcloud container clusters create guestbook --scopes "userinfo-email","cloud-platform","datastore","default" --num-nodes 2
The --scopes
flag specifies which other Google Cloud APIs your cluster can
utilise. We’ll only use 2 nodes for this demonstration to keep costs sane.
We then want to copy the cluster’s config into our kubectl
.
gcloud container clusters get-credentials guestbook
We can then test by looking for our 2 nodes.
kubectl get nodes
Django Stack on Kubernetes Link to heading
We need generate completed yaml
manifest files. Make sure you’re in the repository directory.
make templates
Secrets Link to heading
Kubernetes has a built in secrets manager which allows you to store secrets and then inject them into pods via different means.
Having generated the templates, the file secrets.yaml
will have been created with a randomly generated password. This password will then be injected into the Django and Postgres pods.
To apply these secrets.
kubectl apply -f ./secrets.yaml
Redis Link to heading
We’re going to use Redis to cache the amount of page views.
kubectl apply -f ./redis.yaml
Postgres Link to heading
Postgres is a bit more complex because we need a persistent volume to store our data. Fortunately, Kubernetes also has a built in component to handle this too.
First of all, we need to crate a volume in GCP.
gcloud compute disks create pg-data --size 200GB
This is then tied to the database by Kubernetes with the persistentvolume
and persistentvolumeclaim
directive in the postgres.yaml
manifest.
To handle Kubernetes secrets, we’ve got a very simple, custom Docker image in the postgres
directory. This needs to be built and pushed to our registry.
cd postgres/
docker build . --tag gcr.io/$(gcloud config list project --format="value(core.project)")/postgres-pw:v1
gcloud docker -- push gcr.io/$(gcloud config list project --format="value(core.project)")/postgres-pw:v1
Finally, we can deploy Postgres.
cd ../
kubectl apply -f ./postgres.yaml
Note there may been some errors thrown regarding persistent volume claims, this should clear up in a minute or less; it’s a race condition within Kubernetes.
Django Link to heading
We’re finally ready to deploy Django. The manifest also defines a load balancer which will act as Nginx or Apache would in a legacy deployment.
First, we need to build and push the initial Docker image. The Dockerfile
for our guestbook is generic enough to be used with most basic Django deployments. You will, however, need to change the settings.py
to get the correct username and password from the mounted secrets directory. Open settings.py
to see how this handled.
cd guestbook/
docker build . --tag gcr.io/$(gcloud config list project --format="value(core.project)")/guestbook:v1
gcloud docker -- push gcr.io/$(gcloud config list project --format="value(core.project)")/guestbook:v1
We can then deploy.
cd ../
kubectl apply -f guestbook.yaml
And run migrations.
kubectl exec $(kubectl get pods | grep guestbook | awk '{ print $1 }') python ./manage.py migrate
We can then get the public IP address from the load balancer.
kubectl get services
You should then be able to connect to that IP address and see your Django site!
Operating the Deployment Link to heading
This is all great, but hasn’t really bought us much over a legacy deployment. Let’s explore a couple of very simple things Kubernetes buys us straight away.
Rolling out an update Link to heading
We can roll out updates to our Django application. These roll outs are zero downtime and will stop if there is an issue that means that Django won’t start.
First off make a change, then build and push the Docker image. Pay attention to change the version tag.
cd guestbook/
docker build . --tag gcr.io/$(gcloud config list project --format="value(core.project)")/guestbook:v2
gcloud docker -- push gcr.io/$(gcloud config list project --format="value(core.project)")/guestbook:v2
Now we need to tell Kubernetes to use the new image. This will create a new pod and only swap if the container inside starts (i.e. Django starts).
kubectl set image deployment/guestbook guestbook=gcr.io/$(gcloud config list project --format="value(core.project)")/guestbook:v2
We can see if the roll out is working.
kubectl rollout status deployment/guestbook
You can read more about roll outs here.
Scaling Link to heading
Another thing we might want to do is scale our Django application.
We can either do that manually.
kubectl scale deployment guestbook --replicas=3
Or we can set criteria for automatic scaling.
kubectl autoscale deployment guestbook --min=1 --max=5 --cpu-percent=80
You can read more about scaling here.
Cleaning Up Link to heading
If you’ve just run through this as a demonstration, I advise you clean up the cluster and storage to keep costs down.
gcloud container clusters delete guestbook
gcloud compute disks delete pg-data