Introducción
En los laboratorios de despliegue anteriores, utilizamos imágenes que ya existían en un registro o en la caché del clúster. Los desarrolladores de aplicaciones también necesitan comprender el flujo de trabajo de las imágenes locales: compilar una imagen a partir de archivos de la aplicación, hacer que dicha imagen esté disponible para el nodo de Kubernetes e indicar a un Deployment que la utilice.
En este laboratorio, compilarás una pequeña imagen de aplicación web localmente con Minikube, la desplegarás utilizando imagePullPolicy: Never y, posteriormente, volverás a compilar la aplicación con una segunda etiqueta de imagen para realizar una actualización progresiva (rolling update). Esto refleja una tarea común al estilo CKAD: conectar el artefacto de la aplicación con la carga de trabajo de Kubernetes que lo ejecuta.
Preparar un espacio de trabajo para imágenes locales
En este paso, prepararás un espacio de nombres (namespace) limpio y confirmarás que la ruta de compilación de imágenes esté disponible.
Comienza en /home/labex/project. Crearás los archivos de la aplicación, los archivos de compilación de la imagen y los manifiestos de Kubernetes en este directorio.
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. La aplicación se probará a través de un Service, por lo que la red debe estar operativa.
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 espacio de nombres llamado ckad-prep-local-image y establécelo como el espacio de nombres actual:
kubectl create namespace ckad-prep-local-image
kubectl config set-context --current --namespace=ckad-prep-local-image
Confirma el espacio de nombres y verifica el comando de imagen de Minikube. El comando minikube image build compila una imagen directamente para el perfil de Minikube, de modo que los Pods puedan utilizarla sin necesidad de enviarla a un registro.
kubectl config view --minify --output 'jsonpath={..namespace}'; echo
minikube image build --help | sed -n '1,4p'
La salida esperada incluye:
ckad-prep-local-image
Build a container image...
Compilar la primera imagen local
En este paso, crearás una pequeña aplicación web y la compilarás como local-message-app:v1.
La imagen utilizará httpd de BusyBox para servir un archivo estático. El contenido del archivo representa la versión visible de la aplicación, por lo que más adelante podrás comprobar qué etiqueta de imagen se está ejecutando en Kubernetes.
Crea el directorio de la aplicación y la primera página web:
mkdir -p local-message-app/www
cat > local-message-app/www/index.html <<'EOF'
local-image-v1
EOF
Crea un Dockerfile. La instrucción COPY coloca tu archivo local www/index.html dentro de la imagen, y CMD inicia el servidor web de BusyBox en el puerto 8080 cuando se ejecuta un contenedor a partir de la imagen.
cat > local-message-app/Dockerfile <<'EOF'
FROM busybox:1.36
COPY www/index.html /www/index.html
EXPOSE 8080
CMD ["httpd", "-f", "-p", "8080", "-h", "/www"]
EOF
Compila la imagen para el perfil de Minikube activo. La opción -t asigna una etiqueta local a la imagen, y la ruta final es el directorio de contexto de compilación.
minikube image build --profile labex-v135 -t local-message-app:v1 ./local-message-app
La salida esperada incluye:
naming to docker.io/library/local-message-app:v1 done
Enumera las imágenes conocidas por Minikube y busca tu nueva etiqueta:
minikube image ls --profile labex-v135 | grep local-message-app
Salida esperada:
docker.io/library/local-message-app:v1
Desplegar la imagen local
En este paso, ejecutarás la imagen local en Kubernetes.
Debido a que local-message-app:v1 no se ha enviado a un registro remoto, el Deployment utiliza imagePullPolicy: Never. Esto indica al kubelet que utilice una imagen que ya existe en el nodo en lugar de intentar descargarla de la red.
Crea local-image-app.yaml:
cat > local-image-app.yaml <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: local-message-app
spec:
replicas: 2
selector:
matchLabels:
app: local-message-app
template:
metadata:
labels:
app: local-message-app
spec:
terminationGracePeriodSeconds: 0
containers:
- name: web
image: local-message-app:v1
imagePullPolicy: Never
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 1
periodSeconds: 2
---
apiVersion: v1
kind: Service
metadata:
name: local-message-app
spec:
selector:
app: local-message-app
ports:
- port: 80
targetPort: 8080
EOF
Aplica el manifiesto y espera a que el Deployment esté listo:
kubectl apply -f local-image-app.yaml
kubectl rollout status deployment/local-message-app --timeout=120s
La salida esperada incluye:
deployment.apps/local-message-app created
service/local-message-app created
deployment "local-message-app" successfully rolled out
Crea un Pod cliente y prueba el Service:
kubectl run image-client --image=busybox:1.36 --restart=Never --command -- sleep 3600
kubectl wait --for=condition=Ready pod/image-client --timeout=120s
kubectl exec image-client -- wget -qO- http://local-message-app
Salida esperada:
local-image-v1
Recompilar y desplegar una nueva imagen local
En este paso, volverás a compilar la aplicación con una segunda etiqueta de imagen y actualizarás el Deployment a esa etiqueta.
Modificar un archivo en el disco no cambia una imagen en ejecución. Debes compilar una nueva etiqueta de imagen y actualizar el Deployment para que Kubernetes inicie nuevos Pods a partir de esa etiqueta. Esto mantiene el cambio de versión visible y evita depender de contenidos de imágenes locales mutables.
Reemplaza el contenido de la página web con la versión dos:
cat > local-message-app/www/index.html <<'EOF'
local-image-v2
EOF
Compila la segunda etiqueta de imagen:
minikube image build --profile labex-v135 -t local-message-app:v2 ./local-message-app
La salida esperada incluye:
naming to docker.io/library/local-message-app:v2 done
Actualiza la imagen del Deployment y espera a que finalice la actualización:
kubectl set image deployment/local-message-app web=local-message-app:v2
kubectl rollout status deployment/local-message-app --timeout=120s
La salida esperada incluye:
deployment.apps/local-message-app image updated
deployment "local-message-app" successfully rolled out
Confirma tanto la etiqueta de la imagen como la respuesta de la aplicación:
kubectl get deployment local-message-app -o jsonpath='{.spec.template.spec.containers[0].image}'; echo
kubectl exec image-client -- wget -qO- http://local-message-app
Salida esperada:
local-message-app:v2
local-image-v2
Resumen
Has compilado una pequeña imagen de aplicación para el perfil de Minikube, la has desplegado con imagePullPolicy: Never, la has probado a través de un Service de Kubernetes, has vuelto a compilar la aplicación con una nueva etiqueta de imagen y has actualizado el Deployment. El flujo de trabajo clave consiste en hacer que la imagen esté disponible en el nodo antes de esperar que los Pods la ejecuten.



