5

I can't get my head around on what's the "correct" way to deploy a Django project that uses uwsgi/gunicorn (I haven't decide yet what to use, probably uwsgi since it has better performances, suggestions?) and nginx using docker.

I saw that some people put everything in the same container. I'm not an expert of docker, but the container should just do one (1) thing. So, having Django + nginx seems to be 2 rather than 1.

Now, my idea of the deployment is:

  • a container with Django and uwsgi. At the end of the Dockerfile i run the uwsgi script. This container exposes the port 8000
  • a container with nginx that is linked to django one. This exposes port 80 and proxies the requests to django.

Is there any other way to do it? Is there a tutorial that covers this case a bit deeper. I need for a solid production, not just to test some code on my pc.

3 Answers 3

3

I'm currently building a django app the way you want.

I use docker-compose to do this. This is my docker-compose.yml

version: '2' services: nginx: container_name: nginx-container links: - uwsgi build: ./nginx ports: - "8888:80" volumes_from: - uwsgi uwsgi: container_name: uwsgi-container build: ./uwsgi expose: - "8001" volumes: - ./code/conf:/opt/conf - ./code/app:/opt/app 

Dockerfile for uWSGI:

FROM python:3.5 RUN ["pip", "install", "uwsgi"] CMD ["uwsgi", "--master", "--ini", "/opt/conf/uwsgi.ini"] 

Dockerfile for nginx:

FROM nginx RUN ["rm", "/etc/nginx/conf.d/default.conf"] RUN ["ln", "-s", "/opt/conf/nginx.conf", "/etc/nginx/conf.d/"] CMD ["nginx", "-g", "daemon off;"] 

And this is my directory tree:

├── README.md ├── code │   ├── app │   └── conf ├── collectstatic.sh ├── docker-compose.yml ├── install.sh ├── migrate.sh ├── nginx │   └── Dockerfile ├── restart.sh ├── upgrade.sh ├── uwsgi │   └── Dockerfile 

So I build my images with docker-compose build then launch new containers in background with docker-compose up -d then I can perform some setup tasks like installing django, generate secret key or whatever you want to have your container ready.

nginx and uwsgi containers uses shared volumes to read config files AND to communicate with a file socket.

Well, not sure that is the best way, but it's a work in progress.

2
  • docker-compose is not fine (yet) for production. after a while i found two solutions: 1) use two docker, one for django+uwsgi connected to nginx. they communicate via http-socket (or with a shared volume for the .sock, but not encuraged). 2) all in one docker, it works and someone is using, not sure it's the right approach, should be 1 service for 1 docker. Commented Jul 1, 2016 at 13:34
  • Thanks for pointing me using a shared volume for the socket wasn't so good. In fact I had an error with this and it's solved by linking services together and using http-socket. I updated my docker-compose.yml file in my answer. Commented Jul 1, 2016 at 14:19
3

I found this answer from Michael Hampton:

"This only works if the processes are in the same host, VM or container, because it tries to make a connection to the same machine. When they are in different containers, it does not work.

You need to alter your nginx configuration so that it uses the internal IP address of the uwsgi container."

And definitely is something you have to keep in mind if you will have Nginx in a different container, also you have to set the nginx.conf, pointing your statics file directory as alias preventing a security issue.

I hope this code work for everybody, it took me a couple of hours to figure about how to compose Gunicorn, docker, and Nginx:

# nginx.conf upstream djangoA { server $DOCKER_CONTAINER_SERVICE:9000 max_fails=3 fail_timeout=0; # In my case looks like: web:9000 } Server { include mime.types; # The port your site will be served on listen 80; # the domain name it will serve for server_name $YOUR_SERVER_NAME;# substitute your machine's IP address or FQDN charset utf-8; #Max upload size client_max_body_size 512M; # adjust to taste location /site_media { alias $DIRECTORY_STATIC_FILES/site_media;#your Django project's media files have to be inside of the container have nginxs, you can copy them with volumes. expires 30d; } location / { try_files $uri @proxy_to_app; } # Finally, send all non-media requests to the Django server. location @proxy_to_app { proxy_set_header X-Real-IP $remote_addr; proxy_redirect off; proxy_set_header Host $host; proxy_pass http://djangoA; } } 

And for the docker-compose:

#production.yml version: '2' services: db: extends: file: base.yml service: db nginx: image: nginx:latest volumes: - ./nginx:/etc/nginx/conf.d/ - ./$STATIC_FILE_ROOT/site_media:/$STATIC_FILE_ROOT/site_media ports: - "80:80" depends_on: - web web: extends: file: base.yml service: web build: args: - DJANGO_ENV=production command: bash -c "python manage.py collectstatic --noinput && chmod 775 -R project/site_media/static && gunicorn project.wsgi:application" volumes: - ./$DIRECTORY_APP:/$DIRECTORY_APP ports: - "9000:9000" depends_on: - db volumes: db_data: external: true 
3
  • pointing your statics file directory as alias preventing a security issue Could you please clarify on which security issue? Commented May 20, 2017 at 8:51
  • I hope this link can answer your question, stackoverflow.com/a/16275755/7391092. Best, Commented May 30, 2017 at 4:22
  • Could you fix the indentation? I guess volumes and ports after nginx should have two more spaces prepended. Commented Jan 17, 2018 at 18:15
2

I finally managed to build my docker-compose for Django, Gunicorn, Nginx and Postgres thanks (mostly) to this tutorial.

Basically, you have one container for Nginx, one container for Django+Gunicorn, and one container (or more if you want multiple databases) for Postgres.

You could also split Django+Gunicorn in two containers, but I think it makes more sense to have them both in one container, because one Gunicorn process always runs one Django wsgi application. I don't think you can have either N Gunicorn running 1 Django, 1 Gunicorn running N Django, or N Gunicorn running N Django, so there is no scaling possibilities here, except scaling N Gunicorn+Django containers.

Volumes are used to keep databases' data (and optionnaly Django's static/media files) permanently.

You were asking for a tutorial or other ways to do it, so I will not post my docker-compose.yml contents here (because it would also require the Dockerfile, the Nginx conf file, the Gunicorn conf file, the databases env files, and many snippets of Python code like DATABASES settings), but I will try to make a tutorial when I have time and post the link in a edit/comment.

Meanwhile, the link I provided above is a very good starting point.

EDIT: you can now take a look at this docker setup example and the related blog post.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.