Today we are going to deploy a python web app using gunicorn as a docker container. First we need to write our Dockerfile.
First, we have to create our very minimalistic python web app. First, we will create a root folder to contain the whole project including the Dockerfile. Inside this root folder, we will create another folder called
app where our web app source code will reside. So, the folder structure will look like this:
root folder |__ app |__ Dockerfile
app folder, we will create three files:
serve.py. The first file will simply contain all the requirements for our python app. If you are already know about python app development, you are already know the idea. The second script will contain all gunicorn configurations (Wow! I didn't see this was coming :P). The
serve.py script, as the name suggest, will be the python script which will receive all request from gunicorn, do some processing and will return appropriate reply.
For now, we have only one requirement - Gunicorn itself. So this is the content of our
serve.py looks like this:
import gunicorn import json def app(environ, start_response): response_code = '200 OK' response = json.dumps('Hakuna Matata!').encode('utf-8') start_response(response_code, [ ("Content-Type", "text/plain"), ("Content-Length", str(len(response))) ]) return iter([response])
This is a very barebone version of a gunicorn app serving script. But this will do for our purpose.
gunicorn.config.py, we will define only two configs for now, so it will look like this:
bind = '0.0.0.0:10080' workers = 2
CAUTION: Avoid pulling your hair out
In `gunicorn.config.py`, set the binding address as `0.0.0.0:PORT_YOU_WISH`. This is very important. If you set the binding address to 127.0.0.1 like in non-container way, then it will only receive request from localhost which is the docker container itself. That means, gunicorn won't be reachable outside of the container.
Now, it is time to writ our Dockerfile. We are going to develop our app based on
python:3.6. Please note that,
python:3.6 docker container expects your app to be in
/usr/src/app. So, you must put your python app source files there.
We will add this line in our Dockerfile.
Next, we copy our
requirements.txt file first. The reason we are doing first because, everytime we add a new requirements, it won't invalidate the docker cache. Pip will install the missing packages.
COPY app/requirements.txt /usr/src/app/
Next, we make
/usr/src/app as our work directory and install the requirements there:
WORKDIR /usr/src/app RUN pip install -r requirements.txt
Now we copy our app source files in their designated directory:
COPY app/ /usr/src/app
We expose the port
10080 for obvious reason.
Next, we run the command to start up the gunicorn process:
CMD ["gunicorn", "serve:app", "-c", "/usr/src/app/gunicorn.config.py"]
We are done writing our Dockerfile. The complete Dockerfile looks like this:
FROM python:3.6 COPY app/requirements.txt /usr/src/app/ WORKDIR /usr/src/app RUN pip install -r requirements.txt COPY app/ /usr/src/app EXPOSE 10080 CMD ["gunicorn", "serve:app", "-c", "/usr/src/app/gunicorn.config.py"]
Now it's time to build and run our docker container. To build the container we will run this command in terminal from within our root folder.
$ docker build -t docker-gunicorn .
And to start our container, we will run this command:
$ docker run -p 10080:10080 docker-gunicorn
While our container is running, we can visit
http://localhost:10080. We wish you Hakuna Matata! 🙂
Of course, to see all the docker images you have, you can run this command:
$ docker images
And to see the running container:
$ docker ps
The complete source code is available on github: