Una referencia escaneable de patrones arquitectónicos que evalúa el examen CKAD. Lee de arriba a abajo o salta a una sección.
Entorno, Configuración y Seguridad de la Aplicación
Crear un ConfigMap o Secret genérico a partir de pares clave-valor de línea de comandos.
Usa `kubectl create configmap <name> --from-literal=<key>=<value>` o `kubectl create secret generic <name> --from-literal=<key>=<value>`.
Por qué: `--from-literal` es para entrada directa de clave-valor. Usa el flag múltiples veces para múltiples claves. Esto es más rápido que crear un archivo YAML para casos simples.
Por qué: `valueFrom` proporciona inyección selectiva y permite mapear la clave de origen a un nombre de variable de entorno diferente.
Montar un ConfigMap o Secret como archivos en un Pod, permitiendo actualizaciones en vivo.
Define un `volume` de tipo `configMap` o `secret`. Móntalo en el contenedor usando `volumeMounts`. Los archivos se nombrarán según las claves.
Por qué: Los archivos montados de ConfigMaps/Secrets se actualizan automáticamente cuando la fuente cambia. Las variables de entorno no lo hacen, requiriendo un reinicio del Pod.
Aplicar las mejores prácticas de seguridad: evitar la ejecución como root, hacer el sistema de archivos raíz de solo lectura o especificar un ID de usuario.
Usa `securityContext` a nivel de Pod o contenedor. Establece `runAsNonRoot: true`, `readOnlyRootFilesystem: true`, y/o `runAsUser: <UID>`.
Por qué: SecurityContext proporciona un control declarativo y granular sobre los privilegios del contenedor, esencial para fortalecer las aplicaciones y cumplir con las políticas de seguridad.
Conceder a un Pod permisos mínimos para acceder a la API de Kubernetes.
1. Crea un `ServiceAccount` personalizado. 2. Crea un `Role` con solo los permisos de API necesarios (por ejemplo, listar pods). 3. Crea un `RoleBinding` para vincular el ServiceAccount y el Role. 4. Asigna el ServiceAccount al Pod a través de `spec.serviceAccountName`.
Por qué: Sigue el principio de mínimo privilegio, minimizando la superficie de ataque si un Pod es comprometido.
Evitar el montaje automático de un token de ServiceAccount en un Pod que no necesita acceso a la API.
Establece `automountServiceAccountToken: false` en la especificación del Pod o en el propio ServiceAccount.
Por qué: Reduce la superficie de ataque al no proporcionar credenciales de API a los contenedores que no las requieren.
Crear un Secret para su uso en la terminación TLS para un Ingress u otro servicio seguro.
Usa `kubectl create secret tls <secret-name> --cert=<path/to/cert.pem> --key=<path/to/key.pem>`.
Por qué: Esto crea un Secret del tipo correcto `kubernetes.io/tls` con las claves de datos estándar `tls.crt` y `tls.key` esperadas por los controladores de Ingress.
Exponer metadatos del Pod (como nombre, namespace, etiquetas o IP del nodo) a un contenedor.
Usa la Downward API para proyectar metadatos como variables de entorno o archivos en un volumen `downwardAPI`. Ejemplo: `valueFrom: {fieldRef: {fieldPath: metadata.name}}`.
Por qué: Permite que los contenedores sean conscientes de sí mismos sin necesidad de consultar la API de Kubernetes, simplificando la configuración y reduciendo los requisitos de RBAC.
Establecer solicitudes y límites predeterminados de CPU/memoria para todos los Pods en un namespace.
Crea un objeto `LimitRange` en el namespace. Define valores `default` y `defaultRequest` para los recursos.
Por qué: Asegura que todos los Pods tengan restricciones de recursos, mejorando la programación y la estabilidad, incluso si los desarrolladores olvidan especificarlas. Funciona en conjunto con ResourceQuota.
Limitar la cantidad total de recursos (CPU, memoria, recuento de objetos) que se pueden consumir en un namespace.
Crea un objeto `ResourceQuota`. Define límites estrictos en `spec.hard`, por ejemplo, `requests.cpu: "4"`, `pods: "10"`.
Por qué: Evita que un namespace o equipo consuma todos los recursos del clúster, asegurando una asignación justa de recursos.
Diseño y Construcción de la Aplicación
Ejecutar tareas prerrequisito (por ejemplo, esperar una base de datos, ejecutar migraciones, extraer datos) antes de que se inicie la aplicación principal.
Define uno o más `initContainers` en la especificación del Pod. Se ejecutan secuencialmente hasta su finalización antes de que se inicien los contenedores de la aplicación principal.
Por qué: Desacopla la lógica de configuración del contenedor de la aplicación y garantiza que las dependencias se cumplan antes del lanzamiento de la aplicación.
Extender un contenedor de aplicación principal con funcionalidades de ayuda como registro, monitoreo o proxying.
Agrega un segundo contenedor (el sidecar) a la especificación del Pod. Ambos contenedores comparten recursos como la red y los volúmenes.
Por qué: Mejora la funcionalidad sin modificar el código de la aplicación principal, promoviendo la separación de responsabilidades.
Compartir un directorio para leer/escribir entre contenedores en el mismo Pod.
Define un volumen `emptyDir` en la especificación del Pod y móntalo en todos los contenedores requeridos.
Por qué: `emptyDir` proporciona un volumen de almacenamiento simple y efímero que existe durante la vida útil del Pod, perfecto para compartir datos dentro del Pod.
Anular el ENTRYPOINT y/o CMD predeterminados de una imagen de contenedor.
En la especificación del contenedor, usa `command` para anular ENTRYPOINT y `args` para anular CMD. `command: ["/bin/sh"], args: ["-c", "echo hello"]`.
Por qué: Proporciona control total sobre el comando de inicio del contenedor desde la definición del Pod, útil para adaptar imágenes genéricas.
Ejecutar una tarea finita hasta su finalización, controlando el paralelismo y el número de finalizaciones exitosas.
Usa un recurso `Job`. Establece `spec.completions` para el recuento de éxitos deseado y `spec.parallelism` para el número de Pods concurrentes. Usa `spec.backoffLimit` para controlar los reintentos.
Por qué: Los Jobs están diseñados para tareas que se ejecutan hasta su finalización, a diferencia de los Deployments de larga duración. Estas configuraciones son clave para gestionar las cargas de trabajo por lotes.
Programar una tarea recurrente usando la sintaxis cron y controlar cómo se manejan los trabajos superpuestos.
Usa un recurso `CronJob`. Define `spec.schedule` en formato cron (por ejemplo, `*/5 * * * *`). Establece `spec.concurrencyPolicy` en `Allow`, `Forbid` o `Replace`.
Por qué: Automatiza tareas programadas. `concurrencyPolicy` es crítico para prevenir ejecuciones superpuestas (`Forbid`) o reemplazar las obsoletas (`Replace`).
Generar rápidamente un manifiesto YAML para un recurso sin crearlo en el clúster.
Usa los flags `--dry-run=client -o yaml` con comandos imperativos. Ejemplo: `kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml`.
Por qué: Ahorra tiempo al generar un manifiesto válido que se puede personalizar y luego aplicar de forma declarativa.
Despliegue de la Aplicación
Actualizar, escalar, verificar el estado, ver el historial y revertir un Deployment de forma imperativa.
Usa `kubectl set image`, `kubectl scale`, `kubectl rollout status`, `kubectl rollout history` y `kubectl rollout undo`.
Por qué: Estos son los comandos imperativos centrales para gestionar el ciclo de vida de una aplicación desplegada durante el desarrollo y la resolución de problemas.
Controlar la velocidad y seguridad de una actualización de Deployment para asegurar la disponibilidad.
En `spec.strategy.rollingUpdate`, configura `maxSurge` (cuántos Pods adicionales se pueden crear) y `maxUnavailable` (cuántos pueden estar inactivos).
Por qué: Equilibrar `maxSurge` y `maxUnavailable` es clave para gestionar la capacidad frente al uso de recursos durante las actualizaciones. Para un tiempo de inactividad cero, `maxUnavailable` debe ser menor que `replicas`.
Asegurar que no haya dos versiones de una aplicación ejecutándose simultáneamente al terminar todos los Pods antiguos antes de crear los nuevos.
Establece `spec.strategy.type: Recreate` en el Deployment.
Por qué: Garantiza que las versiones antiguas y nuevas no coexistan, lo cual es necesario para aplicaciones que no pueden manejar dos versiones diferentes accediendo a los mismos datos. Esta estrategia implica tiempo de inactividad.
Realizar múltiples cambios en un Deployment activo sin activar un despliegue intermedio para cada cambio.
Usa `kubectl rollout pause deployment/<name>`, aplica los cambios, y luego `kubectl rollout resume deployment/<name>`.
Por qué: Consolida múltiples actualizaciones en un solo evento de despliegue, evitando la inestabilidad y las condiciones de carrera.
Limitar el número de ReplicaSets antiguos que se conservan para un Deployment para ahorrar almacenamiento en etcd.
Establece `spec.revisionHistoryLimit` al número deseado de revisiones a mantener (por ejemplo, 3). El valor predeterminado es 10.
Por qué: Establecer un límite inferior reduce el desorden en etcd. Establecerlo en `0` deshabilita completamente la capacidad de reversión.
Documentar la razón de una actualización de Deployment para que aparezca en el historial de revisiones.
Agrega una anotación `kubernetes.io/change-cause` al manifiesto del Deployment. Ejemplo: `kubectl annotate deployment/nginx kubernetes.io/change-cause="update to 1.20"`.
Por qué: Proporciona un contexto valioso al ver el historial de despliegues (`kubectl rollout history`), facilitando la identificación de la revisión a la que se debe revertir.
Desplegar una nueva versión de la aplicación junto con la antigua y cambiar el tráfico instantáneamente con cero tiempo de inactividad.
Usa dos Deployments (por ejemplo, `app-blue`, `app-green`) con diferentes etiquetas de versión. Un único Service selecciona la versión activa a través de su `selector`. Para cambiar, `kubectl patch service` para actualizar el selector a la nueva etiqueta de versión.
Por qué: Proporciona lanzamientos instantáneos y de bajo riesgo y capacidad de reversión inmediata simplemente parchando el selector del Service de vuelta.
Dirigir un pequeño porcentaje del tráfico a una nueva versión de la aplicación para pruebas en producción.
Usa dos Deployments (estable, canary) que compartan la misma etiqueta de selector. Un Service apunta a ambos. Controla el porcentaje de tráfico mediante la proporción de réplicas (por ejemplo, 9 réplicas estables, 1 canary para el 10% del tráfico).
Por qué: Una forma sencilla de realizar lanzamientos canary sin una malla de servicios, permitiendo pruebas controladas y de bajo riesgo de nuevas características. La distribución del tráfico es aproximada.
Servicios y Redes
Exponer un conjunto de Pods para comunicación solo desde dentro del clúster.
Usa un Service con `type: ClusterIP`. Este es el tipo predeterminado.
Por qué: `ClusterIP` proporciona una dirección IP interna y un nombre DNS estables para un servicio, abstraer las IPs individuales de los Pods.
Exponer un servicio en un puerto estático en la dirección IP de cada nodo.
Usa un Service con `type: NodePort`. K8s asigna un puerto de un rango (predeterminado: 30000-32767).
Por qué: Útil para el desarrollo o cuando un balanceador de carga externo no está disponible. El tráfico a `<NodeIP>:<NodePort>` se reenvía al Service.
Enrutar el tráfico HTTP/S externo a servicios internos basado en el nombre de host o la ruta URL.
Crea un recurso `Ingress`. Define `rules` para hosts y `http.paths` para mapear a servicios de backend. Configura TLS con `spec.tls` apuntando a un Secret TLS.
Por qué: Ingress proporciona enrutamiento L7, consolidando múltiples servicios bajo una única IP externa y descargando la terminación TLS.
Restringir el tráfico de red hacia y desde Pods basado en etiquetas, namespaces o bloques IP.
Crea un `NetworkPolicy` dirigido a Pods con `podSelector`. Define reglas `ingress` y/o `egress` para permitir tráfico específico. Por defecto, aplicar una política a un pod deniega todo el tráfico no permitido explícitamente.
Por qué: Las NetworkPolicies son fundamentales para la segmentación de red y la implementación de un modelo de seguridad de confianza cero en Kubernetes.
Bloquear todo el tráfico de entrada y salida para todos los pods en un namespace por defecto.
Crea un NetworkPolicy con un `podSelector: {}` vacío y reglas `ingress`/`egress` vacías. Ejemplo: `podSelector: {}, policyTypes: [Ingress, Egress]`.
Por qué: Establece una línea de base segura donde todo el tráfico es denegado a menos que sea permitido explícitamente por otras NetworkPolicies más específicas.
Proporcionar una entrada DNS estable que resuelva directamente a todas las IPs de Pods, sin una IP virtual para balanceo de carga.
Crea un Service con `spec.clusterIP: None`.
Por qué: Esencial para aplicaciones con estado (como StatefulSets) o sistemas peer-to-peer que necesitan descubrir y comunicarse directamente con Pods específicos.
Asegurar que los Pods de backend vean la IP original del cliente para el tráfico de un Service NodePort o LoadBalancer.
Establece `spec.externalTrafficPolicy: Local` en el Service.
Por qué: La política predeterminada (`Cluster`) ofusca la IP de origen mediante la traducción de direcciones de red. `Local` la preserva, pero puede llevar a una distribución de tráfico desigual si los Pods no están en todos los nodos.
Asegurar que todas las solicitudes de un cliente específico se envíen al mismo Pod.
En el Service, establece `spec.sessionAffinity: ClientIP`.
Por qué: Proporciona 'sesiones pegajosas', lo cual es necesario para aplicaciones legadas que almacenan el estado de la sesión en memoria en un Pod específico.
Un Pod en un namespace necesita comunicarse con un Service en otro namespace.
Usa el nombre DNS expandido: `<service-name>.<namespace-name>.svc.cluster.local` o la forma corta `<service-name>.<namespace-name>`.
Por qué: Los nombres de servicio simples solo se resuelven dentro del mismo namespace. La comunicación entre namespaces requiere especificar el namespace de destino en la consulta DNS.
Observabilidad y Mantenimiento de la Aplicación
Definir comprobaciones de salud para gestionar el ciclo de vida del Pod: reiniciar en caso de fallo vs. eliminar del servicio.
`livenessProbe`: Reinicia el contenedor si la sonda falla. `readinessProbe`: Elimina el Pod de los endpoints del Service si la sonda falla. `startupProbe`: Deshabilita otras sondas hasta que el contenedor termine su inicio.
Por qué: Las sondas correctamente configuradas son esenciales para la auto-curación de aplicaciones y para lograr despliegues sin tiempo de inactividad.
Diagnosticar por qué un Pod está atascado en un estado que no es Running (por ejemplo, Pending, ContainerCreating, CrashLoopBackOff).
Usa `kubectl describe pod <pod-name>`. La sección `Events` proporciona pistas críticas del scheduler (problemas de recursos), kubelet (errores de extracción de imagen) o el runtime del contenedor.
Por qué: `describe` es el comando más importante para entender los problemas del ciclo de vida del Pod que ocurren antes de que la aplicación se inicie o registre algo.
Inspeccionar los logs de un contenedor que ha fallado y ahora está en un bucle de reinicio (CrashLoopBackOff).
Usa `kubectl logs <pod-name> --previous`.
Por qué: El flag `--previous` muestra los logs de la última instancia terminada del contenedor, que contiene el error que causó el fallo.
Ver y seguir logs de todos los Pods que coinciden con un selector de etiquetas en tiempo real.
Usa `kubectl logs -l <label-selector> -f`. Agrega `--prefix` para ver de qué pod proviene cada línea.
Por qué: Agrega logs de una aplicación distribuida, proporcionando una vista unificada de su comportamiento.
Ejecutar un comando u obtener un shell interactivo dentro de un contenedor en ejecución para depuración.
Usa `kubectl exec -it <pod-name> -- /bin/sh` (o `/bin/bash`). El `--` separa los flags de kubectl del comando.
Por qué: Proporciona acceso directo al entorno del contenedor para depuración en vivo, inspección de archivos o verificación de conectividad de red.
Ver el consumo actual de CPU y memoria de un Pod en ejecución.
Usa `kubectl top pod <pod-name>`. Usa `--containers` para ver el uso de cada contenedor en el Pod.
Por qué: Requiere que el Metrics Server esté instalado. Es esencial para identificar aplicaciones que consumen muchos recursos, fugas de memoria o cuellos de botella de CPU.
Solucionar problemas de un contenedor en ejecución que carece de un shell o herramientas de depuración.
Usa `kubectl debug <pod-name> -it --image=busybox --share-processes --copy-to=debug-pod`. Esto crea un nuevo Pod con un contenedor de depuración que comparte el mismo namespace de procesos.
Por qué: `kubectl debug` es la forma moderna de adjuntar un "contenedor efímero" temporal con herramientas de depuración a un Pod en ejecución sin modificar la especificación original del Pod.