Hace tiempo te estuve hablando del papel que jugaba el recurso Ingress Controller dentro del ecosistema de Kubernetes. En artículos anteriores te conté cómo hacer uso de Nginx para desarollar esta función e incluso cómo jugar con diferentes hostnames apoyándome en nip.io. Hoy quiero mostrarte cómo usar Traefik para este mismo objetivo.
Instalación de Traefik en el clúster de Kubernetes
Para mostrarte cómo funciona Traefik voy a usar un clúster de Kubernetes en Azure. Si todavía no tienes uno puedes crearlo con los siguiente comandos:
#Variables
RESOURCE_GROUP="traefik-aks"
LOCATION="northeurope"
AKS_NAME="traefik-demo"
#Create resource group
az group create -n $RESOURCE_GROUP -l $LOCATION
# Create AKS cluster
az aks create -n $AKS_NAME -g $RESOURCE_GROUP --node-count 1 --generate-ssh-keys
#Get the context for the new AKS
az aks get-credentials -n $AKS_NAME -g $RESOURCE_GROUP
Para poder utilizar Traefik necesitas crear una serie de recursos: el primero de ellos es una Service Account sobre la que aplicaremos después los permisos necesarios:
apiVersion: v1
kind: ServiceAccount
metadata:
name: traefik-ingress-controller
namespace: kube-system
También hay que definir qué es lo que quiero que haga esta service account, en este ejemplo usando un ClusterRole, que básicamente es visualizar lo relativo a servicios, sus endpoints y secretos:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses/status
verbs:
- update
Ahora, para asociar estos roles al service account anterior podemos usar un ClusterRoleBinding para que sea a nivel global del clúster y no asociado a un namespace en concreto (en el caso de que prefieras esto segundo deberías crear un RoleBinding en su lugar):
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: traefik-ingress-controller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: traefik-ingress-controller
subjects:
- kind: ServiceAccount
name: traefik-ingress-controller
namespace: kube-system
Por último, falta desplegar el Ingress Controller de Traefik. Como se comenta en su documentación, puedes hacerlo de dos formas: usando Deployments o Daemonsets. En este ejemplo lo he desplegado con un Daemonset:
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: traefik-ingress-controller
namespace: kube-system
labels:
k8s-app: traefik-ingress-lb
spec:
selector:
matchLabels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
template:
metadata:
labels:
k8s-app: traefik-ingress-lb
name: traefik-ingress-lb
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 60
containers:
- image: traefik:v1.7
name: traefik-ingress-lb
ports:
- name: http
containerPort: 80
hostPort: 80
- name: admin
containerPort: 8080
hostPort: 8080
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
args:
- --api
- --kubernetes
- --logLevel=INFO
Para finalizar con la configuración, necesitamos un recurso del tipo Service que será el punto de entrada a nuestro clúster utilizando Traefik:
kind: Service
apiVersion: v1
metadata:
name: traefik-ingress-service
namespace: kube-system
spec:
type: LoadBalancer
selector:
k8s-app: traefik-ingress-lb
ports:
- protocol: TCP
port: 80
name: web
Mi ejemplo difiere de la configuración mostrada en la documentación en que el tipo de servicio es LoadBalancer, para que en este caso Azure me provea una IP pública (20.82.157.204) asociada al mismo.
Si has seguido todos estos pasos ya tienes Traefik configurado en tu clúster como Ingress Controller. Lo único que necesitas es crear Ingress Resources asociados a los Servicios que tiene que enrutar en base a las reglas que establezcas.
Ejemplo 1
Para poder probar Traefik puedes desplegar este ejemplo con la imagen de traefik/whoami.
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
selector:
matchLabels:
app: whoami
replicas: 3
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
selector:
app: whoami
ports:
- port: 7070
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: whoami-ingress
labels:
name: whoami-ingress
spec:
rules:
- host: whoami.20.82.157.204.nip.io
http:
paths:
- pathType: "Prefix"
path: "/"
backend:
service:
name: whoami
port:
number: 7070
Utilizo un recurso de tipo Ingress para asociar un host a una ruta concreta y el servicio, haciendo uso de nip.io. En este caso si accedes a http://whoami.TU_IP.nip.io te llevará al servicio llamado whoami accediendo a través del puerto 7070, donde verás la siguiente información:

Ejemplo 2
Para finalizar, voy a configurar el acceso al UI de Traefik, que forma parte del DaemonSet desplegado, que nos da de forma visual información sobre todos los Ingress configurados en el clúster. Sin embargo, para este ejemplo voy a querer que, además de enrutarme correctamente al servicio y por lo tanto al despliegue de esta interfaz web, el usuario tenga que autenticarse. Para ello, voy a crear antes un secreto con las credenciales para este acceso. Como las contraseñas tienen que estar hasheadas en MD5, SHA1 o BCrypt puedes usar htpassword con el siguiente formato:
#Create a secret for the basic authentication
htpasswd -c auth gis
Esto me generará un archivo con las credenciales del usuario gis con el siguiente aspecto:
gis:$apr1$WsmLAtfK$ndZnFVqE1U26.ziSAIOur.
Por último, puedes crear el secreto utilizando kubectl y haciendo uso de este nuevo archivo:
kubectl create secret generic traefik-web-ui-secret --from-file=auth -n kube-system
Como el servicio está desplegado en kube-system, este secreto y el recurso Ingress también tienen que estar en el mismo namespace. Para configurar estas credenciales, debo añadir la configuración en forma de anotaciones.
apiVersion: v1
kind: Service
metadata:
name: traefik-web-ui
namespace: kube-system
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- name: web
port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: traefik-web-ui
namespace: kube-system
annotations:
traefik.ingress.kubernetes.io/auth-type: "basic"
traefik.ingress.kubernetes.io/auth-secret: "traefik-web-ui-secret"
spec:
rules:
- host: traefik-ui.20.82.157.204.nip.io
http:
paths:
- pathType: "Prefix"
path: /
backend:
service:
name: traefik-web-ui
port:
name: web
Una vez que accedas a http://traefik-ui.TU_IP.nip.io e introduzcas las credenciales que has elegido podrás ver la interfaz que proporciona Traefik para ver las reglas configuradas:

Los frontends son las reglas que hemos definido y los backends son los recursos de tipo Service donde se muestran ademas los endpoints asociados a cada uno.
¡Saludos!