Asegurar y Observar Microservicios con un Service Mesh
Cómo desplegar Istio o Linkerd para agregar mTLS, gestión de tráfico, observabilidad y enforcement de políticas a microservicios sin cambiar código de aplicación.
Visión general
Los microservicios se comunican a través de la red, y la red no es confiable. Cada llamada inter-servicio cruza límites de pod, límites de nodo y potencialmente límites de cluster. Sin encriptación, atacantes con acceso a la red pueden leer o modificar tráfico. Sin identidad, cualquier servicio comprometido puede impersonar a otro. Sin observabilidad, debuggear un request que atraviesa 10 servicios es casi imposible.
Un service mesh resuelve estos problemas insertando un proxy — un sidecar container — al lado de cada pod de aplicación. Todo el tráfico entrante o saliente del pod fluye a través del sidecar. El sidecar maneja mTLS mutuo, enrutamiento de tráfico, retries, timeouts, métricas y políticas de acceso. El código de aplicación permanece completamente inconsciente. Aqui se explica como conceptos de service mesh, despliegue de Istio, políticas de tráfico y observabilidad.
Cuándo usarlo
Usa esta receta cuando:
- Ejecutando 10+ microservicios en Kubernetes con comunicación inter-servicio compleja
- Requiriendo encriptación para todo el tráfico servicio-a-servicio sin modificar aplicaciones
- Implementando despliegues canary, A/B testing o mirroring de tráfico entre versiones de servicios
- Necesitando observabilidad unificada (métricas, logs, traces) a través de todos los microservicios
- Haciendo enforcement de políticas de acceso (ej. “el servicio de pagos solo puede hablar con billing y fraud detection”)
Solución
Instalación de Istio (istioctl)
istioctl install --set profile=default -y
kubectl label namespace default istio-injection=enabled
kubectl rollout restart deployment -n default
Enrutamiento de Tráfico con VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: user-service-route
spec:
hosts:
- user-service
http:
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: user-service
subset: v2
weight: 100
- route:
- destination:
host: user-service
subset: v1
weight: 90
- destination:
host: user-service
subset: v2
weight: 10
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: user-service-dr
spec:
host: user-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
mTLS con PeerAuthentication
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
---
# Permitir solo servicios específicos a acceder payment-service
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: payment-policy
namespace: default
spec:
selector:
matchLabels:
app: payment-service
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/order-service"
- "cluster.local/ns/default/sa/billing-service"
Explicación
- Sidecar proxy: Envoy corre como sidecar en cada pod. Intercepta todo el tráfico de red vía reglas de iptables. Las aplicaciones aún hablan a
localhost:8080, pero Envoy enruta, encripta y loguea el request real. El código de aplicación no requiere cambios. - Mutual TLS (mTLS): el sidecar proporciona un certificado para probar su identidad y valida el certificado del peer. El tráfico está encriptado en tránsito y autenticado en ambos extremos. Incluso dentro del mismo cluster, los servicios no pueden impersonarse entre sí sin robar un certificado.
- Gestión de tráfico: VirtualService define reglas de enrutamiento — despliegues canary, retries, timeouts, inyección de fallos. Las políticas de tráfico son declarativas y versionadas en Git.
- Observabilidad: Istio agrega esto en Kiali (topología), Grafana (métricas) y Jaeger (traces). Ves el grafo completo de servicios sin agregar instrumentación a las aplicaciones.
Variantes
| Feature | Istio | Linkerd | Consul Connect | Cilium Service Mesh |
|---|---|---|---|---|
| Complejidad | Alta | Baja | Media | Media |
| Performance | Buena | Excelente | Buena | Excelente (eBPF) |
| mTLS | Sí | Sí | Sí | Sí |
| Enrutamiento de tráfico | Completo | Básico | Básico | Básico |
| Uso de recursos | Mayor | Menor | Media | Bajo |
Lo que funciona
- Empieza con mTLS permisivo, luego enforce estricto: Después de validar flujos de tráfico, cambia a
STRICTpara rechazar conexiones no encriptadas. El modo estricto repentino puede romper servicios que no tienen sidecars. - Define service accounts por workload: las cuentas de servicio de Kubernetes se mapean a identidades de Istio. Esto habilita políticas de autorización granulares.
- Configura retry budgets, no solo retries: retries ingenuos pueden amplificar fallos. Retries ilimitados crean retry storms.
- Usa circuit breakers en cada llamada saliente: Si un servicio downstream retorna 5xx en el 50% de requests durante 30 segundos, échalo durante 30 segundos. Esto previene fallos en cascada.
- Monitorea el uso de recursos del sidecar: Envoy consume CPU y memoria. Setea resource requests/limits en el sidecar. En servicios de alto throughput, el sidecar puede convertirse en el bottleneck antes que la aplicación. Profilea y tunea la concurrencia del proxy.
Errores comunes
- Olvidar inyección de sidecar: un pod sin sidecar bypassa el mesh completamente. Su tráfico no está encriptado, no es observado y no tiene restricciones. Siempre verifica la inyección con
kubectl get pod -o yaml | grep istio-proxy. - Políticas de autorización demasiado permisivas: una política
ALLOW *por defecto derrota el propósito. Empieza conDENY allexplícito, luego agrega reglasALLOWpara paths legítimos. Zero-trust significa denegar por defecto. - Ignorar ordering de startup: durante rolling updates, pods antiguos sin sidecar pueden hablar con pods nuevos con mTLS estricto.
- Sin control de egress: por defecto, el tráfico mesh-internal está controlado pero el egress (APIs externas, bases de datos) no.
Preguntas frecuentes
Instalación de Linkerd (CLI)
# Instalar control plane de Linkerd
linkerd install --crd-only | kubectl apply -f -
linkerd install | kubectl apply -f -
# Verificar instalación
linkerd check
# Agregar mesh a un namespace
kubectl annotate namespace default linkerd.io/inject=enabled
# Reiniciar deployments
kubectl rollout restart deployment -n default
Traffic Mirroring para Shadow Testing
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: payment-mirror
spec:
hosts:
- payment-service
http:
- route:
- destination:
host: payment-service
subset: v1
weight: 100
mirror:
host: payment-service
subset: v2
mirrorPercentage:
value: 100.0
Fault Injection para Resilience Testing
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: order-fault-injection
spec:
hosts:
- order-service
http:
- match:
- headers:
x-test-fault:
exact: "true"
fault:
delay:
percentage:
value: 50
fixedDelay: 5s
abort:
percentage:
value: 10
httpStatus: 503
route:
- destination:
host: order-service
subset: v1
Observabilidad con Kiali y Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: istio-metrics
namespace: istio-system
spec:
selector:
matchLabels:
istio: mesh
endpoints:
- port: http-monitoring
interval: 15s
path: /stats/prometheus
---
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-observability
namespace: istio-system
spec:
accessLogging:
- providers:
- name: envoy
tracing:
- providers:
- name: jaeger
randomSamplingPercentage: 10.0
metrics:
- providers:
- name: prometheus
Egress Gateway para Control de APIs Externas
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-api
spec:
hosts:
- api.stripe.com
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: egress-stripe
spec:
hosts:
- api.stripe.com
http:
- route:
- destination:
host: api.stripe.com
port:
number: 443
timeout: 10s
retries:
attempts: 3
perTryTimeout: 3s
retryOn: 5xx,reset,connect-failure
Recursos Relacionados
Diseñar Microservicios Resilientes con Circuit Breakers,
Cómo construir sistemas distribuidos tolerantes a fallos usando patrones de microservicios incluyendo circuit breakers, bulkheads, retries con backoff y sagas para gestión de transacciones.
RecipeDiseñar un API Gateway Escalable para Microservicios
Construí un gateway de API que enrute requests, maneje autenticación, rate limiting, caching y traducción de protocolos entre clientes y microservicios backend.
RecipeDistribuir Tráfico con Algoritmos de Load Balancing
Cómo distribuir requests entrantes entre múltiples servidores usando round-robin, least-connections, weighted y consistent hashing con health checks y failover.
RecipeGestionar Secretos de Aplicaciones de Forma Segura
Cómo almacenar, rotar e inyectar API keys, contraseñas de base de datos y certificados sin hardcodearlos en código fuente o archivos de entorno.