Services: networking estable para Pods efímeros
Dale a los Pods una dirección estable, exponlos dentro y fuera del clúster y restringe quién puede hablar con quién.
Cada Pod recibe su propia dirección IP, pero los Pods van y vienen, y sus direcciones con ellos. Un Service proporciona una dirección estable delante de un conjunto cambiante de Pods. Esta guía se apoya en el Deployment web de la guía anterior y cubre los Services, cómo exponerlos fuera del clúster, Ingress y las network policies.
El problema: las IP de los Pods cambian
kubectl get pods -l app=web -o wide
kubectl delete pod POD_NAME
kubectl get pods -l app=web -o wide
El Pod de reemplazo tiene una IP distinta y puede estar en otro nodo. Todo lo que tuviera la dirección antigua escrita a mano ahora está roto, y con réplicas que van y vienen, no es posible seguir las direcciones a mano.
Crea un Service ClusterIP
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
El selector elige los Pods que respaldan el Service, usando las mismas etiquetas que viste con los Deployments. port es el puerto en el que escucha el Service y targetPort es el puerto de los Pods al que reenvía, que debe coincidir con el puerto del contenedor. Como no se define type, este es un Service ClusterIP: accesible solo desde dentro del clúster, en una IP virtual estable.
kubectl apply -f service.yaml
kubectl get service web
kubectl get endpointslices -l kubernetes.io/service-name=web
El EndpointSlice lista las IP de los Pods que hay actualmente detrás del Service. Escala el Deployment hacia arriba o hacia abajo y se actualiza automáticamente, mientras que la dirección del propio Service nunca cambia. (Los clústeres y tutoriales más antiguos usan kubectl get endpoints web para la misma información. Las versiones recientes deprecan esa API en favor de EndpointSlices.)
Dentro del clúster, el Service también recibe un nombre DNS: web desde el mismo namespace, o web.NAMESPACE.svc.cluster.local desde cualquier lugar. Pruébalo desde un Pod desechable:
kubectl run tmp --rm -it --image=busybox:1.36 --restart=Never -- wget -qO- http://web
Deberías ver la página de bienvenida de nginx. En cada nodo, kube-proxy mantiene las reglas que reparten las conexiones entre los Pods listos del Service. En el modo iptables habitual esto es efectivamente aleatorio en lugar de un round-robin estricto, y los Pods que fallan su comprobación de readiness se sacan de la rotación.
Expón un Service fuera del clúster
Hay dos tipos de Service más, y cada uno se construye sobre el anterior:
- NodePort además abre un puerto (30000–32767) en cada nodo. Todo lo que pueda llegar a la IP de un nodo puede llegar al Service en ese puerto.
- LoadBalancer además pide al entorno un balanceador de carga externo que apunte a esos node ports. En un proveedor de nube ocurre automáticamente. En bare metal necesitas algo como MetalLB.
apiVersion: v1
kind: Service
metadata:
name: web-public
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080
Si omites nodePort, Kubernetes elige uno libre. En minikube con el driver de Docker, la IP del nodo a menudo no es accesible directamente desde tu portátil, así que deja que minikube lo abra por ti:
minikube service web-public --url
Para un Service LoadBalancer en minikube, ejecuta minikube tunnel en otra terminal.
Enruta HTTP con Ingress
Un LoadBalancer por Service resulta caro y solo maneja tráfico en bruto. Un Ingress te permite enrutar tráfico HTTP(S) a muchos Services por host y ruta, a través de un único punto de entrada, y terminar TLS allí. Un Ingress solo describe las reglas. Necesita un ingress controller ejecutándose en el clúster para actuar sobre ellas (en minikube, minikube addons enable ingress).
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web
spec:
ingressClassName: nginx
rules:
- host: web.example.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
Las peticiones para web.example.local ahora van al Service web. Los certificados del host pueden automatizarse con una herramienta como cert-manager.
Restringe el tráfico con NetworkPolicy
Por defecto, cada Pod puede hablar con cualquier otro Pod. Una NetworkPolicy selecciona Pods y lista qué tráfico se permite. Una vez que cualquier política selecciona un Pod para ingress, todo lo que no esté permitido explícitamente se deniega. Empieza denegando todo el tráfico entrante en un namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
El podSelector vacío selecciona todos los Pods del namespace. Luego permite solo lo que necesites, por ejemplo tráfico hacia los Pods web desde Pods con la etiqueta role: client:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-client-to-web
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: client
ports:
- protocol: TCP
port: 80
Las network policies tienen ámbito de namespace y solo se aplican si el plugin de red del clúster las soporta, por ejemplo Calico o Cilium. Algunas configuraciones locales mínimas aceptan los objetos pero los ignoran en silencio, así que comprueba que una conexión denegada realmente esté bloqueada.
Guías populares
-
Qué es Kubernetes y los problemas que resuelve Por qué los contenedores por sí solos dejan de escalar y cómo Kubernetes convierte un grupo de máquinas en una sola plataforma. -
Cómo funciona un clúster de Kubernetes: plano de control y nodos Los componentes que hacen funcionar un clúster y qué ocurre entre kubectl apply y un contenedor en ejecución. -
Deployments: escalado, autorreparación y rolling updates Ejecuta réplicas de un Pod, actualízalas sin tiempo de inactividad y revierte cuando un despliegue sale mal. -
Depura un Pod que falla: describe, logs, exec y port-forward Una lista de comprobación repetible para averiguar por qué un Pod está Pending, se cae o no responde.