Migrating Traefik from v1.7.x to v2.1

Traefik

Traefik is an open-source Edge Router that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them.
source: https://docs.traefik.io/

Why Traefik?

Traefik is a great solution when using container platforms such as Docker Swarm, Kubernetes, Openshift, etc. It has a great Auto Discover solution, and the use of configuration labels makes it easier to configure and implement when using Docker Swarm.

About this article

At Gonkar we have some customers running their workload on Docker Swarm clusters solutions. Docker Swarm is a great solution when your work load does not require advanced configuration and also it helps to keep it simple.

Recently the Traefik released their new version Traefik v2.1. It introduces new features like Consul Catalog, Load Balancing Mirroring, More Control in Internal Routing and much more.

In our case, we were running Traefik v1.7.x, and after the release of v2.1, we felt that the branch 2.x is mature enough to start some migration work in our test environment.

What I need to know?

When migrating from v1.7.x to v2.x, we have a significant change in how Traefik works and is being configured. It means that commands to start Traefik service changed as well as the Docker labels.

Command arguments

What we did to update our commands in our Traefik Docker Swarm deployment was to use the help from the Traefik service.

Docker:
docker run traefik:2.1 --help

Podman:
podman run traefik:2.1 --help
It is great if we start getting used to Podman since Kubernetes and Openshift are moving in that direction, and the commands are basically the same as docker

With the above command we will see all the new options we have to pass to our Traefik instance.

Something that can help, is if you are looking the command arguments for Docker provider you could just use grep to simplify the search.

podman run traefik:2.1 --help | grep docker
    --providers.docker  (Default: "false")
    --providers.docker.constraints  (Default: "")
    --providers.docker.defaultrule  (Default: "Host(`{{ normalize .Name }}`)")
    --providers.docker.endpoint  (Default: "unix:///var/run/docker.sock")
    --providers.docker.exposedbydefault  (Default: "true")
    --providers.docker.network  (Default: "")
    --providers.docker.swarmmode  (Default: "false")
    --providers.docker.swarmmoderefreshseconds  (Default: "15")
    --providers.docker.tls.ca  (Default: "")
    --providers.docker.tls.caoptional  (Default: "false")
    --providers.docker.tls.cert  (Default: "")
    --providers.docker.tls.insecureskipverify  (Default: "false")
    --providers.docker.tls.key  (Default: "")
    --providers.docker.usebindportip  (Default: "false")
    --providers.docker.watch  (Default: "true")

In this way we can find the new arguments used in v2.x and update our existent v1.7.x config.

Here I shared our stable Docker Compose for Traefik v2.1

version: '3.7'
services:
  traefik:
    image: traefik:2.1
    ports:
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
    command: >
      --api
      --log.level=INFO
      --accesslog=true
      --metrics.prometheus=true
      --providers.docker=true
      --providers.docker.endpoint=unix:///var/run/docker.sock 
      --providers.docker.swarmMode=true
      --providers.docker.exposedbydefault=false
      --providers.docker.network=traefik-net
      --entrypoints.http.address=:80
      --entrypoints.https.address=:443
      --certificatesResolvers.certbot=true
      --certificatesResolvers.certbot.acme.httpChallenge=true
      --certificatesResolvers.certbot.acme.httpChallenge.entrypoint=http
      --certificatesResolvers.certbot.acme.email=hostmaster@example.com
      --certificatesResolvers.certbot.acme.storage=/certs/acme-v2.json
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /data/traefik/certs:/certs
    networks:
      - traefik-net
    deploy:
      mode: replicated
      replicas: 1
      placement:
        constraints:
          - node.role == manager
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      labels:
        # v2.1
        - "traefik.docker.network=traefik-net"
        - "traefik.enable=true"
        - "traefik.http.services.traefik.loadbalancer.server.port=8080"
        # Http
        - "traefik.http.routers.traefik.rule=Host(`ingress.traefik.example.com`)"
        - "traefik.http.routers.traefik.entrypoints=http,https"
        # Enable Let's encrypt auto certificat creation
        - "traefik.http.routers.traefik.tls.certresolver=certbot"
        # Enable authentification
        - "traefik.http.routers.traefik.middlewares=traefik-auth"
        - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:HASH"
        # Redirect All hosts to HTTPS
        - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)"
        - "traefik.http.routers.http-catchall.entrypoints=http"
        - "traefik.http.routers.http-catchall.middlewares=redirect-to-https@docker"
        - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
        - "traefik.http.routers.traefik.service=api@internal"
        - "traefik.http.routers.traefik.tls"

networks:
  traefik-net:
    driver: overlay
    name: traefik-net

Our config is set up to work with Docker Swarm provider, enabling the API and Dashboard you could access as it appears in our example going to https://ingress.traefik.example.com.

Labels

Labels will define how we want our service to be integrated with Traefik. Basically, we will configure our routers and middlewares in order to pass to Traefik parameters such as hostname, ports, redirects, etcs.

In our case, what we did and what we recommend is to check the official documentation. There are two links there that I recommend:

https://docs.traefik.io/migration/v1-to-v2/

This link helps compare the labels between both versions and also shows some configs

https://docs.traefik.io/user-guides/docker-compose/basic-example/

The second link shows basic examples related to Docker Provider.

We can take as an example a service like Nginx that use as a webserver for this blog.

version: '3'

services:
    web:
        image: "${CI_REGISTRY}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}:latest"
        ports:
            - "80"
        networks:
            - traefik-net
        deploy:
            labels:
                - "traefik.enable=true"
                - "traefik.docker.network=traefik-net"
                - "traefik.http.routers.adminsecblog.rule=Host(`adminsecurity.guru`)"
                - "traefik.http.routers.adminsecblog.entrypoints=https"
                - "traefik.http.services.adminsecblog.loadbalancer.server.port=80"
                - "traefik.http.routers.adminsecblog.tls.certresolver=certbot"

networks:
  traefik-net:
    external: true

Explaining each label

traefik.enable=true
This option tells to Traefik that this service can be discovered.

traefik.docker.network=traefik-net
Here we define the network that containers and services use to communicate.

traefik.http.routers.adminsecblog.rule=Host(adminsecurity.guru)
The Host rule sets the hostname. It knows where to route the request and also to create the certificate

traefik.http.routers.adminsecblog.entrypoints=https
Here we define our entry point. In our case, since Traefik router is sending all requests to HTTPS, we use only the https entrypoint.

traefik.http.services.adminsecblog.loadbalancer.server.port=80
Our service is set to listen this port(80). It is important to specify when using Docker Swarm provider. With Docker provider it is not necessary to specify ports since they are recognized automatically by Traefik. But with Docker Swarm we have to keep in mind that service port needs to be defined.

traefik.http.routers.adminsecblog.tls.certresolver=certbot
This label set the certificasteResolver name that we defined in our Traefik config.

Conclusion

Every day, Traefik improves the ways we use ingress routers and load balancing for our containerized deployments, and it is easy to implement among different container orchestration platforms.

Migration between v1 and v2 is effortless following the official documentation, and it should not produce big downtime in your production environments.

Should you need any assistance with Traefik or container technologies, be sure to contact Gonkar and check our Consultancy Services.