[Update 04/2018]
Un des problèmes rencontrés lorsque l'on travaille avec des conteneurs, c'est de pouvoir tracker leur cycle de vie afin d'y envoyer (ou non) le trafic qui lui est destiné. Dans le cas d'un service load-balancé, il est important que nos conteneurs s'enregistrent d'eux même pour passer proprement à l'échelle.
Les reverseproxy comme Nginx ou HAProxy ne gèrent pas nativement ce genre de comportement. Mais : Y'a Traefik ! Et Traefik est un reverse-proxy un peu plus récent et donc un peu plus intelligent que Nginx ;)
On cherche à faire quoi déjà ?
La problématique est un peu toujours la même : un conteneurs ça apparait et disparait assez vite, on ne veut pas avoir à maitriser le port de l'host sur lequel ils écoutent. Et quand il s'agit de webservices, ça devient vite problématique... Consul et les discovery services en général solutionnent une partie du problème, on a un outil qui permet de savoir ce qui tourne et où. C'est bien, mais si on pouvait exploiter ces infos ça serait mieux.
Dans le cas de webservices, on cherche à avoir un reverse-proxy qui sache en "temps réel" où se trouvent nos conteneurs et sache sur quel groupe de conteneurs forwarder les requêtes destinées à une URL donnée. Si on peut load-balancer entre plusieurs conteneurs et disposer de plusieurs backends, ça serait top.
Traefik
Je présente ici Traefik. Traefik a été écrit par Emile Vauge, c'est français, bien de chez nous, donc c'est bien !
Traefik est donc un reverse-proxy et un load-balancer fait pour déployer principalement des microservices (ie conteneurs). Il est nativement simple puisque sa configuration propre est extrêmement limitée étant donné que celle-ci est majoritairement "déléguée" à ses backends. Et parmi ces backends, on compte Docker, Consul, k8s, mesos, etcd etc. Personne ne manque à l'appel. Traefik peut même être backé par de simples fichiers statiques et se comporter comme un reverse-proxy classique.
Pour notre première démonstration, on va utiliser directement le backend Docker.
Comme pour Registrator et Consul, il faudra donner à notre conteneur Traefik accès au socket Docker afin que celui ci puisse accéder aux évènements.
Utilisons docker-compose pour créer les conteneurs nécessaires :
version: '2'
services:
traefik:
image: traefik:1.5
command: --web --docker --logLevel=DEBUG
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "$PWD/traefik.toml:/traefik.toml"
webapp:
image: osones/helloworld
labels:
- "traefik.port=80"
- "traefik.backend=hello"
- "traefik.frontend.rule=Host:hello.docker"
Rien de spécial du côté du conteneur Traefik. Une interface web est dispo sur le port 8080.
Pour notre webapp de test, j'ai repris l'image dockercloud/hello-world modifiée avec le logo Osones, qui nous permettra de vérifier la load balancing simplement. Les labels servent à donner les informations à Traefik.
- Un backend représente ici un service. Si traefik décide de forwarder les requêtes web à un backend, celles-ci seront load balancées entre tous les conteneurs appartenant à ce backend.
- Un frontend peut être assimiler à la directive
server_name
chez Nginx. Cela permet de contrôler le trafic entrant. Ici la règle est simple et stipule que le header http "Host" doit être àhello.docker
pour faire parti de ce frontend.
D'autres labels peuvent être utilisés pour spécifier différents paramètres à Traefik comme le poids du conteneur au sein du backend.
Pas besoin d'exposer de port, nous sommes sur un seul host, le trafic se fera au sein du bridge docker0.
Ah et la conf Traefik traefik.toml
!
[docker]
domain = "docker"
endpoint = "unix:///var/run/docker.sock"
watch = true
Ouais c'est tout.
On peut ensuite lancer tout ça : docker-compose up -d
Pour le test, j'ai ajouté 127.0.0.1 hello.docker
dans mon fichier /etc/hosts
.
Vous pouvez tester l'URL http://hello.docker
dans votre navigateur. La page du conteneur osones/helloworld
devrait fonctionner.
Mais ce qui est vraiment intéressant c'est que si on augmente le nombre de conteneur osones/helloworld
docker-compose scale webapp=5
Et qu'on recharge plusieurs fois notre page web, on voit bien le round-robin s'effectuer !
La même chose avec un discovery service existant
Dans l'exemple précédent nous avons donné accès à Traefik directement au socket Docker. Mais il est possible que votre infra dispose déjà d'un cluster Consul par exemple et que vous souhaitiez vous en servir comme backend pour Traefik.
Avec Consul, on a deux options, soit utiliser son KV Store ou son catalogue. De base, le KV Store est vide. Registrator ne peuple pas le KV Store mais le catalogue, le KV Store est juste là si vous en avez besoin mais il est vide de base.
Le catalogue :
curl localhost:8500/v1/catalog/services | jq .
{
"consul": [],
"hello": [],
"osones/helloworld": [
"traefik.backend=hello2",
"traefik.frontend.rule=Host:hello2.osones.com"
]
}
Le KV Store
curl http://localhost:8500/v1/kv/\?recurse
curl -X PUT -d 'good' http://localhost:8500/v1/kv/web/osones
curl http://localhost:8500/v1/kv/\?recurse | jq .
[
{
"CreateIndex": 35,
"ModifyIndex": 35,
"LockIndex": 0,
"Key": "web/osones",
"Flags": 0,
"Value": "Z29vZA=="
}
]
Le KV doit être rempli pour être utilisé. Il y'a donc peu de chance que vous ayez privilégié cette méthode alors que des outils comme registrator peuvent faire le travail pour vous et peupler le catalogue.
Repartons sur un docker-compose.yml :
version: "2"
services:
consul:
image: progrium/consul
command: -server -bootstrap
ports:
- "8500:8500"
labels:
SERVICE_IGNORE: "true"
registrator:
depends_on:
- consul
image: gliderlabs/registrator
command: -internal consul://172.17.0.1:8500
volumes:
- "/var/run/docker.sock:/tmp/docker.sock"
traefik:
depends_on:
- consul
image: traefik:1.5
ports:
- "80:80"
- "8080:8080"
volumes:
- "$PWD/traefik.toml:/traefik.toml"
labels:
SERVICE_IGNORE: "true"
hello:
image: osones/helloworld
labels:
SERVICE_NAME: "hello"
hello2:
image: osones/helloworld
labels:
SERVICE_TAGS: "traefik.backend=hello2,traefik.frontend.rule=Host:hello2.osones.com"
Et le traefik.toml
logLevel = "DEBUG"
[web]
address = ":8080"
[consulCatalog]
endpoint = "172.17.0.1:8500"
domain = "consul.local"
prefix = "traefik"
Prenons le conteneur "hello" :
Si aucun SERVICE_NAME n'est défini, une URL de la forme "nom_image"."traefik_domain" sera créee.
SERVICE_NAME permet d'override le nom de l'image et vous pouvez override toute l'URL avec traefil.frontend.rule
.
Les paramètres Traefik ne sont plus passés directement au conteneur mais sont passés à Consul via SERVICE_TAGS :
curl localhost:8500/v1/catalog/service/helloworld | jq .
[
{
"Node": "128688b27e1f",
"Address": "172.18.0.3",
"ServiceID": "0a2be7713001:consul_hello2_1:80",
"ServiceName": "helloworld",
"ServiceTags": [
"traefik.backend=hello2",
"traefik.frontend.rule=Host:hello2.osones.com"
],
"ServiceAddress": "172.18.0.4",
"ServicePort": 80
}
]
Deux URL sont donc disponibles, hello.consul.local
et hello2.osones.com
donnant respectivement accès aux backends hello
et hello2
.
Conclusion
Bien que consul-template permettait déjà d'effectuer beaucoup d'update de configuration de façon automatique, Traefik apporte énormément de simplicité et de puissance ainsi qu'une compatibilité avec énormément de produit.
Une présentation des Ingress Controllers sous Kubernetes ainsi qu'une intérgration avec Traefik et Let's Encrypt en bonus est disponible ici !
Aller plus loin :
(Re)découvrez les derniers articles Osones !
Si vous les avez loupés, voici les nouveaux articles sur le Blog Osones :
- Construire un pipeline de déploiement continu avec Kubernetes et Concourse-CI
- Conteneurs sur AWS : ECS, EKS, ou Fargate ?
- Multi git branches workflow with Concourse-CI (EN)
- Kubernetes : Introduction aux PetSet et bootstrap d'un cluster Consul
Rejoignez vous aussi la conversation !
- Questions, remarques, suggestions... Contactez-nous directement sur Twitter sur @osones !
- Pour discuter avec nous de vos projets, nous sommes disponibles directement via contact@osones.com !
Découvrez les derniers articles d'alter way
- : Prowler : L'outil de sécurité multi-cloud indispensable pour renforcer votre infrastructure
- : Kubernetes : plateforme "star" de l'IT et levier d'innovation des entreprises
- AI_dev2024
- : DirectPV : Avoir du stockage bloc distribué facilement dans kubernetes
- : Simple comme GitOps : kluctl
- Conférence Wax 2024 @thecamp