Wed, 2023/02/08 - 20:57
No sé exactamente como voy a explicar o compartir la experiencia que tengo de usar Traefik, desde su version 1.8 hasta la actual hasta esta fecha de publicación 2.9
Básicamente es Traefik con Docker provider
Partiendo de la base de tener instalado Docker en GNU/Linux, cualquier distribución tiene su solución para instalar Docker, cualquier duda ve a la documentación oficial de como instalar Docker en GNU/Linux. Quizá será una muy simple guía en donde muestre configuraciones que me funcionan y como ir organizando la estructura a medida de que agregamos servicios a Traefik. La cosa ha cambiado bastante desde que empece a escribir VirtualHosts ahora Docker nos facilita a ser mas abstractos con la plataforma y concentrarnos más en el servicio / aplicación, junto con esto enrutar hacia servicios no podría ser más fácil. Ahora los requisitos serían.
Requisitos
- Conocimientos básicos de network y configuración de networks, caen de perlas saber que ocurre a la hora de configurar los network en Docker
- Kernel y utilidades de GNU/Linux
- Conocer bien la distribución en la que te encuentras, actualmente muchas distribuciones tienen similitudes pero incluso así tienen detalles que es bueno conocer
- Definición de lo que es un Proxy y Edge Router (básicamente lo que es Traefik)
- Conocimientos básicos del Docker compose file
- Ganas de estar mucho tiempo buscando la razón de porque tu servicio no está público (aunque intentaré compartir detalles y trucos para evitar eso)
- Tener instalado Docker (no voy a cubrir aquí el modo rootless de Docker)
Puesta en Servicio de Traefik
Vamos a empezar por lo básico, levantar el contenedor de Docker, para esto usaremos siempre el modo orchestrate de Docker, que es simplemente escribir archivos "docker-compose.yml" y usar el comando "docker compose up -d"
creamos nuestro directorio
$ mkdir traefik-docker && cd $_
$ vim docker-compose-traefik.yml
Una vez creado el directorio y abierto nuestro primer Docker compose file escribimos lo siguiente.
version: '3.2'
services:
traefik:
container_name: traefik
image: traefik:v2.9
restart: unless-stopped # Suelo agregar esta regla, porque en el caso de hacer 'docker compose stop' y reiniciar el sistema esto garantiza que el container no iniciara
ports:
- '80:80/tcp'
- '433:433/tcp'
- '433:433/udp' # Para usar el HTTP/3 que es experimental en la versión previa a 3.0
networks:
- edge-router
volumes:
- ./acme.json:/acme.json
- type: bind
source: ./dynamic/conf
targe: /dynamic/conf
- ./traefik.yml:traefik.yml:ro
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock
healcheck:
test: [ "CMD", "traefik", "healthcheck" ]
interval: 1m
timeout: 5s
retries: 5
networks:
edge-router:
name: edge-router
attachable: true
Con esto ya tenemos el fichero del primer contenedor con traefik para capturar el trafico en los puertos 80/TCP y 443/TCP y UDP (para dar soporte a HTTP/3), ahora a crear el fichero traefik.yml con el siguiente contenido
global:
checkNewVersion: true
api: {}
providers:
docker:
exposedByDefault: false
watch: true
file:
directory: /dynamic/conf
watch: true
experimental:
http3: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
http3:
advertisedPort: 443
http:
tls:
certResolver: example_com
domains:
- main: example.com
sans:
- "www.example.com"
- "*.example.com" # Se necesita de dnsChallenge con Let's Encrypt
certificatesResolvers:
example_com:
acme:
email: tuto.traefik@example.com
storage: acme.json
dnsChallenge:
provider: digitalocean
delayBeforeCheck: '0'
Aquí podría detenerme y explicar punto a punto sobre el fichero de configuración de Traefik, pero quizá lo realice en otro post mas a fondo sobre la configuración, por los momentos como sus parámetros son muy explícitos doy por hecho que se entiende cada punto.
Hasta ahora tenemos configurado el docker compose file y la configuración de Traefik vamos agregar nuestra primera configuración dinámica, las configuraciones dinámicas nos ayudaran a compartir configuraciones comunes entre contenedores / servicios. Creemos un fichero en dynamic/conf/tsl.yml
tls:
options:
modern:
minVersion: VersionTLS13
sniStrict: true
flex:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
curvePreferences:
- CurveP521
- CurveP384
sniStrict: true
Esto esta configuración garantiza un certificado A+ usando la tls.flex, para servicios extrictos la tls.modern nos aseguran que solo dispositivos modernos puedan hacer el hand-shake con nuestro endpoint / router point.
Ya tenemos ahora sí todo lo necesario para ejecutar el comando docker compose -f docker-compose-traefik.yml up -d para así correr un contener con Traefik enrutando todo el tráfico de los puertos 80 y 443 hacia ese contendor usando el network host de Docker (esto es importante)
Nuestro primer servicio
Ahora que tenemos Traefik trabajando para nosotros como main entutador de los puertos comunes de Internet, vamos a crear un servicio, uno que sea útil, no un simple nginx whoami, vamos a crear un servicio de searxng, un buscador anonimo en modo self-hosting.
Vamos a crear la carpeta para este servicio para tener mas orgnizado este proyecto, dentro de la carpeta "traefik-docker" vamos a crear otra.
$ mkdir searxng && cd $_
Preparado la carpeta que nos organiza el chiringuito para tener las cosas un poco mas claras creamos nuestro docker-compose.yml
version: '3.7'
services:
redis:
container_name: redis
image: "redis:alpine"
command: redis-server --save "" --appendonly "no"
restart: unless-stopped
networks:
- searxng
tmpfs:
- /var/lib/redis
cap_drop:
- ALL
cap_add:
- SETGID
- SETUID
- DAC_OVERRIDE
healthcheck:
test: [ "CMD", "redis-cli", "--raw", "incr", "ping" ]
interval: 30s
timeout: 5s
retries: 5
searxng:
container_name: searxng
image: searxng/searxng:latest
restart: unless-stopped
networks:
- searxng
- edge-router
volumes:
- ./searxng/settings.yml:/etc/searxng/settings.yml:ro
environment:
- SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
labels:
- traefik.enable=true
- traefik.http.routers.searx_http.entrypoints=web
- traefik.http.routers.searx_http.rule=Host(`searxng.example.com`)
- traefik.http.routers.searx_http.middlewares=https-only@file
- traefik.http.routers.searx_https.entrypoints=websecure
- traefik.http.routers.searx_https.rule=Host(`searxng.example.com`)
- traefik.http.routers.searx_https.tls.options=flex@file
- traefik.http.routers.searx_https.middlewares=hardness-chained@file
- traefik.http.routers.searx_https.service=searxng
- traefik.http.services.searxng.loadbalancer.server.port=8080
networks:
edge-router:
external: true
searxng:
Luego de esto, es cuestion de levantar el servicio con docker compose up -d e ir a la dirección searxng.example.com, puntos para detallar.
- Importante estar atentos del networks en el docker-compose.yml ahí se usa el network exterior que definimos en el docker-compose de Traefik.
- Traefik está atento del socket de docker para mirar cualquier contener que active traefik y defina reglas
- La comunicación de trafico ocurre una vez traefik puede saber la IP del contenedor que active traefik