Deploy Django app in docker container with auto reload

1. Intro

This post is to take notes about how I set up auto reload Django environment in docker.

I am learning Django recently, but I don't want to install the Django directly on my vps. As you know, the installation of Django will change the environment a lot, which is not friendly for maintenance. So I will try to keep every thing inside a container.

Unfortunately, the author of the docker image didn't make the Django automatically reload when changing the codes. That's why I did the following things.

With the help of Git hook, it is quite easy to realize it automatically. The strategy is shown as the following figure:
django-git.png

Every time when new commit is pushed to the git server, the git hook will deploy the source files to the mapped volume of the container, and also touch a reload.ini file which tells the uwsgi to gracefully reload the codes without restart the container.

2. Deploy Django on docker

A new container called django is created in the docker based on the image of mbentley/django-uwsgi-nginx.

$ sudo docker run -d \
  -p 80:80 \
  -v /var/www/django/:/opt/django/app \
  -e MODULE=myapp \
  --name django \
  mbentley/django-uwsgi-nginx

Note: You can use other image instead of mbentley/django-uwsgi-nginx. But you need to find the uwsgi.ini on your own. It can be found from their Dockerfile.

3. Modify uwsgi setting

The uwsgi won't automatically reload by default in this image. So it is necessary to change the settings in the uwsgi.ini in the image.

Add the following line to /opt/django/uwsgi.ini in the container:

[uwsgi]
...
touch-reload = /opt/django/app/reload.ini
...

4. Setup git hooks for auto deployment

4.0. Install git server on the vps (Optional)

# Install git server on the Ubuntu
$ sudo apt-get update
$ sudo apt-get install -y git-all
$ sudo useradd git
$ sudo passwd git
# enter password for the user: git

For security reasons, let the user: git uses git-shell only

$ sudo vim /etc/passwd

Change the following line:

git:x:1003:1003:,,,:/home/git:/bin/bash

to:

git:x:1003:1003:,,,:/home/git:/usr/bin/git-shell

Enable the RSA authentication for the ssh

$ sudo vim /etc/ssh/sshd_config

Make sure the following lines look like this:

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile  .ssh/authorized_keys

Upload your public key to the git server:

$ sudo cat id_rsa.pub >> /home/git/.ssh/authorized_keys

Now it's ready to create a new repository.

4.1. Init git repository on the git server

$ cd /home/git
$ git init --bare django.git
$ sudo chown -R git:git django.git

Now, a new reposity called django.git is created.

4.2. Add hooks to the repository

To update the django app webfiles every time after successfully commited, the filename of the hook must be post-receive

# Create the hook
$ sudo vim /home/git/django.git/hooks/post-receive

Add the following line to the file:

#!/bin/sh
rm /var/www/django/* -rf
git --work-tree=/var/www/django --git-dir=/home/git/django-lesson.git checkout -f
touch /var/www/django/reload.ini

Make sure the git can write to the folder:

$ sudo chown -R git:git /var/www/django

4.3. Test

Try to commit the views.py to see if the page changes accordingly.

If not, here are some tips:

  1. Make sure that touch-reload = /path/to/reload.ini is added under the section of [uwsgi]
  2. Make sure the path of the reload.ini is the same as indicated in both post-receive and the uwsgi.ini
  3. Make sure the git server is allowed to write the reload.ini to the directory.
  4. Make sure that the hook works fine.