In this tutorial, we show how you can build and deploy a really simple Python app using Docker. To demonstrate, we'll create an API to return details of the TFL train lines in London. We'll use Flask to build the application.

Create a Flask app

First, create a python flask app which returns details about the TFL trains. This application serves a very basic API with details on London's TFL trains.

from flask import Flask, jsonify, request
import sys
import logging

logging.basicConfig(level=logging.INFO)

app = Flask(__name__)

tasks = [
    {
        'id': 1,
        'service': 'tube',
        'line': 'northern',
        'colour': 'black'
    },
    {
        'id': 2,
        'service': 'tube',
        'line': 'circle',
        'colour': 'red'
    }
]

def shutdown_server():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()

@app.route('/trains', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})

@app.route('/')
def hello_world():
    return 'Welcome to trains API'

@app.route('/exit')
def exit():
    message = logging.info("Stopping application")
    shutdown_server()
    print("The Flask server has been shutdown.")

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Run a quick 'hello world' type test

import requests

url = "http://192.168.1.74:5000/"

response = requests.get(url)
response_code = response.status_code
response_text = requests.get(url).text

display(response_code)
display(response_text)
200
'Welcome to trains API'

Setup the Dockerfile

Next, we want to package the application into a container using a Dockerfile. The finished Dockerfile will look as follows:

FROM python:3.7-alpine

COPY . /app

WORKDIR /app

RUN pip install -r requirements.txt

EXPOSE 5000

CMD ["python", "app.py"]

Deconstruct the Dockerfile

Let's break down each line in turn to describe what is happening...

In the first line we declare a parent image which is the image our own image is based on. Each subsequent declaration in the Dockerfile modifies this image. In our example, we use a version of Alpine Linux as our base image. Alpine Linux is a lightweight Linux distribution which makes it ideal for our container.

FROM python:3.7-alpine

Next we copy all of the files from the current host directory into the container's app directory.

COPY . /app

We change our working directory to the app directory. And then we tell Docker to install the Python packages needed for the app.py

WORKDIR /app

RUN pip install -r requirements.txt

Next we tell the container to listen on a specific network port at runtime. The default is TCP but you can also specify UDP. Note that the EXPOSE instruction does not actually publish the port. This instruction is there for documentation purposes. To actually publish the port, you need to use the -p flag on the docker run command.

EXPOSE 5000

Finally, we run the app:

CMD ["python", "app.py"]

Run the docker container locally

You might want to run the Dockerfile on your own machine to verify that it is working correctly. To do that, we docker build and then docker run:

You can build the Dockerfile as follows. The -t or tag allows you to tag the image with a name.

docker build -t slemasne/trains .

Then run the image to create a container which runs our application. The '-p' flag maps port 5000 on localhost in the host to port 5000 in the docker container.

docker run -p 5000:5000 slemasne/trains

You can also run the command with a '-d' detached flag to run the container in the background:

docker run -d -p 5000:5000 slemasne/trains

The application can be accessed on our localhost:

http://localhost:5000/trains