migration de mon infra vers Tricot
Fri, 06 Dec 2024 19:20:30 +0200Je me baladais sur le site de l’association Deuxfleurs dont j’ai déjà parlé au sujet de leur serveur S3 Garage et je suis tombé cette page de leur guide qui présente les logiciels qu’ils ont développé.
A l’époque de ma découverte de Garage j’avais du faire l’impasse sur leurs autres outils mais ca été une “révélation” lorsque je suis tombé sur Tricot 😱
Je tiens à dire que ces hackers sont étonnants et leur association qui propose à leurs usagers d’être hébergé sur une infra auto-hébergés sur plusieurs sites mérite d’être largement plus connue => Comment rejoindre l’association.
Si on fait un petit flashback j’utilisais Caddy et notamment caddy-docker-proxy (voir aussi Nomad et Caddy). Ce module Caddy fonctionne comme Traefik c’est à dire qu’il se connecte sur la socket de Docker pour auto découvrir les services et appliquer un reverse proxy. Je l’ai plus ou moins détourné sur mon infra Nomad en utilisant des conteneurs vide (qui font un sleep) afin de publier un label permettant à Caddy de faire un reverse vers des services déployés sur d’autres serveurs Docker.
Cette technique est inutile si on utilise un Docker swarm dans lequel les Dockers sont connectés, mais Docker swarm rocks plus vraiment :/
Bref cela marche plutôt bien mais Tricot permet de s’en passer ! En effet quel intérêt d’utiliser la socket de Docker alors qu’il suffirait d’utiliser Consul ?!
Deuxfleurs a le bon goût d’utiliser Nomad et Consul et dans une telle infra les conteneurs peuvent enregistrer de l’information dans Consul via des tags comme je le faisais avec tags = ["allocport=${NOMAD_HOST_PORT_http}"]
.
Or si un reverse proxy pouvait lire directement la présence de ces tags dans Consul il pourrait automatiquement faire un reverse. Et c’est exactement ce que fait Tricot.
Il est d’ailleurs inspiré par le fonctionnement de Traefik comme on peut le voir sur le dépôt git : Tricot, a replacement for Traefik.
J’en ai eu marre de Traefik lors du passage à la version 2 qui a horriblement complexifié sa configuration. Caddy a été une libération par sa simplicité mais on va voir que Tricot est encore plus simple (plus besoin de conteneur qui sleep pour ajouter des labels) tout en étant aussi efficace, Rust n’ayant rien à envier à Go en terme de performance.
tricot.hcl
job "tricot" {
datacenters = ["dc1"]
type = "service"
group "proxy" {
count = 1
network {
mode = "bridge"
port "internal" {
static = 9334
to = 9334
host_network = "tailscale"
}
port "http-public" {
static = 80
to = 80
host_network = "public"
}
port "https-public" {
static = 443
to = 443
host_network = "public"
}
}
restart {
attempts = 2
interval = "2m"
delay = "30s"
mode = "fail"
}
task "tricot" {
driver = "docker"
constraint {
attribute = "${attr.unique.hostname}"
value = "node1"
}
config {
image = "fredix/tricot"
volumes = [
"secrets:/etc/tricot",
]
ports = ["internal", "http-public", "https-public"]
}
resources {
cpu = 400
memory = 1000
}
template {
data = <<EOH
TRICOT_NODE_NAME={{ env "attr.unique.hostname" }}
TRICOT_LETSENCRYPT_EMAIL=user@domain.tld
TRICOT_ENABLE_COMPRESSION=true
TRICOT_CONSUL_HOST=http://IP_TAILSCALE_SERVER_CONSUL:8500
TRICOT_CONSUL_TLS_SKIP_VERIFY=true
TRICOT_HTTP_BIND_ADDR=[::]:80
TRICOT_HTTPS_BIND_ADDR=[::]:443
TRICOT_METRICS_BIND_ADDR=[::]:9334
RUST_LOG=tricot=info
EOH
destination = "secrets/env"
env = true
}
service {
name = "tricot-http"
provider = "consul"
port = "http-public"
}
service {
name = "tricot-https"
provider = "consul"
port = "https-public"
}
service {
name = "tricot-metrics"
provider = "consul"
port = "internal"
}
}
}
}
Sur mon infra j’utilise Tailscale, j’ai donc besoin que Tricot ait une patte sur l’interface public et celle de Tailscale pour se connecter aux backends (voir la configuration de Nomad).
L’autre partie importante est la variable TRICOT_CONSUL_HOST
qui contient l’IP Tailscale du serveur Consul (sur Node3). Tricot va alors stocker dedans les certificats générés mais aussi lire les tags qui le concerne (qui commencent par tricot).
Comme exemple voici le hcl de Navidrome (Navidrome et l’autohébergement hybride V2)
navidrome.hcl
job "navidrome" {
datacenters = ["dc1"]
type = "service"
group "home" {
count = 1
network {
port "http" {
to = 4533 # container port the app runs on
host_network = "tailscale"
}
}
task "navidrome" {
driver = "docker"
constraint {
attribute = "${attr.unique.hostname}"
value = "nuc"
}
env {
ND_SCANSCHEDULE = "1h"
ND_LOGLEVEL = "info"
ND_SESSIONTIMEOUT = "24h"
ND_BASEURL = ""
}
config {
image = "deluan/navidrome:latest"
volumes = [
"/data/volumes/navidrome/:/data",
"/data/musiques:/music"
]
ports = [
"http"
]
}
resources {
cpu = 200
memory = 500
}
service {
name = "navidrome"
provider = "consul"
port = "http"
tags = ["tricot navidrome.domain.tld"]
}
}
}
}
La seule différence avec la version pour Caddy est le tag tags = ["tricot navidrome.domain.tld"]
. Cette présence dans Consul suffit à Tricot d’automatiquement faire un reverse en utilisant les autres données stockées par le service dans Consul comme l’IP et le port.
Tricot génère alors un certificat Let’s Encrypt et le stock dans Consul.
Terminé, finito 😎 🎉
Si on souhaite équilibrer la charge entre 4 conteneurs Docker, voici un exemple avec un simple whoami :
whoami.hcl
job "whoami" {
datacenters = ["dc1"]
type = "service"
group "home" {
count = 4
# Add an update stanza to enable rolling updates of the service
update {
max_parallel = 2
min_healthy_time = "30s"
healthy_deadline = "5m"
# Enable automatically reverting to the last stable job on a failed
# deployment.
auto_revert = true
}
network {
port "http" {
to = 80 # container port the app runs on
host_network = "tailscale"
}
}
task "whoami" {
driver = "docker"
constraint {
attribute = "${attr.unique.hostname}"
value = "nuc"
}
config {
image = "containous/whoami"
ports = [
"http"
]
}
resources {
cpu = 30
memory = 16
}
service {
name = "whoami"
provider = "consul"
port = "http"
tags = [
"tricot whoami.fredix.xyz",
"tricot-site-lb",
]
check {
type = "http"
name = "app_health"
path = "/"
interval = "20s"
timeout = "10s"
}
}
}
}
}
On note le tags qui possède une ligne de plus :
"tricot-site-lb"
Cette directive suffit à Tricot pour savoir qu’il doit répartir les requètes. On constate sur la page de whoami que le Hostname change régulièrement au bout d’un certain nombre de reload. En bonus grâce à la section update
vous pouvez modifier la configuration du hcl (par exemple monter ou descendre la memory) et relancer un nomad job run whoami.hcl
, les conteneurs se mettront à jour sans interruption de service 🙌
La beauté est comme toujours dans la simplicité et l’efficacité 😏
Hésitez pas à tester mon image fredix/tricot
ou bien construire la votre, j’ai fait un pull request pour rafraichir le Dockerfile à partir d’une image Alpine.
(Ce texte a été écrit avec VNote)