Asegurar que el estado del clúster coincida continuamente con un estado deseado.
Confiar en el `kube-controller-manager`. Ejecuta bucles de control que observan recursos (por ejemplo, ReplicaSets, Deployments) y concilian diferencias.
Por qué: Este es el mecanismo declarativo y de auto-recuperación central. Si un Pod gestionado por un ReplicaSet falla, el controlador lo reemplaza automáticamente.
Asignar automáticamente los Pods recién creados al nodo trabajador más adecuado.
Confiar en el `kube-scheduler`. Filtra nodos basándose en los requisitos del Pod (por ejemplo, solicitudes de recursos) y los puntúa para elegir el más adecuado.
Por qué: El scheduler toma decisiones de ubicación basadas en políticas, afinidad y disponibilidad, abstrayendo la selección de nodos del usuario.
Asegurar que los contenedores especificados en los Pods estén funcionando y saludables en un nodo trabajador dado.
El agente `kubelet` se ejecuta en cada nodo, se comunica con el API server y gestiona el ciclo de vida del contenedor (inicio, detención, comprobaciones de salud) a través de un tiempo de ejecución de contenedor.
Por qué: Kubelet es el enlace entre el plano de control y el nodo trabajador; ejecuta las especificaciones de los Pods.
Persistir de forma fiable todo el estado y la configuración del clúster de Kubernetes.
Usar `etcd`, un almacén de clave-valor consistente y de alta disponibilidad. Sirve como la única fuente de verdad para el clúster.
Por qué: Todos los objetos del clúster (Pods, Services, etc.) se almacenan en etcd. Solo el API server se comunica directamente con él.
Implementar reglas de red en cada nodo para habilitar la comunicación a través de Kubernetes Services.
El componente `kube-proxy` en cada nodo mantiene reglas de red (por ejemplo, iptables, IPVS) que reenvían el tráfico de una IP de Service a los Pods de backend correctos.
Por qué: Kube-proxy es el detalle de implementación detrás de la abstracción de Service, manejando el balanceo de carga y el enrutamiento.
Particionar lógicamente un único clúster de Kubernetes para múltiples equipos, proyectos o entornos.
Crear recursos `Namespace`. Los Namespaces proporcionan un alcance para los nombres y una forma de adjuntar autorización y políticas (por ejemplo, ResourceQuotas).
Por qué: Los Namespaces permiten la multi-inquilinato y la organización de recursos sin la sobrecarga de múltiples clústeres.
Proporcionar un punto final de red estable (IP y DNS) para un conjunto de Pods efímeros.
Definir un recurso `Service` que apunta a un conjunto de Pods utilizando un selector de etiquetas.
Por qué: Los Pods son efímeros y sus IPs cambian. Un Service proporciona una abstracción duradera que balancea la carga del tráfico a los Pods correctos.
Exponer una aplicación que se ejecuta en Pods a diferentes alcances de red.
Elegir un `type` de Service: `ClusterIP` (solo interno, por defecto), `NodePort` (expone en cada nodo IP:puerto), o `LoadBalancer` (aprovisiona un balanceador de carga en la nube).
Por qué: El tipo de Service determina la accesibilidad de la aplicación, desde puramente interna hasta completamente externa.
Habilitar el descubrimiento de red directo de Pods individuales, omitiendo el proxy de Service.
Crear un `Service` con `clusterIP: None`. Esto crea registros DNS A para cada Pod, permitiendo a los clientes conectarse a los Pods directamente.
Por qué: Esencial para aplicaciones con estado como bases de datos (a menudo con StatefulSets) donde se requiere comunicación peer-to-peer o identidad de Pod estable.
Organizar y seleccionar un subconjunto de objetos de Kubernetes.
Adjuntar `labels` de clave-valor a objetos (por ejemplo, `app: my-api`). Usar `label selectors` en otros objetos (por ejemplo, Services, Deployments) para apuntar a ellos.
Por qué: Las Labels son el mecanismo de agrupación central en Kubernetes, permitiendo un acoplamiento laxo entre recursos.
Desacoplar la configuración de la aplicación de la imagen del contenedor.
Almacenar datos de configuración no sensibles en un `ConfigMap`. Montarlo como un volumen o inyectar claves como variables de entorno en los Pods.
Por qué: Esto permite que la configuración se gestione independientemente del código de la aplicación, siguiendo los principios de la aplicación de 12 factores (12-Factor App).
Almacenar datos sensibles como contraseñas, tokens o claves API para el uso de la aplicación.
Usar un objeto `Secret`. Montarlo como un volumen o inyectarlo como una variable de entorno.
Por qué: Los Secrets son específicamente para datos sensibles y se manejan de forma más segura que los ConfigMaps (por ejemplo, no se muestran en `kubectl describe` por defecto, pueden cifrarse en reposo).
Proporcionar a las aplicaciones con estado almacenamiento que sobrevive a los reinicios de los Pods.
Un Pod crea un `PersistentVolumeClaim` (PVC) para solicitar almacenamiento. Un administrador aprovisiona un `PersistentVolume` (PV) que satisface la solicitud.
Por qué: Esto desacopla el consumo de almacenamiento (PVC) del aprovisionamiento de almacenamiento (PV), permitiendo definiciones de carga de trabajo portátiles.
Gestionar la asignación de CPU y memoria para los contenedores.
Establecer `resources.requests` para recursos garantizados (utilizados para la programación) y `resources.limits` para el uso máximo permitido (aplicado en tiempo de ejecución).
Por qué: Los Requests aseguran que los Pods tengan suficientes recursos para ejecutarse; los Limits evitan que los Pods consuman demasiados recursos e impacten otras cargas de trabajo.
Establecer restricciones de recursos agregadas en un Namespace.
Crear un objeto `ResourceQuota` para limitar la cantidad total de CPU, memoria o número de objetos (Pods, Services) que pueden crearse en un Namespace.
Por qué: Los ResourceQuotas son esenciales para entornos multi-inquilino para asegurar un reparto justo de recursos y prevenir el consumo excesivo.
Gestionar recursos de Kubernetes utilizando archivos de configuración versionados.
Usar `kubectl apply -f <filename.yaml>`. Este comando crea o actualiza recursos basándose en el contenido del archivo.
Por qué: `apply` es declarativo, lo que lo hace ideal para GitOps y CI/CD. Rastrea los cambios y realiza una fusión a tres bandas, lo que es más seguro que los comandos imperativos `create` o `replace`.
Diagnosticar por qué un Pod no se está ejecutando correctamente (por ejemplo, atascado en Pending, ContainerCreating o CrashLoopBackOff).
Usar `kubectl describe pod <pod-name>`. Verificar la sección `Events` en la parte inferior para mensajes detallados del scheduler, kubelet o controladores.
Por qué: `describe` proporciona un registro cronológico de eventos que es la herramienta principal para depurar problemas del ciclo de vida de los recursos.
Proporcionar funcionalidad de red para contenedores, habilitando la comunicación Pod-a-Pod en todo el clúster.
Usar un plugin de Container Network Interface (CNI) (por ejemplo, Calico, Flannel, Cilium). El kubelet en cada nodo usa el plugin CNI para configurar la red para cada Pod.
Por qué: CNI proporciona una interfaz estándar, permitiendo que Kubernetes se integre con diversas soluciones de red sin modificar los componentes principales.
Controlar el acceso a los recursos de la API de Kubernetes para usuarios y aplicaciones.
Usar Role-Based Access Control (RBAC). Definir un `Role` (con ámbito de Namespace) o `ClusterRole` (con ámbito de clúster) con permisos, y vincularlo a un sujeto (User, Group, ServiceAccount) usando un `RoleBinding` o `ClusterRoleBinding`.
Por qué: RBAC es el estándar para asegurar Kubernetes, habilitando el principio de menor privilegio para todas las interacciones de la API.
Gestionar una aplicación sin estado, permitiendo actualizaciones y reversiones fáciles.
Usar una carga de trabajo `Deployment`. Gestiona ReplicaSets para asegurar que un número deseado de réplicas de Pod estén funcionando y proporciona estrategias de actualización declarativas.
Por qué: Los Deployments son el estándar para aplicaciones sin estado, abstrayendo los detalles de escalado y actualizaciones continuas (rolling updates).
Desplegar una aplicación con estado (por ejemplo, base de datos) que requiere identidad de red y almacenamiento estables.
Usar una carga de trabajo `StatefulSet`. Proporciona a cada Pod un nombre de host único y estable y almacenamiento persistente que lo sigue a través de los reinicios.
Por qué: A diferencia de los Deployments, los StatefulSets gestionan Pods con identidad, asegurando un despliegue y escalado ordenados, lo cual es crítico para sistemas con estado.
Desplegar un agente (por ejemplo, colector de logs, agente de monitoreo) en cada nodo del clúster.
Usar una carga de trabajo `DaemonSet`. Asegura que una copia de un Pod se ejecute en cada nodo (o en un subconjunto de nodos).
Por qué: Los DaemonSets automatizan la distribución de servicios a nivel de nodo, escalando automáticamente a nuevos nodos a medida que se unen al clúster.
Ejecutar una tarea finita y única que necesita ejecutarse hasta su finalización.
Usar un recurso `Job`. Crea uno o más Pods y asegura que terminen con éxito.
Por qué: Los Jobs son para procesamiento por lotes, a diferencia de los Deployments que son para servicios continuos. Los Pods no se reemplazan después de una finalización exitosa.
Ejecutar una tarea en un horario recurrente (por ejemplo, copias de seguridad nocturnas, informes).
Usar un recurso `CronJob`. Crea Jobs basándose en una cadena de programación cron.
Por qué: Los CronJobs proporcionan una forma nativa de Kubernetes para gestionar tareas recurrentes basadas en el tiempo.
Reiniciar automáticamente un contenedor que se ha vuelto inoperable (por ejemplo, interbloqueo).
Configurar un `livenessProbe` en la especificación del contenedor. Si la sonda falla, el kubelet reinicia el contenedor.
Por qué: Las sondas de liveness (liveness probes) proporcionan un potente mecanismo de auto-recuperación para aplicaciones que pueden quedarse atascadas en un estado roto sin colapsar.
Evitar que el tráfico se envíe a un contenedor que aún no está listo para atender solicitudes.
Configurar un `readinessProbe` en la especificación del contenedor. El Pod solo se añade a los endpoints del Service después de que la sonda tenga éxito.
Por qué: Las sondas de readiness (readiness probes) son críticas para las actualizaciones continuas sin tiempo de inactividad, asegurando que los nuevos Pods estén completamente inicializados antes de recibir tráfico de producción.
Ejecutar tareas de configuración o esperar a que las dependencias estén listas antes de iniciar el contenedor principal de la aplicación.
Definir uno o más `initContainers` en la especificación del Pod. Se ejecutan hasta su finalización en secuencia antes de que comiencen los contenedores de la aplicación.
Por qué: Los Init containers proporcionan una separación limpia para la lógica de configuración, asegurando que se cumplan los requisitos previos sin saturar el contenedor principal de la aplicación.
Asegurar que los Pods se programen en nodos con características específicas (por ejemplo, nodos con GPUs, SSDs).
Usar `nodeAffinity` en la especificación del Pod para establecer reglas basadas en etiquetas de nodo. Puede ser una restricción "required" (dura) o "preferred" (suave).
Por qué: La afinidad de nodo (node affinity) es más expresiva que `nodeSelector` y es la forma moderna de controlar la ubicación de los Pods basándose en las propiedades del nodo.
Controlar la co-ubicación de Pods entre sí para rendimiento o alta disponibilidad.
Usar `podAffinity` para programar Pods juntos (por ejemplo, en el mismo nodo) o `podAntiAffinity` para dispersarlos (por ejemplo, a través de diferentes nodos o zonas).
Por qué: La anti-afinidad (anti-affinity) es crucial para asegurar que las réplicas de un servicio no estén en el mismo dominio de falla, aumentando así la disponibilidad.
Evitar que los Pods de propósito general se programen en nodos dedicados o de propósito especial.
Aplicar un `Taint` a un nodo. Los Pods deben tener una `Toleration` coincidente en su especificación para ser programados en ese nodo.
Por qué: Los Taints y tolerations aseguran que los nodos estén reservados para cargas de trabajo que tienen permiso explícito para ejecutarse allí.
Asegurar alta disponibilidad distribuyendo Pods uniformemente a través de dominios de falla como zonas o nodos.
Definir `topologySpreadConstraints` en la especificación del Pod para controlar cómo se distribuyen los Pods basándose en etiquetas y claves de topología (por ejemplo, `topology.kubernetes.io/zone`).
Por qué: Esto proporciona un control más granular sobre la alta disponibilidad que la anti-afinidad de Pod, evitando que todas las réplicas se concentren en una única ubicación.
Escalar automáticamente el número de réplicas de la aplicación basándose en la carga observada.
Crear un recurso `HorizontalPodAutoscaler` (HPA) que apunta a un Deployment y especifica una métrica (por ejemplo, utilización de CPU) y un valor objetivo.
Por qué: HPA permite el escalado elástico, asegurando el rendimiento bajo carga mientras ahorra costos durante períodos de baja actividad, sin intervención manual.
Añadir o eliminar automáticamente nodos de trabajo del clúster para igualar la demanda de recursos.
Desplegar el `Cluster Autoscaler`. Observa los Pods que no pueden ser programados (debido a la escasez de recursos) y añade nodos, o elimina nodos subutilizados.
Por qué: El Cluster Autoscaler gestiona la elasticidad a nivel de infraestructura, trabajando con proveedores de la nube para ajustar el tamaño del clúster basándose en las necesidades de la carga de trabajo.
Asegurar que un número mínimo de réplicas de la aplicación permanezcan disponibles durante interrupciones voluntarias (por ejemplo, actualizaciones de nodos).
Crear un `PodDisruptionBudget` (PDB) especificando `minAvailable` o `maxUnavailable` para un conjunto de Pods.
Por qué: Los PDBs evitan que acciones como `kubectl drain` desactiven demasiadas réplicas a la vez, salvaguardando la disponibilidad de la aplicación.
Realizar una actualización sin tiempo de inactividad para una aplicación sin estado.
Usar un `Deployment` con la estrategia `RollingUpdate` por defecto. Configurar `maxSurge` y `maxUnavailable` para controlar el proceso de actualización.
Por qué: Las actualizaciones continuas (rolling updates) reemplazan gradualmente los Pods antiguos por nuevos, asegurando que el servicio permanezca disponible durante toda la actualización.
Entrega de Aplicaciones Cloud Native
Gestionar despliegues de infraestructura y aplicaciones de forma declarativa con control de versiones y un registro de auditoría.
Implementar GitOps. Usar un repositorio Git como única fuente de verdad. Usar una herramienta como Argo CD o Flux para sincronizar automáticamente el estado del clúster con Git.
Por qué: GitOps proporciona un historial claro y auditable de todos los cambios y permite reversiones fáciles deshaciendo commits de Git. Operacionaliza la Infraestructura como Código.
Empaquetar, configurar y desplegar aplicaciones complejas de Kubernetes de forma reutilizable y versionada.
Usar `Helm`, el gestor de paquetes para Kubernetes. Empaquetar aplicaciones como `Charts` con manifiestos con plantillas y archivos `values.yaml` configurables.
Por qué: Helm simplifica la gestión de aplicaciones complejas con muchos componentes, manejando dependencias, versionado y gestión del ciclo de vida.
Personalizar manifiestos de Kubernetes para diferentes entornos sin usar plantillas.
Usar `Kustomize`. Definir un archivo `kustomization.yaml` que especifique una configuración base y aplique parches o superposiciones para cada entorno.
Por qué: Kustomize ofrece una forma declarativa y sin plantillas para gestionar variantes de configuración, lo cual puede ser más simple y menos propenso a errores que el templating basado en texto.
Probar una nueva versión de la aplicación con un pequeño subconjunto de tráfico de producción antes de un despliegue completo.
Desplegar la nueva versión junto con la antigua. Usar una service mesh o un Ingress controller para enrutar un pequeño porcentaje de tráfico (por ejemplo, 5%) a la nueva versión "canary".
Por qué: Las versiones canary (canary releases) reducen el riesgo de introducir una versión defectuosa limitando el radio de impacto y permitiendo pruebas en producción.
Desplegar una nueva versión de la aplicación con cero tiempo de inactividad y capacidad de reversión instantánea.
Desplegar la nueva versión "verde" junto con la versión "azul" existente. Una vez que la versión verde esté verificada, cambiar el 100% del tráfico de azul a verde a nivel de Service/router.
Por qué: Los despliegues azul-verde (blue-green deployments) eliminan el tiempo de inactividad. La reversión es tan sencilla como cambiar el tráfico de vuelta al entorno azul.
Arquitectura Cloud Native
Diseñar una aplicación compleja como una colección de servicios pequeños, independientes y débilmente acoplados.
Estructurar la aplicación como microservicios, cada uno organizado en torno a una capacidad de negocio. Cada servicio debe poseer sus propios datos y comunicarse a través de APIs bien definidas.
Por qué: Esta arquitectura permite el desarrollo, despliegue y escalado independiente de los servicios, mejorando la agilidad y la resiliencia.
Construir una aplicación portátil, escalable y cloud-native siguiendo las mejores prácticas establecidas.
Adherirse a la metodología Twelve-Factor App. Un principio clave es almacenar toda la configuración que varía entre entornos en variables de entorno.
Por qué: Esto separa estrictamente la configuración del código, permitiendo que la misma imagen de contenedor se promocione entre entornos sin cambios.
Gestionar la comunicación compleja entre servicios, proporcionando gestión de tráfico, seguridad y observabilidad.
Implementar una service mesh (por ejemplo, Istio, Linkerd). Inyecta un proxy sidecar en cada Pod para interceptar y gestionar todo el tráfico de red.
Por qué: Una service mesh abstrae las preocupaciones de red (mTLS, reintentos, circuit breaking) del código de la aplicación, aplicándolas a nivel de plataforma.
Extender o mejorar la funcionalidad de un contenedor de aplicación sin modificar su código.
Desplegar un contenedor "sidecar" en el mismo Pod que la aplicación principal. Comparte la misma red y almacenamiento.
Por qué: Los Sidecars se utilizan para preocupaciones transversales como logging, monitoring o proxying (como en una service mesh), promoviendo la separación de preocupaciones.
Obtener una visión profunda del comportamiento de un sistema distribuido para facilitar la resolución de problemas.
Implementar los tres pilares de la observabilidad: `Metrics` (datos numéricos agregados), `Logs` (eventos discretos) y `Traces` (flujos de solicitudes de extremo a extremo).
Por qué: Juntos, estos tipos de datos proporcionan una visión completa de la salud y el rendimiento del sistema, lo cual es esencial para arquitecturas de microservicios complejas.