A FlaskRESTFul app starter using Python, Docker and Gunicorn

1. Create the project folder (e.g: flask-restful-gunicorn-starter) in your path desired:

2. Create app folder inside project folder

3. Create the FlaskRESTful app (app.py) in the app folder of the previous step:
from flask_restful import Resource, Api
from flask import Flask
# Create flask restful app
app = Flask(__name__)
api = Api(app)
class HelloWorld(Resource):
def get(self):
"""Return hello world msg"""
return {'hello': 'world'}
# Add url to API
api.add_resource(HelloWorld, '/')
4. (Optional) Add flake8 file: create .flake8 file in app folder to modify the maximum lenght of characters for a Python code line. Maximum is set to 120 instead of 80 of PEP-8 standard. (Flake8 is a tool for style guide enforcement https://flake8.pycqa.org/en/latest/index.html).
[flake8] max-line-length = 120
5. Create requirements.txt file: in the project folder to install all the Python libraries required on the docker container:
Flask>=1.1.2,<1.2.0
gunicorn>=20.0.4,<20.1.0
flake8>=3.8.4,<3.9.0
Flask-RESTful>=0.3.8,<1.0.0
6. Add Dockerfile in the project folder: Python 3.8 image is used, the requirements and the app folder are copied to the container, then requirements are installed using pip and finally port 8000 is exposed to serve the API.
FROM python:3.8
# Avoid pyc files and output console buffer
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# Copy requirements to container
COPY ./requirements.txt /requirements.txt
# Upgrade pip
RUN pip install --upgrade pip
# Install requirements
RUN pip install -r /requirements.txt
# Create app dir in the container
RUN mkdir /app
# Set default dir in the container
WORKDIR /app
# Copy from local machine to container
COPY ./app /app
# Expose port
EXPOSE 8000
7. Create docker-compose.yml in the project folder: the command section in app service starts Gunicorn Server to expose the API using two workers and two threads. Reload argument allows to reload the server if there is a change on the code (this option is only recommended for development environment)
version: "3"
services:
app:
build:
context: .
ports:
- "8000:8000"
volumes:
- ./app:/app
command: # Start gunicorn server with 2 worker, 2 threads and reload option (only for dev)
gunicorn app:app -w 2 --threads 2 -b 0.0.0.0:8000 --reload
container_name:
app
8. Create Makefile in the project folder: makefile allows to execute easily commands for your project (e.g: “make up” to start container)
DOCKER_COMPOSE := $(shell which docker-compose)
DOCKER := $(shell which docker)
# Start container
up:
$(DOCKER_COMPOSE) up
# Start container (detached mode)
upd:
$(DOCKER_COMPOSE) up -d
# Down container
down:
$(DOCKER_COMPOSE) down
# Stop container
stop:
$(DOCKER_COMPOSE) stop
# Build container
build:
$(DOCKER_COMPOSE) build
# Delete container
rm:
$(DOCKER_COMPOSE) rm
# Pull docker image
pull:
$(DOCKER_COMPOSE) pull
# Run flake8 linting
lint:
$(DOCKER_COMPOSE) run --rm app flake8
# Access to container´s bash
bash:
$(DOCKER) exec -it app bash
8) Execute “make up” command to build and start the app container

10) Check API is working: open a browser and go to http://localhost:8000/. Your API is working, enjoy it!!!

All the code for this project flask-restful-gunicorn-starter is on my Github profile: https://github.com/safuente/flask-restful-gunicorn-starter.