--- title: "Cómo instalar la malla de servicios Linkerd en Kubernetes" description: "Instala Linkerd en Kubernetes, añade tus servicios a la malla con mTLS automático, consulta sus métricas con Linkerd Viz y reparte tráfico con HTTPRoute." category: "Kubernetes Avanzado" language: es source: https://cubepath.com/es/docs/kubernetes-avanzado/malla-de-servicios-de-kubernetes-con-linkerd updated: 2026-09-25 --- # Cómo instalar la malla de servicios Linkerd en Kubernetes 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. - `kubectl` configurado 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 | > Nota: desde 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: ```bash 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): ```bash export PATH="$HOME/.linkerd2/bin:$PATH" linkerd version --client ``` ```output 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: ```bash 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): ```bash 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: ```bash 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: ```bash linkerd install | kubectl apply -f - ``` Espera a que esté listo y valida la instalación: ```bash linkerd check ``` ```output linkerd-existence ----------------- √ 'linkerd-config' config map exists √ control plane pods are ready ... Status check results are √ ``` > Importante: el certificado raíz (trust anchor) que genera `linkerd install` caduca 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: ```bash linkerd viz install | kubectl apply -f - linkerd viz check ``` ```output 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: ```bash 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: ```bash 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`: ```bash kubectl -n emojivoto get pods ``` ```output 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: ```bash linkerd check --proxy -n emojivoto ``` > Consejo: si 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: ```bash linkerd viz stat deploy -n emojivoto ``` ```output 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`: ```bash 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: ```bash linkerd viz edges deploy -n emojivoto ``` ```output 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: ```bash 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: ```bash nano echo.yaml ``` ```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: ```bash 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`: ```bash 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' ``` ```output 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: ```bash nano echo-route.yaml ``` ```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 ``` ```bash 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' ``` ```output 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: ```bash 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: ```bash 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 ``` ```output 403 ``` El cliente de la malla sigue funcionando, porque presenta su identidad mTLS: ```bash 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 ` y comprueba la anotación con `kubectl get 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 -c linkerd-proxy -n ` 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.