Tarea asignada para desplegar una app sencilla en un clúster Kubernetes con Deployments y Services.
Actividad Kubernetes: Desplegando una Aplicación con Despliegues y Servicios
Paso 1: Preparar la aplicación
En este paso, crearemos una aplicación web sencilla basada en Nginx y la empaquetaremos en una imagen Docker. Usaremos un archivo index.html personalizado para mostrar un mensaje "Hola Mundo" desde Kubernetes.
1.1 Crear el archivo index.html:
Crea un archivo llamado index.html con el siguiente contenido:
<!DOCTYPE html>
<html>
<head>
<title>Hola Mundo Kubernetes</title>
</head>
<body>
<h1>¡Hola desde Kubernetes!</h1>
</body>
</html>Este archivo HTML mostrará el mensaje "Hola desde Kubernetes" cuando se acceda a la aplicación.
1.2 Crear el Dockerfile:
Crea un archivo llamado Dockerfile con el siguiente contenido:
FROM nginx:alpine # Usamos la imagen oficial de Nginx basada en Alpine Linux (más ligera)
COPY index.html /usr/share/nginx/html # Copiamos nuestro archivo index.html al directorio raíz del servidor web NginxEste Dockerfile utiliza la imagen nginx:alpine como base. Alpine Linux es una distribución de Linux muy ligera, lo que resulta en imágenes Docker más pequeñas y eficientes. El comando COPY copia el archivo index.html al directorio correcto dentro de la imagen para que Nginx lo sirva.
1.3 Construir la imagen Docker:
Abre una terminal en el directorio donde se encuentran los archivos index.html y Dockerfile. Ejecuta el siguiente comando para construir la imagen Docker:
docker build -t tu-usuario/nginx-hola-mundo:1.0 .docker build: Comando para construir una imagen.-t tu-usuario/nginx-hola-mundo:1.0: Etiqueta la imagen con un nombre y una versión. Reemplazatu-usuariocon tu nombre de usuario de Docker Hub (si lo vas a subir)..: Indica que el contexto de construcción es el directorio actual.
1.4 Subir la imagen a un registro (opcional pero recomendado):
Si estás usando un clúster Kubernetes en la nube o quieres compartir tu imagen, es recomendable subirla a un registro de contenedores como Docker Hub.
docker push tu-usuario/nginx-hola-mundo:1.0Reemplaza tu-usuario con tu nombre de usuario de Docker Hub. Asegúrate de haber iniciado sesión en Docker Hub con docker login.
1.5 Verificar la imagen (local):
Puedes verificar que la imagen se ha creado localmente con:
docker imagesDeberías ver tu imagen tu-usuario/nginx-hola-mundo:1.0 en la lista.
Crea un archivo llamado deployment.yaml con el siguiente contenido:
apiVersion: apps/v1 # Versión de la API para Deployments
kind: Deployment # Tipo de recurso (Deployment)
metadata:
name: nginx-deployment # Nombre del Deployment
labels:
app: nginx # Etiqueta para identificar el Deployment
spec:
replicas: 3 # Número de réplicas (pods) a mantener
selector:
matchLabels:
app: nginx # Selector que coincide con las etiquetas de los pods
strategy:
type: RollingUpdate # Estrategia de actualización (sin downtime)
rollingUpdate:
maxUnavailable: 1 # Máximo de pods no disponibles durante la actualización
maxSurge: 1 # Máximo de pods nuevos creados durante la actualización
template:
metadata:
labels:
app: nginx # Etiqueta aplicada a los pods creados
spec:
containers:
- name: nginx # Nombre del contenedor
image: tu-usuario/nginx-hola-mundo:1.0 # Imagen Docker a usar
ports:
- containerPort: 80 # Puerto expuesto por el contenedor| Sección | Propósito | Ejemplo |
|---|---|---|
apiVersion |
Especifica la versión de la API de Kubernetes. Para Deployments, usa apps/v1. |
apps/v1 |
kind |
Define el tipo de recurso. Aquí es un Deployment. |
Deployment |
metadata |
Proporciona metadatos como el nombre y las etiquetas del Deployment. | name: nginx-deployment |
spec.replicas |
Número de pods que el Deployment debe mantener en ejecución. | replicas: 3 |
spec.selector |
Define cómo el Deployment encuentra los pods que gestiona. Debe coincidir con las etiquetas del pod. | matchLabels: app: nginx |
spec.strategy |
Configura cómo se actualizan los pods. RollingUpdate reemplaza pods gradualmente. |
type: RollingUpdate |
spec.template |
Plantilla para crear nuevos pods. Incluye la configuración del contenedor. | containers: - name: nginx |
spec.template.spec.containers |
Define la imagen del contenedor y los puertos expuestos. | image: tu-usuario/nginx-hola-mundo:1.0 |
-
Ejecuta el comando para crear el Deployment:
kubectl apply -f deployment.yaml
Salida esperada:
deployment.apps/nginx-deployment created -
Verifica el estado del Deployment:
kubectl get deployments
Salida esperada:
NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 3/3 3 3 10s -
Verifica los pods creados:
kubectl get pods
Salida esperada (3 pods en estado
Running):NAME READY STATUS RESTARTS AGE nginx-deployment-5c689d8bb6-abcde 1/1 Running 0 15s nginx-deployment-5c689d8bb6-fghij 1/1 Running 0 15s nginx-deployment-5c689d8bb6-klmno 1/1 Running 0 15s
| Comando | Propósito |
|---|---|
kubectl describe deployment nginx-deployment |
Muestra detalles del Deployment (eventos, réplicas, etc.). |
kubectl rollout status deployment nginx-deployment |
Monitorea el progreso de una actualización. |
kubectl logs <nombre-del-pod> |
Muestra los logs de un pod específico. |
kubectl scale deployment nginx-deployment --replicas=5 |
Escala el número de pods a 5. |
| Error | Causa | Solución |
|---|---|---|
ImagePullBackOff |
Kubernetes no puede descargar la imagen Docker. | Verifica que la imagen existe y la etiqueta es correcta. |
CrashLoopBackOff |
El contenedor falla al iniciarse. | Revisa los logs del pod con kubectl logs <pod-name>. |
selector does not match template labels |
Las etiquetas del pod no coinciden con el selector del Deployment. | Asegúrate de que spec.selector.matchLabels y spec.template.metadata.labels sean idénticos. |
Usaremos un Service de tipo NodePort, que permite acceder a la aplicación desde fuera del clúster a través de un puerto específico en los nodos de Kubernetes.
Crearemos un archivo llamado service.yaml con el siguiente contenido:
apiVersion: v1
kind: Service # Tipo de recurso (Service)
metadata:
name: nginx-service # Nombre del Service
spec:
type: NodePort # Tipo de Service (NodePort expone la aplicación externamente)
selector:
app: nginx # Selector que coincide con las etiquetas de los pods del Deployment
ports:
- protocol: TCP # Protocolo de red (TCP o UDP)
port: 80 # Puerto interno del Service
targetPort: 80 # Puerto del contenedor al que se redirige el tráfico
nodePort: 30007 # Puerto del nodo (rango 30000-32767)| Campo | Propósito | Ejemplo |
|---|---|---|
apiVersion |
Versión de la API para Services. | v1 |
kind |
Tipo de recurso. Aquí es un Service. |
Service |
metadata.name |
Nombre del Service. | nginx-service |
spec.type |
Tipo de Service. NodePort expone la aplicación en un puerto del nodo. | NodePort |
spec.selector |
Etiquetas para seleccionar los pods gestionados por el Deployment. Debe coincidir con las etiquetas del Deployment. | app: nginx |
spec.ports |
Configuración de los puertos. | port: 80 (Service), targetPort: 80 (contenedor) |
nodePort |
Puerto del nodo para acceso externo. | 30007 (rango 30000-32767) |
-
Ejecuta el comando para crear el Service:
kubectl apply -f service.yaml
Salida esperada:
service/nginx-service created -
Verifica el estado del Service:
kubectl get services
Salida esperada:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service NodePort 10.96.123.123 <none> 80:30007/TCP 10s
Dependiendo de tu entorno Kubernetes:
minikube service nginx-service --urlEste comando abrirá automáticamente la aplicación en tu navegador.
Ejemplo de salida:
http://192.168.49.2:30007
-
Obtén la IP externa de un nodo del clúster:
kubectl get nodes -o wide
Ejemplo de salida:
NAME STATUS EXTERNAL-IP node-01 Ready 34.123.45.67 -
Accede a la aplicación usando la IP del nodo y el
nodePort:http://34.123.45.67:30007
| Comando | Propósito |
|---|---|
kubectl describe service nginx-service |
Muestra detalles del Service (IP, puertos, eventos). |
kubectl delete service nginx-service |
Elimina el Service. |
kubectl edit service nginx-service |
Edita el Service en tiempo real. |
| Error | Causa | Solución |
|---|---|---|
No endpoints available for service |
El selector del Service no coincide con las etiquetas de los pods. | Verifica que spec.selector en el Service coincida con las etiquetas del Deployment. |
Connection refused |
Los pods no están escuchando en el targetPort. |
Asegúrate de que el contenedor expone el puerto correcto (containerPort en el Deployment). |
nodePort fuera de rango |
El nodePort no está entre 30000-32767. |
Usa un puerto dentro del rango permitido. |
Usuario Externo
↓
[Nodo Kubernetes:30007] # Service (NodePort)
↓
[Pod 1] ←→ [Pod 2] ←→ [Pod 3] # Réplicas del Deployment
Profundicemos en las formas de acceder a la aplicación y verificar su funcionamiento.
a) Usando Minikube:
minikube service nginx-service --urlEste comando devolverá una URL como http://192.168.49.2:30007 y abrirá automáticamente la aplicación en tu navegador. Verás el mensaje "¡Hola desde Kubernetes!".
b) En un clúster en la nube:
- Obtén la IP externa del nodo y el puerto del Service:
Ejemplo de salida:
kubectl get service nginx-service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-service NodePort 10.96.123.123 34.123.45.67 80:30007/TCP 5m - Accede a la aplicación usando la IP externa y el
nodePort:http://34.123.45.67:30007
c) Verificar conectividad interna (dentro del clúster): Si quieres probar la comunicación entre pods, ejecuta:
kubectl exec <nombre-del-pod> -- curl http://nginx-serviceEsto simulará una solicitud desde un pod hacia el Service.
El Deployment permite escalar horizontalmente el número de réplicas (pods) de la aplicación.
a) Escalar manualmente:
kubectl scale deployment nginx-deployment --replicas=5Verifica el escalamiento:
kubectl get podsVerás 5 pods en ejecución:
nginx-deployment-abcde 1/1 Running 0 10s
nginx-deployment-fghij 1/1 Running 0 10s
...
b) Escalado automático (Horizontal Pod Autoscaler - HPA): Si tienes métricas configuradas, puedes usar:
kubectl autoscale deployment nginx-deployment --cpu-percent=50 --min=3 --max=10Este comando ajustará automáticamente las réplicas según el uso de CPU.
a) Ver logs de un pod específico:
kubectl logs <nombre-del-pod>b) Monitorear el tráfico en tiempo real:
kubectl get pods -w # Muestra cambios en los pods (creación/eliminación)c) Ver métricas de recursos:
kubectl top pods # Requiere instalación de Metrics ServerUsuario Externo
│
▼
[Service] (NodePort:30007)
│
▼
[Deployment]
├── Pod 1 (nginx)
├── Pod 2 (nginx)
├── Pod 3 (nginx)
├── Pod 4 (nginx) # Después del escalamiento
└── Pod 5 (nginx)
¡Perfecto! Vamos al Paso 5: Actualizar la aplicación para implementar una nueva versión sin interrumpir el servicio. Usaremos la estrategia de actualización RollingUpdate definida en el Deployment.
-
Actualiza la versión de la imagen en el
deployment.yaml:containers: - name: nginx image: tu-usuario/nginx-hola-mundo:2.0 # Cambia de 1.0 a 2.0
-
Aplica los cambios:
kubectl apply -f deployment.yaml
-
Verifica el estado de la actualización:
kubectl rollout status deployment nginx-deployment
Salida esperada:
deployment "nginx-deployment" successfully rolled out -
Observa los pods en tiempo real:
kubectl get pods --watch
Verás cómo los pods antiguos se eliminan gradualmente y se crean nuevos.
- Accede a la aplicación:
Asegúrate de que la nueva versión muestra los cambios esperados (ej: "¡Hola desde Kubernetes v2.0!").
minikube service nginx-service --url # O usa la IP del nodo en la nube
Si la nueva versión tiene errores, puedes revertir al estado anterior:
kubectl rollout undo deployment nginx-deployment