Introducción

Con este artigo quero comezar poñendo o primeiro bloque do meu proxecto de servizos auto aloxados. A idea con isto é ter un proxy que redirixa as chamadas ao servizo que corresponda. Isto é porque teño intención de ter varios servizos web funcionando, tales como Invidious, Searx, Syncthing, etc.
Para isto escollo Traefik, a lo menos de momento, se non me convence probarei outros como NGiNX, Caddy ou Envoy.

tal e como dí a documentación de traefik, trátase dun enrutador que recibirá as peticións e atopará os compoñentes responsables de ocuparse delas.
Como eles mesmos indican na documentación, descobre a configuración correcta dos servizos inspeccionando a infraestructura. Con esta información redirixe as peticións ao servizo adecuado.
Deste xeito non teremos que mapear distintos portos para poder acceder aos servizos. Non será necesario ter un Wordpress no porto 8082, un Django no 8083, etc. Toda-las peticións lle chegarán a Traefik e este detectará o destino. Ademais é compatible con Docker, Kubernetes e Docker Swarm, entre outros. O primeiro é o que estou a usar e os dous últimos algo que teño pensado practicar nalgún momento.

Instalando Traefik con Docker

O primeiro que comprobo é que xa hai unha imaxe oficial para Traefik en Docker Hub. Usarei esta imaxe para levantar o contenedor. Así só terei que facer un docker-compose.yaml no que engadirlle os volumes, a rede e demáis. Neste caso non vou facer un Dockerfile para este servizo, xa que parece traer o preciso para traballar.
Para comezar creo un novo repositorio en Codeberg, onde irei montando todo.

Como curiosidade a imaxe baséase nunha alpine e engade algunhas capas para copiar ficheiros e instalar certificados.

Ficheiro docker-compose.yaml

Este será polo momento o ficheiro ca configuración que vou usar.

version: '3.7'
services:
  Traefik:
    image: traefik:v3.0
    container_name: traefik
    command: --api.insecure=true --providers.docker
    init: true
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - "80:80"
      - "8080:8080"
    environment:
      - TZ=Europe/Madrid
    volumes:
      - $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock
networks:
  proxy:
    name: proxy
    external: true

Imos por partes para entender o ficheiro:

  • image: dígolle que imaxe quero que utilice. Neste caso a última imaxe estable é a v3.0. Non quero usar a latest para previr complicacións. Se nalgún momento actualizan algo podería haber algunha incompatibilidade, prefiro actualizar a man.

  • command: estoulle a indicar dous parámetros.
    • --api.insecure=true aquí dígolle que erga a interface web.
    • --providers.docker activa a escoita ao socket de docker. Que será o xeito no que recoñecerá outros servizos.
  • init: true activa o inicio do contenedor cun proceso init con PID 1.
    Para explicalo brevemente, os procesos medran en árbore. Por exemplo un proceso pode a súa vez lanzar outros procesos e estes outros, co cal fórmase esa árbore. De forma natural os procesos pai agardan a que rematen os procesos fillos, para recoller o seu estado de finalización e máis cousas. Pero se un proceso pai remata, de xeito intencional ou non, os fillos poden quedar orfos. Desta forma eses procesos poden producir comportamentos inesperados. Con esta bandeira init: true ese proceso con PID 1 que creamos, adoptará estes nodos orfos para que poidan rematar de xeito natural.

  • restart: unless-stopped no caso de que algo vaia mal e o contendor caia, volverá a levantarse ata que o paremos a man. O cal está ben cando, coma neste caso, queremos un servizo que estea funcionando permanentemente.

  • security_opt co valor no-new-privileges:true, evitamos que os procesos do contenedor unha vez iniciados poidan escalar en privilexios alén dos asignados ao inicio.

  • volumes: está a parte que tiven que modificar por mor de executar docker en modo rootless. Xa que orixinalmente na documentación de Traefik aparecía como /var/run/docker.sock:/var/run/docker.sock. Ao executalo sen a modificación obtiña o seguinte erro:
    • Traefik 2024-01-30T21:04:37+01:00 ERR Provider error, retrying in 3.277931364s error=”Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?” providerName=docker

Ao sustituír a ruta por $XDG_RUNTIME_DIR apunta ao socket específico para o usuario rootless. Se facemos un echo $XDG_RUNTIME_DIR podemos ver esa ruta. No meu caso /run/user/1001/.

  • external: true estoulle dicindo que a rede proxy non a ten que crear, que esta rede xa existe. Que foi creada fóra deste servizo.

Erro levantando o contenedor

Unha vez xa configurado ao executar docker-compose up ocorreume un erro que me impedía levantar o servizo.

ERROR: for Traefik  Cannot start service traefik: driver failed programming external connectivity on endpoint traefik (7358d9d3f5abdbf9e95be662fe47338658b85f3b4fa9536109af6640efd925c5): Error starting userland proxy: error while calling PortManager.AddPort(): cannot expose privileged port 80, you can add 'net.ipv4.ip_unprivileged_port_start=80' to /etc/sysctl.conf (currently 1024), or set CAP_NET_BIND_SERVICE on rootlesskit binary, or choose a larger port number (>= 1024): listen tcp4 0.0.0.0:80: bind: permission denied

Este erro indica que non teño permisos para vincular o servizo ao porto 80. Non é que estea ocupado, é que non teño permiso.

Nota: ao executar docker en modo rootless, non ten permisos para utilizar portos por debaixo do 1024. Para solventalo na documentación do proxecto indican os pasos. Noutro momento adicarei un artigo a isto se fose preciso.

Así que simplemente mudo o valor “80:80” por “8081:80”, facendo que o porto á escoita no noso equipo sexa o 8081 e internamente no contenedor será o 80.

Volvo executar docker-compose up e agora sí, o contenedor levanta sen erros:

$ docker-compose up
Removing traefik
Starting 49e3ebc0b618_Traefik ... done
Attaching to 49e3ebc0b618_Traefik

E podemos ver o panel de control.
Panel de control de Traefik

Comprobando o funcionamento

O proxecto de Traefik, ten unha imaxe para poder proba-lo servizo. Así que imos engadila temporalmente no docker-compose e ver que nos amosa. No apartado de servizos engadimos este:

whoami:
    # A container that exposes an API to show its IP address
    image: traefik/whoami
    labels:
      - "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"

Unha vez levantado o contenedor, podemos ir a ver no panel de control os servizos para comprobar que sae. whoami entre os servizos de Traefik

Conclusión

De momento non hai moito que ver. No seguinte artigo levantarei o primer servizo real que xestionará Traefik e que poderá ser accedido dende outros equipos da rede. Neste caso será Syncthing, que me permitirá sincronizar carpetas entre dispositivos, incluíndo o móbil.

Referencias

Documentación de Traefik: https://doc.traefik.io/traefik/
Vincular portos por debaixo do 1024 sen root: https://docs.docker.com/engine/security/rootless/#exposing-privileged-ports