Prerequisites: Docker knowledge
1. What is Traefik?
Traefik is an open-source solution serving as a reverse proxy and load balancing for services. What makes it stand out is its possibility for dynamic routing.
2. Why use Traefik?
Traefik uses dynamic routing to target services without any manual intervention which makes it very convenient, if you need simple and fast implementation of a solution for your microservices for example. In comparison with other reverse proxy solutions where you need to manually update the configuration (which might be tedious and time-consuming), now Traefik detects these changes automatically and activates them.
3. How does Traefik work?
Since we explained the basic concept of Traefik, now we can proceed with understanding how it works. First, we need to get familiar with its components and the configuration.
The automatic configuration discovery is achieved with the help of providers. The providers could be cloud providers, container engines, and other infrastructure components. Docker, Kubernetes, or Amazon ECS to name a few. Traefik works with dozens of them. In addition to the dynamic routing, you no longer need to maintain a configuration file. Instead, Traefik scans the entire infrastructure every 2 seconds (by default but this is editable) and reads the information you attach to the services. The labels in the Docker provider contain such information according to which Traefik routes the requests.
Installation of Traefik and Basic demonstration
Let’s demonstrate how Traefik is routing requests dynamically. For this purpose, we are going to use the Docker provider.
First, we need to pull the required containers. (At the time of writing the latest version is v2.9)
docker pull traefik |
Now before running the container, we need to include some options. We will use a docker-compose file and describe all the options required to run a basic working configuration of Traefik.
First, let us create a network for Traefik:
docker network create traefik-net |
Next, we will write the compose file with the following options explained in a comment:
version: '3'
services:
traefik:
image: "traefik:v2.9"
container_name: "traefik"
ports:
- "80:80"
- "8080:8080" # Expose Dashboard
command:
- --providers.docker=true # Enables docker as the provider
- --api.insecure=true # Allows using the api without any ssl certs
- --api.dashboard=true # Allows dashboard to detect services (dashboard explained below)
- --providers.docker.network=traefik-net # Traefik will be working in the network we created named “traefik-net”
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-net
networks:
traefik-net:
external: true
We are ready to run the container:
docker-compose up -d |
We can check the running container with the docker ps command
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
144e6e1cbcd2 traefik:v2.9 "/entrypoint.sh --pr…" 19 minutes ago Up 18 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp traefik
As you have probably noticed from the compose file, we already exposed the dashboard of Traefik. We can access it on port 8080:
Few words on the dashboard
The dashboard is a very convenient and pretty way to view the statistics of your services and routes. When a service gets scanned by Traefik, it will appear automatically on the dashboard. If we go to the HTTP section, we can see that we already have 3 routers. According to the official documentation, a router is in charge of connecting incoming requests to the services that can handle them. The port 80, which is one of the entrypoints, is reserved for the incoming requests.
The routers we see here are the default ones that define the routes to the Traefik components.
Note: The dashboard can be very convenient, as we noted. However, it is a security liability and shouldn’t be exposed in an environment that has outside network access. Therefore, in a production environment it should be either disabled (remove port 8080 from the compose file), properly protected with SSL certificates and other means, or just used only in an internal network.
Adding services to Traefik
Let’s add a service to which Traefik will route the requests. For the sole purpose of this demonstration, we are going to use an Nginx web server in docker.
Directly pull the image and start the nginx container:
docker run -d -p 8081:80 –net=traefik-net nginx |
Note that we are starting the container in the docker network we created earlier and exposed port 8081 for the webserver since port 80 is already used by Traefik to route through it any requests.
After we ensure that nginx is running we can check how it appears in the dashboard. And without any additional intervention, we can see the new Host:
Now the new host is not a FQDN and we cannot access it that way, which means Traefik cannot route any requests through it at the moment. As we know Traefik scans the services and specifically looks for container labels. The labels serve as instructions for Traefik.
Let us add labels to the containers.
Run docker-compose down
and edit the compose file as follows:
version: '3'
services:
traefik:
image: "traefik:v2.9"
container_name: "traefik"
ports:
- "80:80"
- "8080:8080" # Expose Dashboard
command:
- --providers.docker=true
- --api.insecure=true
- --api.dashboard=true
- --providers.docker.network=traefik-net
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-net
labels:
- "traefik.enable=true" # Enable assigning subdomain to the dashboard
- "traefik.http.routers.api.rule=Host(`traefik.localhost`)" # Domain for the dashboard
nginx1:
image: "nginx:latest"
container_name: "nginx1"
ports:
- "8081:80"
depends_on:
- traefik
networks:
- traefik-net
labels:
- "traefik.http.routers.nginx1.rule=(Host(`nginx.localhost`)
- "traefik.enable=true" # Enable assigning subdomain to the service
networks:
traefik-net:
external: true
traefik.http.routers.nginx1.rule
will set the localhost from which Traefik will route the request to the webserver.
docker-compose up -d |
We see that we now have a proper host. Let’s test if it works:
Notice that now we can connect to the dashboard via the traefik.localhost domain which we set in the label of the container. The nginx.localhost should also redirect us to the webserver container:
Configuring more than one service with a single domain
The typical use case is when we have microservices that are using one domain. We are going to create two custom Nginx images with custom configs. Let’s pretend that those 2 containers will have different functions.
First webserver default.conf:
server {
listen 80;
listen [::]:80;
server_name localhost;
location /static {
alias /usr/share/nginx/html/static;
try_files $uri $uri/ @static;
index index.html;
}
location @ static {
rewrite /static/(.*)$ /static/index.html?/$1 last;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Dockerfile:
FROM nginx
RUN mkdir -p /usr/share/nginx/html/static
COPY index.html /usr/share/nginx/html/static
RUN chmod -R 755 /usr/share/nginx/html/static
COPY default.conf /etc/nginx/conf.d
Create a custom index file. The contents of mine are just “STATIC PAGE”.
Second web server default.conf:
server {
listen 80;
listen [::]:80;
server_name localhost;
location /info {
alias /usr/share/nginx/html/info;
try_files $uri $uri/ @info;
index index.html;
}
location @ info {
rewrite /info/(.*)$ /info/index.html?/$1 last;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Dockerfile:
FROM nginx
RUN mkdir -p /usr/share/nginx/html/static
COPY index.html /usr/share/nginx/html/static
RUN chmod -R 755 /usr/share/nginx/html/static
COPY default.conf /etc/nginx/conf.d
Create the second index file with a different content.
Build both of the images in the respective directories. I will call them nginx1 and nginx2.
docker build -t nginx1 .
docker build -t nginx2 .
Update the compose file and add the labels to the new containers with the proper rules.
version: '3'
services:
traefik:
image: "traefik:v2.9"
container_name: "traefik"
ports:
- "80:80"
- "8080:8080" # Expose Dashboard
command:
- --providers.docker=true
- --api.insecure=true
- --api.dashboard=true
- --providers.docker.network=traefik-net
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`traefik.localhost`)"
nginx1:
image: "nginx1:latest"
container_name: "nginx1"
ports:
- "8081:80"
depends_on:
- traefik
networks:
- traefik-net
labels:
- "traefik.http.routers.nginx1.rule=(Host(`nginx.localhost`) && PathPrefix(`/static`))"
- "traefik.enable=true"
nginx2:
image: "nginx2:latest"
container_name: "nginx2"
ports:
- "8082:80"
depends_on:
- traefik
networks:
- traefik-net
labels:
- "traefik.http.routers.nginx2.rule=(Host(`nginx.localhost`) && PathPrefix(`/info`))"
- "traefik.enable=true"
networks:
traefik-net:
external: true
PathPrefix rule matches the request prefix path.
Start the containers:
sudo docker-compose up -d
On the dashboard now we can see both of the Hosts.
Let’s see if we have access to each of the URLs:
Traefik successfully redirects the requests according to the URL based on the labels we set in the containers. This is how you can set dynamic and automatic routing to your microservices.
Conclusion
In this guide, we demonstrated that with a straightforward configuration, Traefik can be of great practical use. In addition, its capabilities are not at all limited to those we have presented. Traefik offers many more advanced options, such as adding HTTP middleware, additional rules, SSL certificates to the services, and more. There are also a lot more cases in which Traefik can be of help. Feel free to dive deeper and explore new case scenarios and learn more about how to simplify your work with this modern reverse proxy!
2 Responses
Very nice article. Can you please help understanding if we need to horizontally scale traefik then what should be the approach?
Hi Sanjeev,
You can run multiple traefik instances. So, you should look for a solution with docker swarm mode.