Introduction
In my previous post I described how to deploy a django restframework app to a Kubernetes cluster. However, I used the ‘runserver’ command which is not suitable for production. Some research taught that Gunicorn is a far better choice on production, and in this article I will describe the rather simple steps to deploy this app with Gunicorn.
The requirements file
Add ‘gunicorn’ to the requirements.txt file:
django
djangorestframework
psycopg2
gunicorn
Now run:
pip install -r requirements.txt
You should do this in your virtual python environment of course.
The shellscript
If you are following along with our previous project, you will have an entrypoint.sh shellscript. Change this as follows:
#!/bin/bash
python manage.py migrate
echo "from django.contrib.auth.models import User; User.objects.create_superuser('$DJANGO_SUPERUSER_USERNAME','$DJANGO_SUPER_USER_EMAIL','$DJANGO_SUPERUSER_PASSWORD')" | python manage.py shell
gunicorn --bind :8000 --workers 3 --threads 2 --timeout 90 webevents.wsgi
As you can see only the last line has changed. I will explain the arguments:
- bind: the port to bind to, in our case 8000
- workers: the number of worker processes to handle the requests
- threads: the number of threads per worker
- timeout: workers silent for more than this many seconds are killed and restarted.
Serving static files
When working on this, I found out that gunicorn does not serve static files out of the box. For that we need to change our urls file in the webevents directory as follows:
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import path, include
urlpatterns=[
path('admin/', admin.site.urls),
path('', include('eventsapi.urls')),
]
urlpatterns+=staticfiles_urlpatterns()
We just add the staticfiles to our url patterns. Doing that ensures we can see the static files.
If you are in Linux or MacOS you should now be able to run it, if you are on Windows you have no such luck since Gunicorn does not run on Windows
Dockerize!
If you have followed along with our previous project, you also have built a Dockerfile. Open a terminal or commandline in your project and type:
docker build -t <your hubusername>/webeventspython:latest .
Make sure Docker/Docker desktop is running
After this has finished succesfully, you can push it to the hub:
docker push <your hubusername>/webeventspython:latest
Depending on your internetspeed, this can take some minutes
Deploying it to your local Kubernetes
For this you need to have a local kubernetes cluster running, I myself prefer minikube.
If you are using minikube, type in your terminal or commandline:
minikube start
In your project go the kubernetes folder and open the web-deployment.yaml file and change the image tag to this:
image: <your hubusername>/webeventspython:latest
Deploying the database
Open a terminal or commandline in your kubernetes directory and type the following (that is, if you are still using our project):
kubectl apply -f db-configmap.yaml
kubectl apply -f db-persistent-volume.yaml
kubectl apply -f db-persistent-volume-claim.yaml
kubectl apply -f db-deployment.yaml
kubectl apply -f db-service.yaml
This will deploy the postgres database which we will need for our API.
Deploying the API
In the same terminal type:
kubectl apply -f web-deployment.yaml
kubectl apply -f web-service.yaml
Time to test
If you are using minikube you can now type:
minikube service web-service
A web browser will now open. Add ‘/admin’ to URL in the address bar, enter your credentials, and you can see our API is still working
Conclusion
As you can see, changing from ‘runserver’ to ‘gunicorn’ is not very hard. From the documentation I understand that gunicorn can be used in production, however it is often highly recommended to put an nginx proxy in front of it, but this is for another post.