En este artículo, te muestro, como de una manera bastante sencilla, podemos desplegar Traefik v2.3.5 en Kubernetes.
Desde hace unos días estoy armando un ambiente de Kubernetes, específicamente corriendo k3s y me dispuse a instalar el reverse proxy, por supuesto, todo este tipo de experiencias son material para este blog y porque creo, que alguien seguramente debe estar buscando como hacerlo.
K3s
Si estás montando tu cluster de Kubernetes en K3s, en el momento que lo vas a instalar, tenés que pedirle que se saltee la parte de Traefik, ya que lo vamos a hacer nosotros, de manera manual y con la última versión disponible.
Para Instalar K3s sin Traefik, debemos correr lo siguiente:
$ curl -sfL https://get.k3s.io | sh -s - --disable=traefik
Una vez que K3s está corriendo, que podemos verificarlo de la siguiente manera:
$ kubectl get nodes
El resultado se vería mas o menos así: En mi caso, tengo dos nodos corriendo, pero si solo usas uno, deberías ver el "master" solamente.
NAME STATUS ROLES AGE VERSION
kube-master-27aa Ready master 17h v1.18.6+k3s1
kube-node-4f41 Ready worker 17h v1.18.6+k3s1
Declarando el recurso ingress y otras cosillas...
Vamos a empezar con la instalación, para eso, antes debemos declarar cual va a ser nuestro Ingress y algunas otras definiciones, usando CRD. Yo lo tengo especificado en un archivo llamado crd.yml y el mismo se ve de la siguiente manera:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutes.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRoute
plural: ingressroutes
singular: ingressroute
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: middlewares.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: Middleware
plural: middlewares
singular: middleware
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressroutetcps.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteTCP
plural: ingressroutetcps
singular: ingressroutetcp
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: ingressrouteudps.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: IngressRouteUDP
plural: ingressrouteudps
singular: ingressrouteudp
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: tlsoptions.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSOption
plural: tlsoptions
singular: tlsoption
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: tlsstores.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TLSStore
plural: tlsstores
singular: tlsstore
scope: Namespaced
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: traefikservices.traefik.containo.us
spec:
group: traefik.containo.us
version: v1alpha1
names:
kind: TraefikService
plural: traefikservices
singular: traefikservice
scope: Namespaced
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: traefik-ingress-controller
rules:
- apiGroups:
- ""
resources:
- services
- endpoints
- secrets
verbs:
- get
- list
- watch
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
- ingressclasses
verbs:
- get
- list
- watch
- apiGroups:
- extensions
resources:
- ingresses/status
verbs:
- update
- apiGroups:
- traefik.containo.us
resources:
- middlewares
- ingressroutes
- traefikservices
- ingressroutetcps
- ingressrouteudps
- tlsoptions
- tlsstores
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
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: default
Para aplicar esto, tal cual esta, debemos correr:
$ kubectl apply -f crd.yml
El resultado, se verá mas o menos así:
customresourcedefinition.apiextensions.k8s.io/ingressroutes.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/middlewares.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/ingressroutetcps.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/ingressrouteudps.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/tlsoptions.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/tlsstores.traefik.containo.us created
customresourcedefinition.apiextensions.k8s.io/traefikservices.traefik.containo.us created
clusterrole.rbac.authorization.k8s.io/traefik-ingress-controller created
clusterrolebinding.rbac.authorization.k8s.io/traefik-ingress-controller created
Desplegando Traefik
Ahora si se viene lo bueno, vamos a desplegar nuestro Traefik en un archivo llamado deployment.yml, el mismo tiene el siguiente contenido:
apiVersion: v1
kind: Service
metadata:
name: traefik
spec:
ports:
- protocol: TCP
name: web
port: 80
- protocol: TCP
name: websecure
port: 443
type: LoadBalancer
selector:
app: traefik
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: default
name: traefik-ingress-controller
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: default
name: traefik
labels:
app: traefik
spec:
replicas: 1
selector:
matchLabels:
app: traefik
template:
metadata:
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
containers:
- name: traefik
image: traefik:v2.3.5
args:
- --api
- --log.level=ERROR
- --accesslog
- --entrypoints.web.Address=:80
- --entrypoints.websecure.Address=:443
- --entrypoints.web.http.redirections.entryPoint.to=:443
- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --providers.kubernetescrd
- --providers.kubernetesingress
- --certificatesresolvers.myresolver.acme.tlschallenge
- --certificatesresolvers.myresolver.acme.email=tuemail@tudominio.com
- --certificatesresolvers.myresolver.acme.storage=acme.json
ports:
- name: web
containerPort: 80
- name: websecure
containerPort: 443
Acá básicamente lo que hacemos es definir el servicio, que se va a llamar Traefik y el mismísimo deployment, publicamos puertos, definimos la configuración de Let's Encrypt, la redirección, para que todo lo que sirvamos sea a través de SSL seteamos el numero de replicas y por favor, no se olviden de poner su correo electrónico en esta sección:
certificatesresolvers.myresolver.acme.email=tuemail@tudominio.com
Una vez que estamos listos, vamos a aplicar este deployment:
$ kubectl apply -f deployment.yml
El resultado debería ser algo como esto:
service/traefik created
serviceaccount/traefik-ingress-controller created
deployment.apps/traefik created
Comprobando...
Buenos, vamos a ver que todo este andando como esperamos. Para esto, podemos ejecutar un comando que nos va a permitir ver nuestros pods, en este caso deberiamos ver el de Traefik y uno (o varios, dependiendo de los nodos que tengas en tu cluster).
$ kubectl get pods
El resultado debería ser algo como esto:
NAME READY STATUS RESTARTS AGE
svclb-traefik-5f6qf 2/2 Running 0 2m59s
traefik-7b7f4d6f68-mrwb4 1/1 Running 0 2m57s
Todo parece estar bien, hagamos una comprobación más, corramos un pod de hello world para asegurarnos de que Traefik esta funcionando bien.
Este es el que vamos a correr y lo guardaremos con el nombre hello.yml
kind: Deployment
apiVersion: apps/v1
metadata:
name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: containous/whoami
---
apiVersion: v1
kind: Service
metadata:
name: hello-world
labels:
app: hello-world
spec:
ports:
- port: 80
name: hello-world
selector:
app: hello-world
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: hello-ingress
spec:
entryPoints:
- websecure
routes:
- match: Host(`midominio.com`)
kind: Rule
services:
- name: hello-world
port: 80
tls:
certResolver: myresolver
Ejecutamos con...
$ kubectl apply -f hello.yml
El resultado debería ser algo así:
deployment.apps/hello-world created
service/hello-world created
ingressroute.traefik.containo.us/hello-ingress created
Ahora, si apuntamos nuestro navegador a "midominio.com", veremos que nos redirige a https y nos mostrará algo parecido a esto:
Para ir cerrando
Como ves, no es muy complicado, es bastante rápido y sencillo. Da miedo lo largo y la cantidad de definiciones de los archivos yml, pero es un poco la gracia de Kubernetes, que sea algo completamente modular y que esos "módulos" puedan escalar, cambiar o ser diferentes dependiendo de nuestras necesidades.
Les dejo la receta lista para usar, solo tienen que cambiar su email en la configuración de Traefik y el nombre de dominio en el hello.yml.
¿Qué te pareció este artículo? ¿Te sirvió? ¿Tienes alguna duda o comentario? Puedes dejarla aquí abajo.
Buena semana.