Resolución de problemas de conectividad en Kubernetes: Uso efectivo de exec y port-forward
Resuelve problemas de conectividad en Kubernetes y de aplicaciones internas con confianza. Esta guía proporciona ejemplos prácticos del uso de `kubectl exec` para ejecutar comandos dentro de contenedores y `kubectl port-forward` para acceder de forma segura a servicios desde tu máquina local. Aprende a diagnosticar problemas de red, inspeccionar configuraciones y obtener información detallada sobre el comportamiento de tu aplicación dentro del clúster.
Resolución de problemas de conectividad en Kubernetes: Uso efectivo de exec y port-forward
Cuando un servicio de Kubernetes agota el tiempo de espera, normalmente necesitas responder una pregunta simple antes de poder arreglar algo: ¿dónde deja de funcionar la conexión? kubectl exec te permite probar desde dentro del clúster, cerca de la aplicación. kubectl port-forward te permite traer un pod o servicio a tu laptop sin cambiar un Ingress, LoadBalancer, regla de firewall o registro DNS.
Usados juntos, estos dos comandos te ayudan a evitar suposiciones. Puedes probar si la aplicación está escuchando, si el DNS del clúster funciona, si un Service apunta a los pods correctos y si el problema está en la red de Kubernetes o en la aplicación misma.
Entendiendo kubectl exec
El comando kubectl exec te permite ejecutar comandos dentro de un contenedor en ejecución dentro de un pod. Esto es increíblemente útil para inspeccionar registros, verificar configuraciones y ejecutar herramientas de diagnóstico directamente donde vive tu aplicación.
Úsalo con cuidado en producción. Estás ejecutando un comando dentro de un contenedor de carga de trabajo real. Un env, cat, curl o ss inofensivo es normal. Instalar paquetes, cambiar archivos o ejecutar diagnósticos costosos dentro de un pod en vivo puede ocultar el problema original o crear uno nuevo.
Sintaxis básica
La sintaxis fundamental para kubectl exec es:
kubectl exec <nombre-del-pod> -- <comando> [argumentos...]
<nombre-del-pod>: El nombre del pod en el que deseas ejecutar un comando.--: Este separador es crucial. Distingue entre las banderas dekubectly el comando que deseas ejecutar dentro del contenedor.<comando>: El comando a ejecutar dentro del contenedor (por ejemplo,ls,cat,ping).[argumentos...]: Cualquier argumento para el comando.
Acceso a shell interactivo
Uno de los usos más comunes de kubectl exec es obtener un shell interactivo (como bash o sh) dentro de un contenedor. Esto te permite explorar el sistema de archivos del contenedor y ejecutar múltiples comandos.
Para obtener un shell interactivo:
kubectl exec -it <nombre-del-pod> -- /bin/bash
-i(o--stdin): Mantiene stdin abierto incluso si no está adjunto.-t(o--tty): Asigna una pseudo-TTY, que es necesaria para sesiones de shell interactivas.
Ejemplo: Acceder a un shell bash en un pod llamado my-app-pod:
kubectl exec -it my-app-pod -- /bin/bash
Una vez dentro, puedes usar comandos estándar de Linux. Para salir del shell, escribe exit o presiona Ctrl+D. Si /bin/bash no está presente, prueba /bin/sh; muchas imágenes pequeñas no incluyen Bash.
Ejecutar un solo comando
También puedes ejecutar un solo comando sin un shell interactivo. Esto es útil para verificaciones rápidas o scripting.
Ejemplo: Verificar archivos en el directorio /app de my-app-pod:
kubectl exec my-app-pod -- ls /app
Ejemplo: Ver el contenido de un archivo de configuración config.yaml:
kubectl exec my-app-pod -- cat /etc/my-app/config.yaml
Especificar un contenedor dentro de un pod
Si tu pod tiene múltiples contenedores, debes especificar en qué contenedor ejecutar el comando usando la bandera -c.
kubectl exec <nombre-del-pod> -c <nombre-del-contenedor> -- <comando>
Ejemplo: Ejecutar env en el sidecar-container de multi-container-pod:
kubectl exec multi-container-pod -c sidecar-container -- env
Entendiendo kubectl port-forward
El comando kubectl port-forward te permite establecer un túnel seguro desde tu máquina local a un pod o servicio específico en tu clúster de Kubernetes. Esto es invaluable para depurar aplicaciones que no están expuestas externamente, acceder a bases de datos o probar APIs internas.
No es una ruta de tráfico de producción. Es un túnel de depuración a través de tu conexión con el servidor API. Si la conexión del servidor API se cae, tu túnel local también se cae.
Sintaxis básica
La sintaxis general es:
kubectl port-forward <nombre-del-pod> <puerto-local>:<puerto-remoto>
<nombre-del-pod>: El nombre del pod al que deseas conectarte.<puerto-local>: El puerto en tu máquina local que escuchará las conexiones.<puerto-remoto>: El puerto en el pod que recibirá el tráfico reenviado.
Ejemplo: Reenviar el puerto local 8080 al puerto 80 de my-app-pod:
kubectl port-forward my-app-pod 8080:80
Una vez que este comando se está ejecutando, puedes acceder a tu aplicación navegando a http://localhost:8080 en tu navegador web o usando herramientas como curl en tu máquina local.
Reenviar a un servicio
También puedes reenviar tráfico a un Service de Kubernetes en lugar de un pod específico. kubectl seleccionará automáticamente un pod que respalde ese servicio.
kubectl port-forward service/<nombre-del-servicio> <puerto-local>:<puerto-del-servicio>
Ejemplo: Reenviar el puerto local 3000 al puerto 80 del servicio my-service:
kubectl port-forward service/my-service 3000:80
Al reenviar a un Service, recuerda que kubectl elige un pod de respaldo. Si solo una réplica está rota, el reenvío a nivel de servicio puede pasarla por alto. Por ejemplo, un Deployment con tres pods puede tener dos pods saludables y un pod con una configuración incorrecta. Reenviar a service/my-service podría elegir un pod saludable y hacer que el servicio parezca correcto. Cuando sospeches de un problema específico de una réplica, reenvía al nombre exacto del pod.
Reenviar a Deployments o StatefulSets
De manera similar, puedes reenviar a Deployments o StatefulSets. kubectl seleccionará uno de los pods gestionados por el recurso especificado.
kubectl port-forward deployment/<nombre-del-deployment> <puerto-local>:<puerto-del-contenedor>
kubectl port-forward statefulset/<nombre-del-statefulset> <puerto-local>:<puerto-del-contenedor>
Vincular a una dirección específica
Por defecto, port-forward se vincula a localhost. Puedes especificar una dirección local diferente usando la bandera --address.
kubectl port-forward --address 127.0.0.1 <nombre-del-pod> <puerto-local>:<puerto-remoto>
Reenvío de múltiples puertos
kubectl port-forward puede reenviar múltiples puertos simultáneamente.
kubectl port-forward my-app-pod 8080:80 9090:90
Este comando reenvía el puerto local 8080 al puerto 80 del pod y el puerto local 9090 al puerto 90 del pod.
Escenarios comunes de resolución de problemas y soluciones
Escenario 1: La aplicación no responde, pero el pod parece saludable.
- Problema: El pod se está ejecutando, pero las solicitudes a su servicio están fallando o agotando el tiempo de espera. La aplicación podría tener problemas de configuración interna o estar bloqueada.
- Solución con
kubectl exec:- Obtén un shell interactivo en el pod:
kubectl exec -it <nombre-del-pod> -- /bin/bash - Dentro del shell, verifica los registros de la aplicación (por ejemplo,
tail -f /var/log/myapp.log). - Verifica los archivos de configuración interna de la aplicación.
- Verifica la conectividad de red desde dentro del pod a otros servicios usando
pingocurl(si están instalados).
- Obtén un shell interactivo en el pod:
- Solución con
kubectl port-forward:- Reenvía un puerto al puerto de escucha de la aplicación:
kubectl port-forward <nombre-del-pod> 8080:<puerto-de-la-app> - Intenta acceder a la aplicación localmente a través de
http://localhost:8080. Esto ayuda a determinar si el problema está en el descubrimiento de servicios de Kubernetes o en el Ingress, o si la aplicación misma no responde.
- Reenvía un puerto al puerto de escucha de la aplicación:
Si el port-forward funciona pero la URL normal del servicio falla, inspecciona el selector del Service y los endpoints:
kubectl get service <nombre-del-servicio> -n <namespace> -o yaml
kubectl get endpoints <nombre-del-servicio> -n <namespace>
kubectl get pods -n <namespace> --show-labels
Un fallo muy común es una discrepancia de etiquetas. Los pods están saludables, el servicio existe, pero el selector no coincide con las etiquetas del pod, por lo que el Service no tiene endpoints.
Escenario 2: Necesidad de depurar una base de datos que se ejecuta en un pod.
- Problema: Necesitas conectar tu cliente de base de datos local a una base de datos que se ejecuta dentro de un pod de Kubernetes para inspeccionar datos o ejecutar consultas.
- Solución con
kubectl port-forward:- Identifica el pod que ejecuta la base de datos y su puerto (por ejemplo,
mysql-pod, puerto3306). - Reenvía un puerto local al puerto de la base de datos:
kubectl port-forward mysql-pod 3306:3306 - Configura tu cliente de base de datos local para conectarse a
localhost:3306usando las credenciales de base de datos apropiadas.
- Identifica el pod que ejecuta la base de datos y su puerto (por ejemplo,
Escenario 3: Diagnosticar problemas de resolución DNS dentro de un pod.
- Problema: Una aplicación dentro de un pod no puede alcanzar otros servicios por sus nombres de servicio, lo que sugiere un problema de DNS.
- Solución con
kubectl exec:- Obtén un shell interactivo en el pod:
kubectl exec -it <nombre-del-pod> -- /bin/bash - Dentro del shell, intenta resolver un nombre de servicio conocido:
nslookup <nombre-del-servicio>.<namespace>.svc.cluster.localodig <nombre-del-servicio>.<namespace>.svc.cluster.local. - Verifica el contenido de
/etc/resolv.confpara asegurarte de que la configuración DNS del clúster sea correcta dentro del pod.
- Obtén un shell interactivo en el pod:
Si la imagen no incluye nslookup, dig o curl, usa un pod de depuración temporal en el mismo namespace:
kubectl run net-debug -n <namespace> --rm -it --image=curlimages/curl -- sh
Desde allí, prueba el mismo nombre de servicio que usa tu aplicación. Esto ayuda a separar "mi imagen de aplicación no tiene herramientas" de "el DNS del clúster está roto".
Escenario 4: Port-forward se conecta, luego se cierra inmediatamente.
- Problema:
kubectl port-forwardimprime un mensaje de reenvío, pero la conexión se cierra cuando abres el navegador o ejecutascurl. - Causas probables: El proceso de destino no está escuchando en el puerto remoto, la aplicación solo se vincula a
127.0.0.1dentro del contenedor, o el pod se reinicia mientras el túnel está abierto. - Verificaciones:
kubectl exec <nombre-del-pod> -n <namespace> -- ss -lntp kubectl get pod <nombre-del-pod> -n <namespace> -w kubectl logs <nombre-del-pod> -n <namespace> --tail=100
Si el proceso escucha en el puerto 8080 pero reenvías al 80, el túnel en sí está bien; el destino es incorrecto. Si el pod se reinicia mientras pruebas, arregla la causa del reinicio antes de perseguir problemas de red.
Escenario 5: El servicio funciona desde un pod pero no desde otro.
- Problema: Un backend puede alcanzar Redis, pero un pod worker en otro namespace no puede.
- Verificaciones con
exec:kubectl exec <pod-origen> -n <namespace-origen> -- curl -v http://<servicio>.<namespace-destino>.svc.cluster.local:<puerto> kubectl exec <pod-origen> -n <namespace-origen> -- cat /etc/resolv.conf
Si DNS resuelve pero TCP falla, verifica NetworkPolicies, endpoints del servicio y si la aplicación de destino acepta tráfico de ese namespace. Si DNS no resuelve, prueba el nombre de servicio completamente calificado antes de culpar a la aplicación.
Una escalera de conectividad simple
Cuando una solicitud falla, prueba desde lo más cercano a lo más lejano:
- Dentro del pod, prueba el proceso de la aplicación local:
kubectl exec <pod> -n <namespace> -- curl -v http://127.0.0.1:<puerto>/health - Desde un pod diferente en el mismo namespace, prueba el Service:
kubectl run curl-test -n <namespace> --rm -it --image=curlimages/curl -- curl -v http://<servicio>:<puerto>/health - Desde tu laptop, prueba a través de port-forward:
kubectl port-forward service/<servicio> -n <namespace> 8080:<puerto-del-servicio> curl -v http://localhost:8080/health - Solo después de que esos pasos funcionen, avanza hacia Ingress, balanceadores de carga, DNS y reglas de firewall.
Este orden ahorra tiempo porque cada paso prueba una capa. Si localhost dentro del pod falla, Ingress es irrelevante. Si pod-local tiene éxito pero el acceso al Service falla, la aplicación probablemente está bien y el descubrimiento de servicios de Kubernetes necesita atención.
Un hábito más ayuda: mantén el namespace explícito mientras depuras. Muchas sesiones confusas provienen de ejecutar kubectl exec en el namespace predeterminado mientras la carga de trabajo rota vive en otro lugar. Establece el namespace en tu contexto para la sesión o agrega -n <namespace> a cada comando. El tecleo extra es más barato que probar el pod equivocado.
También guarda el comando exacto que probó el fallo. La siguiente persona de guardia puede volver a ejecutarlo sin reconstruir tu contexto de memoria.
Mejores prácticas y consejos
- Mantén
port-forwarden ejecución:kubectl port-forwardse ejecuta en primer plano. Necesitarás mantener la ventana de terminal abierta. Para ejecutarlo en segundo plano, puedes usar herramientas comonohuposcreen/tmux. - Usa pods específicos al depurar: Si bien reenviar a servicios es conveniente, para identificar problemas con una instancia específica, reenviar a un pod particular usando su nombre suele ser más efectivo.
- Seguridad: Ten en cuenta qué puertos expones. Evita reenviar puertos sensibles a menos que sea absolutamente necesario y asegúrate de que tu máquina local esté segura.
- Uso de recursos:
kubectl execpuede consumir recursos. Úsalo con prudencia, especialmente en clústeres de producción. - Permisos: Asegúrate de que tu contexto de
kubectltenga los permisos necesarios para ejecutar comandos en pods o reenviar puertos.
Qué anotar después de arreglarlo
Una buena depuración deja un rastro. Captura la URL que falló, el pod de origen, el servicio de destino, el namespace, el comando exacto que reprodujo el problema y la capa donde falló. "Problema de conectividad" es demasiado vago para ayudar la próxima vez. "El selector del Service no coincidió con los pods después de un cambio de nombre de etiqueta" es un patrón solucionable.