Linkerd es una malla de servicios (service mesh) para Kubernetes centrada en la sencillez: añade a cada pod un micro-proxy escrito en Rust que cifra el tráfico con mTLS, mide latencia y tasa de éxito, y aplica reintentos y reparto de tráfico sin cambiar el código. Consume bastante menos que Istio y se instala en unos minutos. En este tutorial instalarás Linkerd, meterás una aplicación de ejemplo en la malla, consultarás sus métricas y harás un despliegue canario con un HTTPRoute de Gateway API.
Requisitos previos
Para seguir esta guía necesitas:
- Un clúster de Kubernetes en una versión soportada por Linkerd (consulta la documentación de la release que instales), por ejemplo sobre VPS de CubePath con Ubuntu 24.04.
kubectlconfigurado con permisos de administrador del clúster, en un equipo Linux o macOS.- Al menos 1 GB de RAM libre en el clúster para el plano de control y la extensión Viz.
Linkerd frente a Istio
| Aspecto | Linkerd | Istio |
|---|---|---|
| Proxy | linkerd2-proxy (Rust), específico para Linkerd | Envoy (C++), de propósito general |
| mTLS | Activado por defecto al entrar en la malla | Activado por defecto en modo permisivo |
| Configuración de tráfico | Gateway API (HTTPRoute) y anotaciones | VirtualService, DestinationRule, Gateway API |
| Consumo y complejidad | Bajos | Mayores, a cambio de más funciones |
Notadesde 2024 el proyecto open source solo publica versiones edge (semanales, con nombres como
edge-25.x.y). Las versiones stable las distribuye Buoyant. Este tutorial usa el canal edge; en producción fija la versión y revisa sus notas antes de actualizar.
Paso 1: Instalar la CLI de Linkerd
La CLI linkerd genera los manifiestos de instalación y ofrece comandos de diagnóstico. Descarga el script de instalación oficial, revísalo y ejecútalo:
curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install-edge -o linkerd-install.sh
less linkerd-install.sh
sh linkerd-install.sh
El binario se instala en ~/.linkerd2/bin. Añádelo a tu PATH (y a tu ~/.bashrc para que sea permanente):
export PATH="$HOME/.linkerd2/bin:$PATH"
linkerd version --client
Client version: edge-25.9.2
Paso 2: Validar el clúster e instalar las CRD
linkerd check --pre comprueba que el clúster cumple los requisitos antes de instalar nada:
linkerd check --pre
Todas las comprobaciones deben terminar en √. Linkerd usa los recursos HTTPRoute y GRPCRoute de Gateway API para configurar el tráfico. Si la comprobación indica que faltan sus CRD, instala el canal estándar de Gateway API (revisa en la documentación de Linkerd qué versión admite tu release):
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml
Instala ahora las CRD propias de Linkerd:
linkerd install --crds | kubectl apply -f -
Paso 3: Instalar el plano de control
El plano de control incluye el servicio de identidad, que emite los certificados mTLS de cada proxy, el de destino, que informa a los proxies de los endpoints y políticas, y el inyector de proxies. linkerd install genera los certificados raíz automáticamente:
linkerd install | kubectl apply -f -
Espera a que esté listo y valida la instalación:
linkerd check
linkerd-existence
-----------------
√ 'linkerd-config' config map exists
√ control plane pods are ready
...
Status check results are √
Importanteel certificado raíz (trust anchor) que genera
linkerd installcaduca al año. Para producción, genera tus propios certificados o gestiónalos con cert-manager, siguiendo la guía de rotación de certificados de Linkerd.
Paso 4: Instalar la extensión Viz
La extensión Viz añade Prometheus, un panel web y los comandos linkerd viz para consultar métricas en tiempo real:
linkerd viz install | kubectl apply -f -
linkerd viz check
Status check results are √
Paso 5: Añadir una aplicación a la malla
Emojivoto es una aplicación de ejemplo del proyecto Linkerd con cuatro servicios y un generador de tráfico (vote-bot). Despliégala:
curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/emojivoto.yml | kubectl apply -f -
kubectl -n emojivoto rollout status deploy/web
Para añadirla a la malla, Linkerd necesita la anotación linkerd.io/inject: enabled en los pods o en su namespace. La forma recomendada es anotar el namespace, así cualquier pod nuevo se inyecta automáticamente, y reiniciar los Deployments existentes:
kubectl annotate namespace emojivoto linkerd.io/inject=enabled
kubectl -n emojivoto rollout restart deploy
kubectl -n emojivoto rollout status deploy/web
Cada pod tiene ahora dos contenedores, la aplicación y linkerd-proxy:
kubectl -n emojivoto get pods
NAME READY STATUS RESTARTS AGE
emoji-6d66d87995-9xk2b 2/2 Running 0 40s
vote-bot-b98dc7c55-lhq8m 2/2 Running 0 40s
voting-5f5b555dff-r4wqn 2/2 Running 0 40s
web-64cb5b6f7b-2hc6v 2/2 Running 0 40s
Comprueba que los proxies funcionan correctamente:
linkerd check --proxy -n emojivoto
Consejosi prefieres no anotar el namespace,
kubectl get deploy -n emojivoto -o yaml | linkerd inject - | kubectl apply -f -añade la anotación solo a esos Deployments.
Paso 6: Consultar métricas y comprobar mTLS
Linkerd mide para cada workload las métricas clave: tasa de éxito, peticiones por segundo y latencia. Consúltalas por Deployment:
linkerd viz stat deploy -n emojivoto
NAME MESHED SUCCESS RPS LATENCY_P50 LATENCY_P95 LATENCY_P99 TCP_CONN
emoji 1/1 100.00% 1.9rps 1ms 2ms 3ms 3
vote-bot 1/1 - - - - - -
voting 1/1 87.50% 0.9rps 1ms 2ms 4ms 3
web 1/1 91.91% 1.9rps 2ms 10ms 28ms 3
La tasa de éxito de voting no es del 100 % a propósito: emojivoto devuelve un error al votar un emoji concreto, precisamente para que puedas practicar el diagnóstico. Para ver las peticiones en tiempo real, incluidas las que fallan, usa tap:
linkerd viz tap deploy/web -n emojivoto --to deploy/voting
Pulsa Ctrl+C para salir. Para comprobar que el tráfico entre servicios va cifrado, muestra las conexiones entre workloads:
linkerd viz edges deploy -n emojivoto
SRC DST SRC_NS DST_NS SECURED
vote-bot web emojivoto emojivoto √
web emoji emojivoto emojivoto √
web voting emojivoto emojivoto √
La columna SECURED confirma que cada conexión usa mTLS, sin haber configurado ningún certificado a mano.
Para abrir el panel web de Viz, que muestra lo mismo de forma gráfica:
linkerd viz dashboard
El comando crea un reenvío de puertos y abre el navegador en http://localhost:50750.
Paso 7: Repartir tráfico entre versiones con HTTPRoute
Linkerd implementa la especificación GAMMA de Gateway API: un HTTPRoute cuyo parentRef es un Service modifica el tráfico que los clientes de la malla envían a ese Service. Así se hace un despliegue canario.
Crea un namespace anotado para la malla y dos versiones de un servicio sencillo basado en http-echo, que responde con un texto fijo:
nano echo.yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo
annotations:
linkerd.io/inject: enabled
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-v1
namespace: demo
spec:
replicas: 1
selector:
matchLabels: {app: echo, version: v1}
template:
metadata:
labels: {app: echo, version: v1}
spec:
containers:
- name: echo
image: hashicorp/http-echo:1.0
args: ["-text=v1"]
ports:
- containerPort: 5678
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-v2
namespace: demo
spec:
replicas: 1
selector:
matchLabels: {app: echo, version: v2}
template:
metadata:
labels: {app: echo, version: v2}
spec:
containers:
- name: echo
image: hashicorp/http-echo:1.0
args: ["-text=v2"]
ports:
- containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
name: echo
namespace: demo
spec:
selector: {app: echo, version: v1}
ports:
- port: 5678
---
apiVersion: v1
kind: Service
metadata:
name: echo-v1
namespace: demo
spec:
selector: {app: echo, version: v1}
ports:
- port: 5678
---
apiVersion: v1
kind: Service
metadata:
name: echo-v2
namespace: demo
spec:
selector: {app: echo, version: v2}
ports:
- port: 5678
Los clientes siempre llaman al Service echo. Los Services echo-v1 y echo-v2 son los destinos del reparto.
Aplica el manifiesto y crea un pod cliente en el mismo namespace. Al estar el namespace anotado, el cliente también entra en la malla, algo imprescindible porque el reparto lo aplica el proxy del cliente:
kubectl apply -f echo.yaml
kubectl -n demo rollout status deploy/echo-v2
kubectl run curl -n demo --image=curlimages/curl --restart=Never --command -- sleep 3600
kubectl -n demo wait --for=condition=Ready pod/curl --timeout=120s
Sin ninguna regla, todo el tráfico va a v1:
kubectl -n demo exec curl -c curl -- sh -c 'for i in $(seq 1 50); do curl -s http://echo:5678; done | sort | uniq -c'
50 v1
Crea el HTTPRoute que manda el 90 % a v1 y el 10 % a v2. Las anotaciones añaden hasta dos reintentos ante errores 5xx y un timeout de 2 segundos por petición:
nano echo-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: echo-canary
namespace: demo
annotations:
retry.linkerd.io/http: 5xx
retry.linkerd.io/limit: "2"
timeout.linkerd.io/request: 2s
spec:
parentRefs:
- name: echo
kind: Service
group: ""
port: 5678
rules:
- backendRefs:
- name: echo-v1
port: 5678
weight: 90
- name: echo-v2
port: 5678
weight: 10
kubectl apply -f echo-route.yaml
kubectl -n demo exec curl -c curl -- sh -c 'for i in $(seq 1 50); do curl -s http://echo:5678; done | sort | uniq -c'
46 v1
4 v2
Para avanzar en el despliegue, ajusta los pesos (50/50 y después 0/100) y vuelve a aplicar el archivo. Para deshacerlo, borra el HTTPRoute y el tráfico volverá al Service echo.
Paso 8: Exigir clientes de la malla
Por defecto, un pod de la malla acepta tráfico de cualquier cliente, esté o no en la malla. La anotación config.linkerd.io/default-inbound-policy: all-authenticated hace que los pods solo acepten conexiones con mTLS de otros proxies de Linkerd. Aplícala al namespace demo y reinicia los pods para que la recojan:
kubectl annotate namespace demo config.linkerd.io/default-inbound-policy=all-authenticated
kubectl -n demo rollout restart deploy
kubectl -n demo rollout status deploy/echo-v1
Crea un cliente fuera de la malla, en el namespace default, que no tiene la anotación de inyección:
kubectl run curl-outside --image=curlimages/curl --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/curl-outside --timeout=120s
kubectl exec curl-outside -- curl -s -o /dev/null -w "%{http_code}\n" http://echo.demo:5678
403
El cliente de la malla sigue funcionando, porque presenta su identidad mTLS:
kubectl -n demo exec curl -c curl -- curl -s http://echo:5678
Para reglas más finas (por ejemplo, permitir solo a una ServiceAccount concreta), Linkerd ofrece los recursos Server, AuthorizationPolicy y MeshTLSAuthentication del grupo policy.linkerd.io.
Solución de problemas
Los pods muestran 1/1 tras anotar el namespace. La inyección solo ocurre al crear el pod. Reinicia los Deployments con kubectl rollout restart deploy -n <namespace> y comprueba la anotación con kubectl get namespace <namespace> -o yaml.
El reparto de tráfico no tiene efecto. El cliente debe estar en la malla, y el parentRef debe apuntar al Service y puerto que usa el cliente. Revisa el estado del HTTPRoute con kubectl describe httproute echo-canary -n demo: la condición Accepted debe ser True.
linkerd check avisa de que un certificado va a caducar. Rota el trust anchor y el certificado del emisor siguiendo la guía oficial antes de la fecha indicada; si caducan, los proxies dejarán de poder comunicarse.
Un pod con proxy no arranca. Consulta los registros del proxy con kubectl logs <pod> -c linkerd-proxy -n <namespace> y los del contenedor de inicialización linkerd-init, que configura las reglas de iptables.
Conclusión
Has instalado Linkerd con su extensión Viz, has metido una aplicación en la malla con mTLS automático, has consultado su tasa de éxito y latencia, has hecho un despliegue canario con HTTPRoute y has exigido que solo los clientes de la malla lleguen a tus pods. Como siguientes pasos puedes gestionar los certificados de Linkerd con cert-manager, conectar las métricas a tu Prometheus y Grafana existentes o definir políticas de autorización por ServiceAccount.
