Introducción
Los Pods son temporales. Un Deployment puede reemplazar Pods durante un despliegue, reinicio o escalado, por lo que los clientes no deben conectarse directamente a las direcciones IP individuales de los Pods. Un Service proporciona a los clientes un nombre estable y una IP virtual, utilizando etiquetas (labels) para dirigir el tráfico a los Pods que coincidan actualmente.
En este laboratorio, crearás un pequeño Deployment web, lo expondrás con un Service de tipo ClusterIP, inspeccionarás cómo el Service selecciona los Pods de backend, probarás el Service desde un Pod cliente y escalarás el Deployment para observar cómo se actualizan los endpoints del Service.
Crear un Deployment web
En este paso, prepararás un namespace y crearás un Deployment que posteriormente podrá ser expuesto mediante un Service.
Comienza en /home/labex/project:
mkdir -p /home/labex/project
cd /home/labex/project
Verifica que el servidor de la API de Kubernetes sea accesible. Si la máquina virtual acaba de iniciarse y el nodo aún no está listo, espera unos segundos y vuelve a ejecutar el comando.
kubectl get nodes --request-timeout=5s
La salida esperada incluye:
NAME STATUS ROLES AGE VERSION
labex-v135 Ready control-plane ... v1.35...
Espera hasta que el Pod de red del clúster esté en estado Ready. Este laboratorio envía tráfico entre Pods a través de un Service, por lo que la red del clúster debe estar operativa antes de probar el acceso.
kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s
Salida esperada:
pod/calico-node-... condition met
Crea un namespace llamado ckad-prep-service y establécelo como el namespace actual:
kubectl create namespace ckad-prep-service
kubectl config set-context --current --namespace=ckad-prep-service
Crea un Deployment llamado web-front con un Pod de NGINX. El flag --port=80 registra el puerto del contenedor en la plantilla del Pod. Por sí solo, no crea un Service.
kubectl create deployment web-front --image=nginx:1.25 --port=80
Espera a que el Deployment esté disponible y luego inspecciona la etiqueta del Pod. La etiqueta app=web-front es importante porque el Service la utilizará para encontrar los Pods de backend.
kubectl rollout status deployment/web-front --timeout=120s
kubectl get pods -l app=web-front --show-labels
La salida esperada incluye:
deployment "web-front" successfully rolled out
NAME READY STATUS RESTARTS AGE LABELS
web-front-... 1/1 Running 0 ... app=web-front,...
Exponer el Deployment con un Service de tipo ClusterIP
En este paso, crearás un Service para el Deployment e inspeccionarás los campos que conectan el Service con los Pods.
Usa kubectl expose deployment para crear un Service de tipo ClusterIP. El puerto del Service es 80, y --target-port=80 le indica al Service que redirija el tráfico al puerto 80 de los Pods coincidentes.
kubectl expose deployment web-front --name=web-front --port=80 --target-port=80
Salida esperada:
service/web-front exposed
Inspecciona el Service:
kubectl get service web-front
La salida esperada incluye:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-front ClusterIP ... <none> 80/TCP ...
Ahora inspecciona el selector del Service y el mapeo de puertos. El selector es la forma en que el Service encuentra los Pods; el mapeo de puertos es la forma en que el tráfico del cliente llega al contenedor.
kubectl get service web-front -o jsonpath='{.spec.selector.app}{" "}{.spec.ports[0].port}{":"}{.spec.ports[0].targetPort}{"\n"}'
Salida esperada:
web-front 80:80
Kubernetes almacena las direcciones de backend seleccionadas en objetos llamados EndpointSlices. Lista el EndpointSlice creado para este Service:
kubectl get endpointslice -l kubernetes.io/service-name=web-front
La salida esperada incluye:
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
web-front-... IPv4 80 ... ...
Probar el Service desde dentro del clúster
En este paso, crearás un Pod cliente temporal y enviarás una solicitud HTTP al Service. Un Service de tipo ClusterIP está diseñado para el acceso interno al clúster, por lo que probarlo desde otro Pod es la forma más directa de verificarlo.
Crea un Pod cliente que se mantenga en ejecución:
kubectl run service-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
Espera a que el Pod cliente esté en estado Ready:
kubectl wait --for=condition=Ready pod/service-client --timeout=120s
Salida esperada:
pod/service-client condition met
Usa wget dentro del Pod cliente para solicitar http://web-front. El nombre web-front se resuelve como el Service dentro del namespace.
kubectl exec service-client -- wget -qO- http://web-front | head -n 5
La salida esperada incluye el inicio de la página predeterminada de NGINX:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
Esto demuestra que el cliente alcanzó el nombre estable del Service y que el Service redirigió el tráfico al Pod de backend actual.
Escalar el backend y verificar los endpoints
En este paso, escalarás el Deployment y confirmarás que el Service mantiene el mismo punto de acceso estable mientras sus endpoints de backend cambian.
Escala el Deployment a dos réplicas:
kubectl scale deployment web-front --replicas=2
kubectl rollout status deployment/web-front --timeout=120s
La salida esperada incluye:
deployment.apps/web-front scaled
deployment "web-front" successfully rolled out
Lista los Pods. Ahora debería haber dos Pods de backend en ejecución con la misma etiqueta app=web-front.
kubectl get pods -l app=web-front
La salida esperada incluye dos Pods:
NAME READY STATUS RESTARTS AGE
web-front-... 1/1 Running 0 ...
web-front-... 1/1 Running 0 ...
Cuenta los endpoints detrás del Service. El comando imprime una línea por cada dirección de endpoint y luego cuenta las líneas.
kubectl get endpointslice -l kubernetes.io/service-name=web-front -o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]}{"\n"}{end}' | wc -l
Salida esperada:
2
Solicita el Service nuevamente desde el mismo Pod cliente:
kubectl exec service-client -- wget -qO- http://web-front | grep '<title>Welcome to nginx'
Salida esperada:
<title>Welcome to nginx!</title>
Resumen
Has expuesto un Deployment con un Service de tipo ClusterIP y has verificado la ruta completa de acceso dentro del clúster. Creaste un Deployment de backend, configuraste un Service con un selector y un mapeo de puertos, inspeccionaste el EndpointSlice generado para el Service, probaste el acceso desde un Pod cliente, y finalmente escalaste el Deployment, confirmando que el Service continuó dirigiendo el tráfico al conjunto actualizado de backends.


