Traefik también puede cumplir la función de proxy inverso y balanceador de carga, automatiza la generación de certificados SSL con Letsencrypt, permite configurar middlewares globales por ejemplo para redirección de http a https, prevención de ataques DDOS, y middlewares por servicio como por ejemplo para lanzar una autenticación con .htpasswd.
Lo que distingue a Traefik, además de sus muchas funciones, es que descubre automáticamente la configuración adecuada para sus servicios. La magia sucede cuando Traefik inspecciona su infraestructura, donde encuentra información relevante y descubre qué servicio atiende qué solicitud.
Traefik cumple de forma nativa con todas las principales tecnologías de clúster, como Kubernetes, Docker, Docker Swarm, AWS, Mesos, Marathon, y la lista continúa ; y puede manejar muchos al mismo tiempo. (Incluso funciona para software heredado que se ejecuta en bare metal).
Con Traefik, no hay necesidad de mantener y sincronizar un archivo de configuración separado: todo sucede automáticamente, en tiempo real (sin reinicios, sin interrupciones de conexión). Con Traefik, dedica tiempo a desarrollar e implementar nuevas funciones en su sistema, y ya no a configurar y mantener su estado de funcionamiento.
Descripción del proyecto y como utilizarlo
A continuación se describe el proyecto traefik-sample, disponible en github, contiene una definición de plan de despliegue con docker-compose, además de:
- Generación automática de certificados SSL con Letsencrypt
- Middlewares globales (redirección http a https, rate limit para prevención de ataques DDOS
- Integración con servicios (microservicios con Laravel, Nginx, PWA sea React o Vue, Redis, MySQL, Adminer y Portainer)
- Middleware de servicio para lanzamiento de autenticación htpasswd
- Configuración de logs (si deseas optimizarlo puedes usar logrotate)
Requisitos
- git 2.2 o superior
- docker 20 o superior
- docker-compose 1.20 o superior
- Configura tus claves públicas y privadas con Github para siempre usar SSH con git
- Adrenalina y buena pasión por el código
## Clona el repositorio
Clona el proyecto de traefik-sample en tu directorio de trabajo, por ejemplo:
mkdir github
cd github
git clone git@github.com:marcotorres/traefik-sample.git
## Makefile
Este repositorio contiene un archivo Makefile con comandos preparados para iniciar los servicios de los contenedores, ver los los, estados de los servicios y poder ingresar a cada contenedor definido en el plan de despliegue del docker-compose.yml
.PHONY: help
CMD ?= ''
help: ## This help.
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
.DEFAULT_GOAL := help
start: ## Start the application
@echo "Starting the application"
@docker-compose up -d
restart: ## Restart the application
@echo "Restarting the application"
@docker-compose restart
stop: ## Stop the application
@echo "Stopping the application"
@docker-compose down
status: ## Status the application
@echo "Showing the status for the application"
@docker-compose ps
logs: ## Show the all Logs from the application
@echo "Showing all logs for every container"
@docker-compose logs -f --tail="50"
cli_api: ## Enter to container console from API
@echo "Entering to container console from API"
@docker exec -ti api bash
cli_web: ## Enter to container console from WEB
@echo "Entering to container console from WEB"
@docker exec -ti web sh
cli_db: ## Enter to container console from MySQL
@echo "Entering to container console from MySQL"
@docker exec -ti mysql bash
## docker-compose.yml
A continuación se muestra el contenido del archivo docker-compose.yml, podemos observar las definición del plan de despliegue de cada servicio.
version: "3.8"
networks:
infra:
traefik:
external:
name: traefik
default:
driver: bridge
volumes:
traefik_sample_data_portainer:
traefik_sample_data_mysql:
services:
traefik:
image: traefik:v2.3
container_name: traefik
restart: unless-stopped
networks:
traefik:
ipv4_address: 192.168.90.254
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
- target: 8080
published: 8080
protocol: tcp
mode: ingress
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/traefik.yml
- ./traefik/acme.json:/acme.json
- ./traefik/traefik.log:/traefik.log
- ./traefik/rules:/rules
- ./traefik/shared:/shared
labels:
- "traefik.enable=true"
# router
- "traefik.http.routers.traefik-rtr.entrypoints=websecure"
- "traefik.http.routers.traefik-rtr.rule=Host(`traefik.$HOSTNAME`)"
- "traefik.http.routers.traefik-rtr.tls=true"
- "traefik.http.routers.traefik-rtr.tls.certresolver=le"
# service api
- "traefik.http.routers.traefik-rtr.service=api@internal"
# middlewares
- "traefik.http.routers.traefik-rtr.middlewares=rate-limit@file,myauth@file"
api:
image: webdevops/php-nginx:8.1-alpine
container_name: api
working_dir: /app
restart: always
networks:
- traefik
- infra
volumes:
- ./apps/api:/app:rw
- ./nginx/nginxapi.conf:/etc/nginx/nginx.conf
environment:
- WEB_DOCUMENT_ROOT=/app/public
- VIRTUAL_HOST=api.$HOSTNAME
labels:
- "traefik.enable=true"
# router
- "traefik.http.routers.api-rtr.entrypoints=websecure"
- "traefik.http.routers.api-rtr.rule=Host(`api.$HOSTNAME`)"
- "traefik.http.routers.api-rtr.tls=true"
- "traefik.http.routers.api-rtr.tls.certresolver=le"
web:
image: webdevops/nginx:latest
container_name: web
working_dir: /app
restart: always
networks:
- traefik
- infra
volumes:
- ./apps/web:/app:rw
environment:
- WEB_DOCUMENT_ROOT=/app/build
- WEB_ALIAS_DOMAIN=web.$HOSTNAME
- WEB_DOCUMENT_INDEX=index.html
labels:
- "traefik.enable=true"
# router
- "traefik.http.routers.intranet-rtr.entrypoints=websecure"
- "traefik.http.routers.intranet-rtr.rule=Host(`web.$HOSTNAME`)"
- "traefik.http.routers.intranet-rtr.tls=true"
- "traefik.http.routers.intranet-rtr.tls.certresolver=le"
adminer:
image: adminer:latest
container_name: adminer
restart: always
networks:
- traefik
- infra
volumes:
- ./adminer/plugins-enabled:/var/www/html/plugins-enabled:rw
- ./adminer/robots.txt:/var/www/html/robots.txt
labels:
- "traefik.enable=true"
# router
- "traefik.http.routers.adminer-rtr.entrypoints=websecure"
- "traefik.http.routers.adminer-rtr.rule=Host(`adminer.$HOSTNAME`)"
- "traefik.http.routers.adminer-rtr.tls=true"
- "traefik.http.routers.adminer-rtr.tls.certresolver=le"
# middlewares
- "traefik.http.routers.adminer-rtr.middlewares=rate-limit@file,myauth@file"
mysql:
image: mysql:8.0.25
container_name: mysql
working_dir: /app
restart: on-failure
networks:
- infra
security_opt:
- no-new-privileges:true
ports:
- "3306:3306"
volumes:
- ${PWD}/data:/app:rw
- ${PWD}/mysql/my.cnf:/etc/mysql/conf.d/my-over.cnf
- traefik_sample_data_mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
MYSQL_DATABASE: $MYSQL_DATABASE
MYSQL_USER: $MYSQL_USER
MYSQL_PASSWORD: $MYSQL_PASSWORD
redis:
image: redis:alpine
container_name: redis
restart: unless-stopped
ports:
- "6380:6379"
networks:
- infra
security_opt:
- no-new-privileges:true
portainer:
image: portainer/portainer:latest
container_name: portainer
restart: unless-stopped
command: -H unix:///var/run/docker.sock
networks:
traefik:
ipv4_address: 192.168.90.253
security_opt:
- no-new-privileges:true
volumes:
- itraefik_sample_data_portainer:/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
- TZ=$TZ
labels:
- "traefik.enable=true"
# router
- "traefik.http.routers.portainer-rtr.entrypoints=websecure"
- "traefik.http.routers.portainer-rtr.rule=Host(`portainer.$HOSTNAME`)"
- "traefik.http.routers.portainer-rtr.tls=true"
- "traefik.http.routers.portainer-rtr.tls.certresolver=le"
# services
- "traefik.http.routers.portainer-rtr.service=portainer-svc"
- "traefik.http.services.portainer-svc.loadbalancer.server.port=9000"
## traefik.yml
En esta parte observamos la definición del plan de despliegue de Traefik contenido en traefik.yml, en este punto recuerda que si estas haciendo pruebas con generación del certificado SSL, es mejor que lo hagas descomentando la sección del caServer, para más información sobre el rate limit de letsencrypt puedes revisar la siguiente documentación:
- Rate limit Letsencrypt production: https://letsencrypt.org/docs/rate-limits
- Rate limit Letsencrypt staging: https://letsencrypt.org/docs/staging-environment
- Para consultar la cantidad de certificados que tienes generados: https://crt.sh
global:
checkNewVersion: true
sendAnonymousUsage: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
traefik:
address: ":8080"
api:
dashboard: true
insecure: false
debug: true
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik
swarmMode: false
file:
directory: /rules
watch: true
log:
filePath: "/logs/traefik.log"
level: WARN # DEBUG, INFO, WARN, ERROR, FATAL, PANIC
format: json
accessLog:
filePath: "/logs/traefik.log"
bufferingSize: 100
format: json
filters:
statusCodes:
- "400-499"
retryAttempts: true
minDuration: "10ms"
fields:
defaultMode: keep
names:
ClientUsername: drop
headers:
defaultMode: keep
names:
User-Agent: redact
Authorization: drop
Content-Type: keep
certificatesResolvers:
le:
acme:
email: log@traefik-sample.com
storage: "/acme.json"
#caServer: https://acme-staging-v02.api.letsencrypt.org/directory # no comentar para pruebas indefinidas
httpChallenge:
entryPoint: web
## middlewares.toml
A continuación se muestra el contenido del archivo middlewares.toml, aquí tenemos la definición de los middlewares para una autenticación básica con htpasswd y prevención de ataques http con un rate limit por minuto de a lo mucho 100 request.
[http.middlewares]
[http.middlewares.myauth]
[http.middlewares.myauth.basicAuth]
realm = "Traefik Basic Auth"
usersFile = "/shared/.htpasswd"
[http.middlewares.rate-limit]
[http.middlewares.rate-limit.rateLimit]
average = 100
burst = 50
## .env, logs y acme.json
Para poder iniciar el proyecto no te olvides de crear el archivo .env basado en .env.example, puedes ejecutar los siguientes comandos como una pequeña configuración inicial.
cp .env.example .env && \
cp traefik/acme.json.example traefik/acme.json && \
cp traefik/logs/traefik.log.example traefik/logs/traefik.log && \
cp traefik/shared/.htpasswd.example traefik/shared/.htpasswd && \
chmod 0600 traefik/acme.json
## Docker network y repositorios propios
No te olvides de que en la carpera ./apps/api y ./apps/web deben de ir tus proyectos que están en Laravel (microservicio) y React o Vue (PWA) y que antes de levantar los servicios tengas creado un docker network externo, puedes crearlo con el siguiente comando:
docker network create --gateway 192.168.90.1 --subnet 192.168.90.0/24 traefik
## Make CLI
Levanta el proyecto ya sea con docker-compose o con make así:
make start
Otras utilidades del Makefile:
Más documentación del proyecto en Github, traefik-sample
Espero que esta guía te haya servido de ayuda, hasta una proxima oportunidad.
Social Plugin