Published at

Traefik and Flask with Docker Compose

Traefik and Flask with Docker Compose

A simple guide to setting up a Flask app with Traefik as a reverse proxy using Docker Compose. Learn how to configure routing and load balancing.

Authors
  • avatar
    Name
    James Lau
    Twitter
  • Indie App Developer at Self-employed
Sharing is caring!
Table of Contents

Traefik and Flask: A Simple Docker Compose Setup

This post demonstrates how to set up a simple Flask application behind Traefik using Docker Compose. Traefik acts as a reverse proxy and load balancer, handling routing to your Flask app based on hostnames.

Project Structure

Here’s the directory structure we’ll be using:

.
├── docker-compose.yml
├── flask-app
│   ├── app.py
│   ├── Dockerfile
│   └── requirements.txt
└── traefik
    └── dynamic
        └── dynamic.yml

Flask Application (flask-app)

Let’s start with the Flask application. This is a basic “Hello, World!” app.

flask-app/app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello from Flask!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

This code creates a Flask app that listens on port 5000 and returns “Hello from Flask!” when you visit the root path.

flask-app/requirements.txt

flask==2.3.2

This file specifies the Flask dependency for our application.

flask-app/Dockerfile

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]

This Dockerfile sets up the Flask application environment. It:

  1. Uses a Python 3.9 slim base image.
  2. Sets the working directory to /app.
  3. Copies the requirements.txt file and installs the dependencies.
  4. Copies the app.py file.
  5. Exposes port 5000.
  6. Runs the Flask application.

Traefik Configuration

Traefik is configured using a dynamic configuration file.

traefik/dynamic/dynamic.yml

http:
  routers:
    flask-router:
      rule: "Host(`flask.localhost`)"
      service: flask-service
      entryPoints:
        - web
  services:
    flask-service:
      loadBalancer:
        servers:
          - url: "http://flask-app:5000"

This configuration defines:

  • Router: flask-router that listens for requests to flask.localhost.
  • Service: flask-service that load balances requests to the Flask application at http://flask-app:5000.
  • Entrypoint: Uses the web entrypoint, which is configured to listen on port 80 (in docker-compose.yml).

Docker Compose (docker-compose.yml)

version: '3.8'

services:
  traefik:
    image: traefik:v3.4
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - traefik-net

  flask-app:
    build: ./flask-app
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.flask-router.rule=Host(`flask.localhost`)"
      - "traefik.http.services.flask-service.loadbalancer.server.port=5000"
    networks:
      - traefik-net
  whoami:
    image: traefik/whoami
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
    networks:
      - traefik-net
networks:
  traefik-net:
    driver: bridge

This docker-compose.yml file defines three services:

  • traefik: The Traefik reverse proxy.
    • It’s configured to use Docker as a provider, meaning it will automatically discover and configure routes based on Docker labels.
    • It exposes ports 80 (for HTTP) and 8080 (for the Traefik dashboard).
    • It mounts the Docker socket to allow Traefik to monitor Docker events.
  • flask-app: The Flask application.
    • It’s built from the ./flask-app directory using the Dockerfile.
    • It uses labels to configure Traefik routing. These labels are an alternative to the dynamic.yml file, defining the router, rule, and service directly within the Docker Compose file. Specifically, they define the same router as the dynamic.yml file, routing flask.localhost to the flask app. The label traefik.enable=true is necessary for Traefik to consider the service. The port is defined for the service’s load balancer.
  • whoami: A simple container that returns information about itself, used for testing Traefik routing. It routes whoami.localhost to this container.

The traefik-net network allows the services to communicate with each other.

Running the Application

  1. Save all the files in the correct directory structure.
  2. Run docker-compose up --build in the root directory (where docker-compose.yml is located).

Accessing the Application

  1. Add the following lines to your /etc/hosts file:
127.0.0.1 flask.localhost
127.0.0.1 whoami.localhost
  1. Open your browser and navigate to http://flask.localhost. You should see “Hello from Flask!“.
  2. Navigate to http://whoami.localhost. You should see information about the whoami container.
  3. You can access the Traefik dashboard at http://localhost:8080 (note that --api.insecure=true is only for development and should NOT be used in production).

Explanation for Intermediate Learners

  • Reverse Proxy: Traefik acts as a reverse proxy, sitting in front of your application and handling incoming requests. This allows you to do things like load balancing, SSL termination, and request routing.
  • Load Balancing: Traefik can distribute traffic across multiple instances of your application, improving performance and availability.
  • Docker Provider: Traefik’s Docker provider allows it to automatically discover and configure routes based on Docker labels. This makes it easy to manage routing for your Dockerized applications.
  • Host Header: The Host header is used to determine which application should handle a request. In this example, Traefik routes requests to flask.localhost to the Flask application.
  • Docker Networks: Docker networks allow containers to communicate with each other using their service names as hostnames.

Conclusion

This post demonstrated how to set up a simple Flask application behind Traefik using Docker Compose. This is a basic example, but it can be extended to more complex applications with multiple services and more sophisticated routing rules.

Sharing is caring!