Using Nginx for Production ready Flask app with uWSGI
After creating many Flask applications using Python, the thing that always made me sad is the below ‘WARNING’ message. But since I was doing it mostly for my learning, I didn’t bother much about the warning as long as the flask application worked.
1
2
3
4
5
6
7
8
\* Serving Flask app "app" (lazy loading)
\* Environment: production
**WARNING: This is a development server. Do not use it in a production deployment.**
Use a production WSGI server instead.
\* Debug mode: off
\* Running on [http://127.0.0.1:5000/](http://127.0.0.1:5000/) (Press CTRL+C to quit)
For one of our project we created a Python Flask application and it all worked wonderfully well, but only on my local system. To make it a production ready API service, I had to explore more about serving the application.
Our project has multiple microservices which run as Docker containers orchestrated using Kubernetes.
The aim is to make the Flask application run by Nginx by using uWSGI. And all these should run as seperate Docker containers.
The below is the tree structure for our sample application with flask and nginx folders for each container.
Tree structure of the application
Let’s dive into the program step by step.
app.py would be your working Flask application. In our case it would just print “Hello World”. This would be the only change that you need to do and replace it with your own Flask application.
1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return("Hello World")
if __name__ == "__main__":
app.run()
The Dockerfile for the flask application which installs the needed libraries and runs the uwsgi app.
1
2
3
4
5
FROM python:3.7.3-stretch
WORKDIR /app
ADD . /app
RUN pip install -r requirements.txt
CMD \["uwsgi","app.ini"\]
The uwsgi configurations are maintained in the app.ini file which calls the app.py file. In case you are using a different python file or app name, it needs to be updated here.
1
2
3
4
5
6
7
8
9
10
11
[uwsgi]
wsgi-file = app.py
callable = app
processes = 4
threads = 2
callable = app
socket = :5000
master = true
chmod-socket = 660
vacuum = true
die-on-term = true
The requirements.txt file would hold all the needed libraries.
1
2
3
4
5
6
7
Click==7.0
Flask==1.0.3
itsdangerous==1.1.0
Jinja2==2.10.1
MarkupSafe==1.1.1
uWSGI==2.0.18
Werkzeug==0.15.4
We are done with everything that is to be done for our Flask Docker container. Now we need to prepare our Nginx Docker container to run the flask application.
First creating a Dockerfile to run the Nginx. If your project already has an Nginx Docker service, update the configuration file to add the changes for the flask application.
1
2
3
4
5
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/
Now we need to have our configuration in our nginx server to run the flask container. The Nginx server would listen at port 8080 and call the flask container at port 5000.
1
2
3
4
5
6
7
8
server {
listen 8080;
location / {
include uwsgi_params;
uwsgi_pass flask:5000;
}
}
Now the final part is to create a docker compose file to run our application.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "3"
services:
flask:
build: ./flask
container_name: flask
restart: always
expose:
- 5000
nginx:
build: ./nginx
container_name: nginx
restart: always
ports:
- "8080:8080"
Once all the files are in place, it is time to run the services and see if it is working. Go to the main folder and run the docker compose.
1
docker-compose up
Our nginx server is running, which listens to port 8080 to make any calls to the flask application.
1
[http://localhost:8080](http://localhost:8080)
Voila! It worked.
The entire application is available at https://github.com/ksashok/Flask-Nginx-uwsgi