In the KNoT project, we use traefik as a reverse proxy technology to route requests to the right service, which is running in a Docker container. Recently, traefik released its second version with the replacement of old components such as frontends
and backends
by routers
, middlewares
, and services
.
To keep up-to-date with the newer traefik features and considering the addition of routers
provides a better and flexible way of handling generic TCP requests, we decided to migrate our stack configuration for this new version. This note will briefly describe how this migration was done.
Traefik v1
Firstly, let’s introduce some traefik concepts from its first version:
- entrypoints: network entry points from which traefik is listening (port, SSL, redirection).
- frontends: matching patterns (based on request fields) that indicate the backend target (aka Docker service) of the request.
- backends: composed by one or more target services, which can include a load-balancing strategy.
Below you can see an example of traefik configuration that setup two entrypoints
: one for listening https
requests on 443 port and another for listening http
requests on port 80 and automatically redirecting to the https
entry point.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
traefik:
image: traefik:v1.7
command: >
traefik
--docker
--docker.watch
--docker.swarmMode
--docker.exposedByDefault=false
--entryPoints='Name:http Address::80 Redirect.EntryPoint:https'
--entryPoints='Name:https Address::443 TLS'
--defaultEntryPoints=http,https
ports:
- '80:80'
- '443:443'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
mode: global
After receiving the request through one of these entry points, traefik will route it according to the service’s frontend
rules. As an example, we have two services storage
and babeltower
, which expects the request according to the address domain defined by a regular expression that catches every request that starts with storage.
or bt.
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
babeltower:
image: cesarbr/knot-babeltower
env_file: '../env.d/knot-babeltower.env'
deploy:
replicas: 1
labels:
- traefik.enable=true
- traefik.frontend.rule=HostRegexp:bt,bt.{domain:[a-zA-Z0-9.]+}
- traefik.port=80
storage:
image: cesarbr/knot-cloud-storage
env_file: '../env.d/knot-cloud-storage.env'
deploy:
replicas: 1
labels:
- traefik.enable=true
- traefik.frontend.rule=HostRegexp:storage,storage.{domain:[a-zA-Z0-9.]+}
- traefik.port=80
It’s important to notice that when we define the frontend
rules dynamically on Docker service’s labels, it’s already attached to the service backend
. So, we don’t need any additional configuration to link the frontend
to the backend
.
Traefik v2
Now, there are no frontends
or backends
anymore. They were rewritten into two new components: routers
and services
. This will give us more flexibility because, differently of backends
, the services
aren’t responsible for applying changes on the fly to the requests anymore, moving this role the middlewares
. Then, it’s possible to create one that rewrites pathnames and attach it to a particular router
.
The traefik settings remains quite similar to the v1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
traefik:
image: traefik:v2.2
command: >
traefik
--providers.docker
--providers.docker.watch
--providers.docker.swarmMode
--providers.docker.exposedbydefault=false
--entrypoints.http.address=:80
ports:
- '80:80'
- '443:443'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
deploy:
mode: global
Based on the following steps, you can see the result after migrating the traefik version.
- Specify a port for the
services
through its load balancer server labels. - Create a
router
rule that will enable matching a request hostname to the services based on a definedregex
. - Attach the
router
to anentrypoint
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
babeltower:
image: cesarbr/knot-babeltower:dev
env_file: './env.d/knot-babeltower.env'
deploy:
replicas: 1
labels:
- traefik.enable=true
- traefik.http.services.babeltower.loadbalancer.server.port=80
- traefik.http.routers.babeltower.rule=HostRegexp(`{subdomain:bt}.{domain:[a-zA-Z0-9.]+}`)
- traefik.http.routers.babeltower.entrypoints=http
storage:
image: cesarbr/knot-cloud-storage:dev-go
env_file: './env.d/knot-cloud-storage.env'
deploy:
replicas: 1
labels:
- traefik.enable=true
- traefik.http.services.storage.loadbalancer.server.port=80
- traefik.http.routers.storage.rule=HostRegexp(`{subdomain:storage}.{domain:[a-zA-Z0-9.]+}`)
- traefik.http.routers.storage.entrypoints=http
Was it simple, right?
In the previous example, I didn’t use any middleware, so how it could be useful? Hm. Exactly. We can setup a middleware for automatically redirect http
requests to https
ones. This note will be further updated to add this example and all the necessary https
configuration.
Click here to see the full version of this stack (without https
too).