The purpose of this project is to demonstrate the ability to run nginx, gunicorn and flask together in a Docker container.
In any case of deployment (especially production deployment), using flask alone to serve request is not the right thing to do. Typically, gunicorn is placed in front of flask to receive the request; gunicorn helps out primarily by scaling out the flask service (see here and here). Additionally, gunicorn itself is inadequate and nginx comes into play for better performance such as serving dynamic or static content; in the case of dynamic content, nginx will delegate this to gunicorn; in the case of static content, nginx will do better at serving those content back. There are many reported performance problems with using flask alone, and this demonstration shows a template containerized approach you may adapt to properly deploy your flask application.
One complication comes with having nginx
and gnunicorn
that have to both run at container startup. In Docker, you can only have one CMD
command. Thus, you can only run either nginx
or gnunicorn
.
CMD ["gunicorn", "-b", "unix:app.sock ", "-w", "4", "--chdir", "/app", "app:app"]
or
CMD ["nginx", "-g", "daemon off;"]
You can use the single CMD
with &&
or ;
to start both services. However, that seems a bit undisciplined as these are services, and also, take a look at how the array passed to CMD
grows. (I'm not even sure if the following will work; besides, which service will be in the foreground and which in the background?).
CMD ["gunicorn", "-b", "unix:app.sock ", "-w", "4", "--chdir", "/app", "app:app", ";", "nginx", "-g", "daemon off;"]
The best approach is to use supervisor to control the services. What I like about supervisor
is that it is easy to configure and it can restart failed services. Futhermore, both services are now in the foreground (you are able to monitor logging to the console for debugging purpose).
Build it.
./build.sh
Run it.
docker run -it -p 80:80 --rm nginx-wsgi:local
Observe it.
- Using Supervisor with Docker to manage processes
- Why can't I use Docker CMD multiple times to run multiple services?
- Docker Alpine linux running 2 programs
- /etc/nginx/proxy_params failed (2: No such file or directory)
Check out John Papa. He's got some good philosophical approaches to creating awesome software.
@misc{oneoffcoder_nginx_wsgi_2019,
title={Docker container show how to run a Flask application behind gunicorn and nginx},
url={https://github.com/oneoffcoder/docker-containers/tree/master/nginx-wsgi},
journal={GitHub},
author={One-Off Coder},
year={2019},
month={Jul}}