¡Bienvenido a la documentación de Kubernetes en Castellano!
Como podrá comprobar, la mayor parte de la documentación aún está disponible solo en inglés, pero no se preocupe, hay un equipo trabajando en la traducción al castellano.
Si quiere participar, puede entrar al canal de Slack #kubernets-docs-es y formar parte del equipo detrás de la localización.
También puede pasar por el canal para solicitar la traducción de alguna página en concreto o reportar algún error que se haya podido encontrar. ¡Cualquier aportación será bien recibida!
En esta sección encontrarás toda la información necesaria para poder identificar
la solución que mejor se adapta a tus necesidades.
Decidir dónde ejecutar Kubernetes depende principalmente de los recursos que
tengas disponibles, de las características del clúster y de cuánta flexibilidad
necesites.
Puedes ejecutar Kubernetes casi en cualquier lugar, desde su ordenador portátil
a máquinas virtuales en la nube o en un rack de servidores físicos on-premises.
Puedes configurar un clúster totalmente gestionado ejecutando un solo comando,
desplegar una solución parcialmente automatizada que te ofrezca un poco más de
control o directamente crear tu propio clúster de forma completamente manual
personalizando y controlando cada componente.
Soluciones para la máquina en local
Una solución para la máquina en local es la forma más sencilla de empezar a
utilizar Kubernetes. Puedes crear y probar clústeres de Kubernetes sin tener
que preocuparte por consumir recursos en el cloud ni disponer de conectividad.
Deberías elegir una solución de este tipo si buscas:
Probar o empezar a aprender sobre Kubernetes.
Desarrollar y testear clústeres localmente.
Soluciones gestionadas
Una solución gestionada es la forma más conveniente de crear y gestionar un
clúster de Kubernetes. El proveedor gestiona y opera los clústeres completamente
por lo que tú no has de preocuparte de nada.
Deberías elegir una solución de este tipo si:
Quieres una solución totalmente gestionada.
Quieres centrarte en desarrollar tus aplicaciones o servicios.
No tienes un equipo dedicado de operaciones pero quieres alta disponibilidad.
No tienes recursos para alojar y monitorizar sus clústeres.
Soluciones sobre IaaS en la nube
Un solución sobre IaaS en la nube permite crear clústeres Kubernetes con solo
unos pocos comandos, se encuentran en desarrollo activo, tienen el apoyo de la
comunidad y algunas de ellas forman parte del proyecto Kubernetes.
Se pueden desplegar en la infraestructura como servicio (IaaS) proporcionada por
los proveedores en la nube y ofrecen más flexibilidad que las soluciones
gestionadas, pero requieren más conocimientos para ponerlos en marcha y más
esfuerzo para operarlos.
Deberías elegir una solución de este tipo si:
Necesitas más control que el permitido en las soluciones gestionadas.
Quieres responsabilizarte de la operativa de los clústeres.
Soluciones sobre virtualización On-Premises
Una solución sobre virtualización sobre on-premises permite crear clústeres y
operarlos de forma segura en tú nube privada con solo unos pocos comandos.
Deberías elegir una solución de este tipo si:
Quieres desplegar clústeres en su nube privada dentro de tú red.
Tienes un equipo de operaciones para desplegar y operar el clúster.
Tienes los recursos necesarios para ejecutar y monitorizar el clúster.
Soluciones personalizadas
Una solución personalizadas proporciona total libertad sobre los clústeres
pero requiere más conocimiento y experiencia.
2.1 - Descargando Kubernetes
2.1.1 - Compilando desde código fuente
Se puede o bien crear una release desde el código fuente o bien descargar una versión pre-built. Si no se pretende hacer un desarrollo de Kubernetes en sí mismo, se sugiere usar una version pre-built de la release actual, que se puede encontrar en Release Notes.
El código fuente de Kubernetes se puede descargar desde el repositorio kubernetes/kubernetes .
Compilar desde código fuente
Si simplemente estas compilando una release desde el código fuente, no es necesario hacer una configuración completa del entorno golang ya que toda la compilación se realiza desde un contenedor Docker.
Compilar es fácil.
git clone https://github.com/kubernetes/kubernetes.git
cd kubernetes
make release
Para más detalles sobre el proceso de compilación de una release, visita la carpeta kubernetes/kubernetes build
2.2 - Desplegando un clúster con kubeadm
2.3 - Soluciones sobre IaaS en la nube
2.4 - Soluciones sobre virtualización On-Premises
2.5 - Soluciones personalizadas
2.6 - Kubernetes sobre Windows
3 - Conceptos
La sección de conceptos te ayudará a conocer los componentes de Kubernetes así como las abstracciones que utiliza para representar tu cluster. Además, te ayudará a obtener un conocimiento más profundo sobre cómo funciona Kubernetes.
Introducción
En Kubernetes se utilizan los objetos de la API de Kubernetes para describir el estado deseado del clúster: qué aplicaciones u otras cargas de trabajo se quieren ejecutar, qué imagenes de contenedores usan, el número de replicas, qué red y qué recursos de almacenamiento quieres que tengan disponibles, etc. Se especifica el estado deseado del clúster mediante la creación de objetos usando la API de Kubernetes, típicamente mediante la interfaz de línea de comandos, kubectl. También se puede usar la API de Kubernetes directamente para interactuar con el clúster y especificar o modificar tu estado deseado.
Una vez que se especifica el estado deseado, el Plano de Control de Kubernetes realizará las acciones necesarias para que el estado actual del clúster coincida con el estado deseado. Para ello, Kubernetes realiza diferentes tareas de forma automática, como pueden ser: parar o arrancar contenedores, escalar el número de réplicas de una aplicación dada, etc. El Plano de Control de Kubernetes consiste en un grupo de daemons que corren en tu clúster:
El Master de Kubernetes es un conjunto de tres daemons que se ejecutan en un único nodo del clúster, que se denomina nodo master. Estos daemons son: kube-apiserver, kube-controller-manager y kube-scheduler.
Los restantes nodos no master contenidos en tu clúster, ejecutan los siguientes dos daemons:
kubelet, el cual se comunica con el Master de Kubernetes.
kube-proxy, un proxy de red que implementa los servicios de red de Kubernetes en cada nodo.
Objetos de Kubernetes
Kubernetes tiene diferentes abstracciones que representan el estado de tu sistema: aplicaciones contenerizadas desplegadas y cargas de trabajo, sus recursos de red y almacenamiento asociados e información adicional acerca de lo que el clúster está haciendo en un momento dado. Estas abstracciones están representadas por objetos de la API de Kubernetes. Puedes revisar [Entendiendo los Objetos de Kubernetes] (/docs/concepts/overview/working-with-objects/kubernetes-objects/) para obtener más detalles.
Además, Kubernetes contiene abstracciónes de nivel superior llamadas Controladores. Los Controladores se basan en los objetos básicos y proporcionan funcionalidades adicionales sobre ellos. Incluyen:
Los distintos componentes del Plano de Control de Kubernetes, tales como el Master de Kubernetes y el proceso kubelet, gobiernan cómo Kubernetes se comunica con el clúster. El Plano de Control mantiene un registro de todos los Objetos de Kubernetes presentes en el sistema y ejecuta continuos bucles de control para gestionar el estado de los mismos. En un momento dado, los bucles del Plano de Control responderán a los cambios que se realicen en el clúster y ejecutarán las acciones necesarias para hacer que el estado actual de todos los objetos del sistema converjan hacia el estado deseado que has proporcionado.
Por ejemplo, cuando usas la API de Kubernetes para crear un Deployment, estás proporcionando un nuevo estado deseado para el sistema. El Plano de Control de Kubernetes registra la creación del objeto y lleva a cabo tus instrucciones ejecutando las aplicaciones requeridas en los nodos del clúster, haciendo de esta manera que el estado actual coincida con el estado deseado.
El Master de Kubernetes
El Master de Kubernetes es el responsable de mantener el estado deseado de tu clúster. Cuando interactuas con Kubernetes, como por ejemplo cuando utilizas la interfaz de línea de comandos kubectl, te estás comunicando con el master de tu clúster de Kubernetes.
Por "master" entendemos la colección de daemons que gestionan el estado del clúster. Típicamente, estos daemons se ejecutan todos en un único nodo del clúster, y este nodo recibe por tanto la denominación de master. El master puede estar replicado por motivos de disponibilidad y redundancia.
Kubernetes Nodes
En un clúster de Kubernetes, los nodos son las máquinas (máquinas virtuales, servidores físicos, etc) que ejecutan tus aplicaciones y flujos de trabajo en la nube. El master de Kubernetes controla cada nodo, por lo que en raras ocasiones interactuarás con los nodos directamente.
Si estás interesado en escribir una página sobre conceptos,
revisa Usando Templates de Páginas
para obtener información sobre el tipo de página conceptos y la plantilla conceptos.
3.1 - Introducción
3.1.1 - ¿Qué es Kubernetes?
Esta página ofrece una visión general sobre Kubernetes.
Kubernetes es una plataforma portable y extensible de código abierto para
administrar cargas de trabajo y servicios. Kubernetes facilita la automatización
y la configuración declarativa. Tiene un ecosistema grande y en rápido crecimiento.
El soporte, las herramientas y los servicios para Kubernetes están ampliamente disponibles.
¿Por qué necesito Kubernetes y qué puede hacer por mi?
Kubernetes tiene varias características. Puedes pensar en Kubernetes como:
una plataforma de contenedores
una plataforma de microservicios
una plataforma portable de nube
y mucho más.
Kubernetes ofrece un entorno de administración centrado en contenedores. Kubernetes
orquesta la infraestructura de cómputo, redes y almacenamiento para que las cargas de
trabajo de los usuarios no tengan que hacerlo. Esto ofrece la simplicidad de las Plataformas
como Servicio (PaaS) con la flexibilidad de la Infraestructura como Servicio (IaaS) y permite
la portabilidad entre proveedores de infraestructura.
¿Qué hace de Kubernetes una plataforma?
A pesar de que Kubernetes ya ofrece muchas funcionalidades, siempre hay nuevos
escenarios que se benefician de nuevas características. Los flujos de trabajo
de las aplicaciones pueden optimizarse para acelerar el tiempo de desarrollo.
Una solución de orquestación propia puede ser suficiente al principio, pero suele requerir
una automatización robusta cuando necesita escalar. Es por ello que Kubernetes fue diseñada como
una plataforma: para poder construir un ecosistema de componentes y herramientas que hacen
más fácil el desplegar, escalar y administrar aplicaciones.
Las etiquetas, o Labels, le
permiten a los usuarios organizar sus recursos como deseen. Las anotaciones, o Annotations, les permiten asignar información arbitraria a un recurso para
facilitar sus flujos de trabajo y hacer más fácil a las herramientas administrativas inspeccionar el estado.
Este
diseño
ha permitido que otros sistemas sean construidos sobre Kubernetes.
Lo que Kubernetes no es
Kubernetes no es una Plataforma como Servicio (PaaS) convencional. Ya que
Kubernetes opera a nivel del contenedor y no a nivel del hardware, ofrece
algunas características que las PaaS también ofrecen, como deployments,
escalado, balanceo de carga, registros y monitoreo. Dicho esto, Kubernetes
no es monolítico y las soluciones que se ofrecen de forma predeterminada
son opcionales e intercambiables.
Kubernetes ofrece los elementos esenciales para construir una plataforma
para desarrolladores, preservando la elección del usuario y la flexibilidad
en las partes más importantes.
Entonces, podemos decir que Kubernetes:
No limita el tipo de aplicaciones que soporta. Kubernetes busca dar soporte a un número diverso de cargas de trabajo, que incluyen aplicaciones con y sin estado así como aplicaciones que procesan datos. Si la aplicación puede correr en un contenedor, debería correr bien en Kubernetes.
No hace deployment de código fuente ni compila tu aplicación. Los flujos de integración, entrega y deployment continuo (CI/CD) vienen determinados por la cultura y preferencia organizacional y sus requerimientos técnicos.
No provee servicios en capa de aplicación como middleware (por ejemplo, buses de mensaje), frameworks de procesamiento de datos (como Spark), bases de datos (como MySQL), caches o sistemas de almacenamiento (como Ceph). Es posible correr estas aplicaciones en Kubernetes, o acceder a ellos desde una aplicación usando un mecanismo portable como el Open Service Broker.
No dictamina las soluciones de registros, monitoreo o alerta que se deben usar. Hay algunas integraciones que se ofrecen como prueba de concepto, y existen mecanismos para recolectar y exportar métricas.
No provee ni obliga a usar un sistema o lenguaje de configuración (como jsonnet) sino que ofrece una API declarativa que puede ser usada con cualquier forma de especificación declarativa
No provee ni adopta un sistema exhaustivo de mantenimiento, administración o corrección automática de errores
Además, Kubernetes no es un mero sistema de orquestación. De hecho, Kubernetes elimina la necesidad de orquestar. Orquestación se define como la ejecución de un flujo de trabajo definido: haz A, luego B y entonces C. Kubernetes está compuesto de un conjunto de procesos de control independientes y combinables entre si que llevan el estado actual hacia el estado deseado. No debería importar demasiado como llegar de A a C. No se requiere control centralizado y, como resultado, el sistema es más fácil de usar, más poderoso, robusto, resiliente y extensible.
¿Por qué usar contenedores?
¿Te preguntas las razones para usar contenedores?
La Manera Antigua de desplegar aplicaciones era instalarlas en un
servidor usando el administrador de paquetes del sistema operativo.
La desventaja era que los ejecutables, la configuración, las librerías
y el ciclo de vida de todos estos componentes se entretejían unos a
otros. Podíamos construir imágenes de máquina virtual inmutables para
tener rollouts y rollbacks predecibles, pero las máquinas virtuales
son pesadas y poco portables.
La Manera Nueva es desplegar contenedores basados en virtualización
a nivel del sistema operativo, en vez del hardware. Estos contenedores
están aislados entre ellos y con el servidor anfitrión: tienen sus propios
sistemas de archivos, no ven los procesos de los demás y el uso de recursos
puede ser limitado. Son más fáciles de construir que una máquina virtual, y
porque no están acoplados a la infraestructura y sistema de archivos del
anfitrión, pueden llevarse entre nubes y distribuciones de sistema operativo.
Ya que los contenedores son pequeños y rápidos, una aplicación puede ser
empaquetada en una imagen de contenedor. Esta relación uno a uno entre
aplicación e imagen nos abre un abanico de beneficios para usar contenedores.
Con contenedores, podemos crear imágenes inmutables al momento de la compilación
en vez del despliegue ya que las aplicaciones no necesitan componerse junto al
resto del stack ni atarse al entorno de infraestructura de producción. Generar
una imagen de contenedor al momento de la compilación permite tener un entorno
consistente que va desde desarrollo hasta producción. De igual forma, los contenedores
son más transparentes que las máquinas virtuales y eso hace que el monitoreo y la
administración sean más fáciles. Esto se aprecia más cuando los ciclos de vida de
los contenedores son administrados por la infraestructura en vez de un proceso supervisor
escondido en el contenedor. Por último, ya que solo hay una aplicación por contenedor,
administrar el despliegue de la aplicación se reduce a administrar el contenedor.
En resumen, los beneficios de usar contenedores incluyen:
Ágil creación y despliegue de aplicaciones:
Mayor facilidad y eficiencia al crear imágenes de contenedor en vez de máquinas virtuales
Desarrollo, integración y despliegue continuo:
Permite que la imagen de contenedor se construya y despliegue de forma frecuente y confiable,
facilitando los rollbacks pues la imagen es inmutable
Separación de tareas entre Dev y Ops:
Puedes crear imágenes de contenedor al momento de compilar y no al desplegar, desacoplando la
aplicación de la infraestructura
Observabilidad
No solamente se presenta la información y métricas del sistema operativo, sino la salud de la
aplicación y otras señales
Consistencia entre los entornos de desarrollo, pruebas y producción:
La aplicación funciona igual en un laptop y en la nube
Portabilidad entre nubes y distribuciones:
Funciona en Ubuntu, RHEL, CoreOS, tu datacenter físico, Google Kubernetes Engine y todo lo demás
Administración centrada en la aplicación:
Eleva el nivel de abstracción del sistema operativo y el hardware virtualizado a la aplicación que funciona en un sistema con recursos lógicos
Microservicios distribuidos, elásticos, liberados y débilmente acoplados:
Las aplicaciones se separan en piezas pequeñas e independientes que pueden ser desplegadas y administradas de forma dinámica, y no como una aplicación monolítica que opera en una sola máquina de gran capacidad
Aislamiento de recursos:
Hace el rendimiento de la aplicación más predecible
Utilización de recursos:
Permite mayor eficiencia y densidad
¿Qué significa Kubernetes? ¿Qué significa K8S?
El nombre Kubernetes proviene del griego y significa timonel o piloto. Es la raíz de gobernador y de cibernética. K8s
es una abrevación que se obtiene al reemplazar las ocho letras "ubernete" con el número 8.
Este documento describe los distintos componentes que
son necesarios para operar un clúster de Kubernetes.
Componentes del plano de control
Los componentes que forman el plano de control toman decisiones globales sobre
el clúster (por ejemplo, la planificación) y detectan y responden a eventos del clúster, como la creación
de un nuevo pod cuando la propiedad replicas de un controlador de replicación no se cumple.
Estos componentes pueden ejecutarse en cualquier nodo del clúster. Sin embargo para simplificar, los
scripts de instalación típicamente se inician en el mismo nodo de forma exclusiva,
sin que se ejecuten contenedores de los usuarios en esos nodos. El plano de control se ejecuta en varios nodos
para garantizar la alta disponibilidad.
kube-apiserver
El servidor de la API es el componente del plano de control
de Kubernetes que expone la API de Kubernetes. Se trata del frontend de Kubernetes,
recibe las peticiones y actualiza acordemente el estado en etcd.
La principal implementación de un servidor de la API de Kubernetes es
kube-apiserver.
Es una implementación preparada para ejecutarse en alta disponiblidad y que
puede escalar horizontalmente para balancear la carga entre varias instancias.
etcd
Almacén de datos persistente, consistente y distribuido de clave-valor utilizado
para almacenar toda a la información del clúster de Kubernetes.
Si tu clúster utiliza etcd como sistema de almacenamiento, échale un vistazo a la
documentación sobre estrategias de backup.
Componente del plano de control que está pendiente de los
Pods que no tienen ningún
nodo asignado
y seleciona uno donde ejecutarlo.
Para decidir en qué nodo
se ejecutará el pod, se tienen
en cuenta diversos factores: requisitos de recursos, restricciones de hardware/software/políticas,
afinidad y anti-afinidad, localización de datos dependientes, entre otros.
kube-controller-manager
Componente del plano de control que ejecuta los controladores de Kubernetes.
Lógicamente cada controlador
es un proceso independiente, pero para reducir la complejidad, todos se compilan
en un único binario y se ejecuta en un mismo proceso.
Estos controladores incluyen:
Controlador de nodos: es el responsable de detectar y responder cuándo un nodo deja de funcionar
Controlador de replicación: es el responsable de mantener el número correcto de pods para cada controlador
de replicación del sistema
Controlador de endpoints: construye el objeto Endpoints, es decir, hace una unión entre los Services y los Pods
Controladores de tokens y cuentas de servicio: crean cuentas y tokens de acceso a la API por defecto para los nuevos Namespaces.
cloud-controller-manager
cloud-controller-manager ejecuta controladores que
interactúan con proveedores de la nube. El binario cloud-controller-manager es una característica alpha que se introdujo en la versión 1.6 de Kubernetes.
cloud-controller-manager sólo ejecuta ciclos de control específicos para cada proveedor de la nube. Es posible
desactivar estos ciclos en kube-controller-manager pasando la opción --cloud-provider= external cuando se arranque el kube-controller-manager.
cloud-controller-manager permite que el código de Kubernetes y el del proveedor de la nube evolucionen de manera independiente. Anteriormente, el código de Kubernetes dependía de la funcionalidad específica de cada proveedor de la nube. En el futuro, el código que sea específico a una plataforma debería ser mantenido por el proveedor de la nube y enlazado a cloud-controller-manager al correr Kubernetes.
Los siguientes controladores dependen de alguna forma de un proveedor de la nube:
Controlador de nodos: es el responsable de detectar y actuar cuándo un nodo deja de responder
Controlador de rutas: para configurar rutas en la infraestructura de nube subyacente
Controlador de servicios: para crear, actualizar y eliminar balanceadores de carga en la nube
Controlador de volúmenes: para crear, conectar y montar volúmenes e interactuar con el proveedor de la nube para orquestarlos
Componentes de nodo
Los componentes de nodo corren en cada nodo, manteniendo a los pods en funcionamiento y proporcionando el entorno de ejecución de Kubernetes.
kubelet
Agente que se ejecuta en cada nodo de un clúster. Se asegura de que los contenedores estén corriendo en un pod.
El agente kubelet toma un conjunto de especificaciones de Pod, llamados
PodSpecs, que han sido creados por Kubernetes y garantiza que los contenedores descritos en ellos estén funcionando y
en buen estado.
kube-proxy
kube-proxy permite abstraer un servicio en Kubernetes manteniendo las
reglas de red en el anfitrión y haciendo reenvío de conexiones.
Los addons son pods y servicios que implementan funcionalidades del clúster. Estos pueden ser administrados
por Deployments, ReplicationControllers y otros. Los addons asignados a un espacio de nombres se crean en el espacio kube-system.
Más abajo se describen algunos addons. Para una lista más completa de los addons disponibles, por favor visite Addons.
DNS
Si bien los otros addons no son estrictamente necesarios, todos los clústers de Kubernetes deberían tener un DNS interno del clúster ya que la mayoría de los ejemplos lo requieren.
El DNS interno del clúster es un servidor DNS, adicional a los que ya podrías tener en tu red, que sirve registros DNS a los servicios de Kubernetes.
Los contenedores que son iniciados por Kubernetes incluyen automáticamente este servidor en sus búsquedas DNS.
Interfaz Web (Dashboard)
El Dashboard es una interfaz Web de propósito general para clústeres de Kubernetes. Le permite a los usuarios administrar y resolver problemas que puedan presentar tanto las aplicaciones como el clúster.
Monitor de recursos de contenedores
El Monitor de recursos de contenedores almacena
de forma centralizada series de tiempo con métricas sobre los contenedores, y provee una interfaz para navegar estos
datos.
Registros del clúster
El mecanismo de registros del clúster está a cargo de almacenar
los registros de los contenedores de forma centralizada, proporcionando una interfaz de búsqueda y navegación.
La API de Kubernetes sirve como base para el esquema de configuración declarativa del sistema. La herramienta de
línea de comandos kubectl puede ser usada para crear, actualizar, eliminar y consultar objetos a través de la API.
Kubernetes también almacena el estado de los recursos de la API en forma serializada. Actualmente esto se hace en etcd.
Kubernetes está compuesto, en si mismo, por varios componentes que interactúan a través de su API.
Cambios a la API
En nuestra experiencia, cualquier sistema exitoso necesita crecer y evolucionar al cambiar o emerger nuevos casos de uso. Por lo tanto, esperamos que la API de Kubernetes cambie y crezca continuamente. Dicho esto, nuestro objetivo es no romper la compatibilidad con los clientes ya existentes, por un período de tiempo razonable. En general, podemos esperar que se agreguen nuevos recursos y propiedades con cierta frecuencia. Para eliminar un recurso o propiedad, se requiere seguir la política de obsolescencia de la API.
En el documento de cambios a la API describimos como cambiar la API y definimos lo que es considerado como un cambio compatible.
Definiciones OpenAPI y Swagger
Los detalles completos de la API se documentan usando OpenAPI.
A partir de Kubernetes 1.10, el servidor de API de Kubernetes provee una especificación OpenAPI en el endpoint /openapi/v2.
Se puede solicitar un formato en particular utilizando las siguientes cabeceras HTTP:
Cabecera
Valores admitidos
Accept
application/json, application/com.github.proto-openapi.spec.v2@v1.0+protobuf (el content-type predeterminado es application/json si esta cabecera contiene */* o se omite)
Accept-Encoding
gzip (esta cabecera es opcional)
Antes de 1.14, los endpoints separados por formato (/swagger.json, /swagger-2.0.0.json, /swagger-2.0.0.pb-v1, /swagger-2.0.0.pb-v1.gz)
servían la especificación OpenAPI en distintos formatos. Estos endpoints se consideran obsoletos y serán removidos en Kubernetes 1.14.
Kubernetes implementa un formato alternativo de serialización basado en Protocol Buffer (Protobuf) diseñado principalmente para las comunicaciones dentro del clúster. Este formato está documentado en su propuesta de diseño y los archivos IDL de cada esquema se encuentran en los paquetes de Go que definen los objetos de la API.
Antes de 1.14, el apiserver de Kubernetes ofrecía una API para obtener la especificación Swagger v1.2 de la API de Kubernetes en /swaggerapi. Este endpoint se considera obsoleto y será removido en Kubernetes 1.14.
Versionado de la API
Para facilitar la eliminación de propiedades o reestructurar la representación de un recurso, Kubernetes soporta múltiples versiones de la API en distintas rutas como /api/v1 or /apis/extensions/v1beta1.
Se versiona a nivel de la API en vez de a nivel de los recursos o propiedades para asegurarnos de que la API presenta una visión clara y consistente de los recursos y el comportamiento del sistema, y para controlar el acceso a las APIs experimentales o que estén terminando su ciclo de vida. Los esquemas de serialización JSON y Protobuf siguen los mismos lineamientos para los cambios, es decir, estas descripciones cubren ambos formatos.
Se ha de tener en cuenta que hay una relación indirecta entre el versionado de la API y el versionado del resto del software. La propuesta de versionado de la API y releases describe esta relación.
Las distintas versiones de la API implican distintos niveles de estabilidad y soporte. El criterio para cada nivel se describe en detalle en la documentación de Cambios a la API. A continuación se ofrece un resumen:
Nivel "alpha":
El nombre de la versión contiene alpha (p. ej., v1alpha1).
Puede tener muchos errores. Activar esta característica podría exponer errores. Desactivada por defecto.
El soporte para esta característica podría ser eliminado sin previo aviso.
La API podría volverse incompatible en el futuro y sin previo aviso.
Se recomienda su uso solo en clústers efímeros y de prueba ya que hay mayor riesgo de errores y carece de soporte a largo plazo
Nivel "beta":
El nombre de la versión contiene beta (p. ej., v2beta3).
El código ha sido probado. Activar esta característica es seguro. Activada por defecto.
Los detalles de esta característica podrían cambiar, pero se mantendrá el soporte.
El esquema y/o la semántica de un objeto podría volverse incompatible en el futuro. Si esto pasa, se ofrecerán instrucciones para migrar a una nueva versión. Esto podría requerir eliminar, editar o volver a crear objetos. El proceso de edición podría requerir planificación, incluyendo tiempo de inactividad para aplicaciones que usaban esta característica.
No se recomienda para aplicaciones críticas de negocio ya que podría volverse incompatible en futuras versiones. Si tiene múltiples clústeres que pueden actualizarse de forma independiente se podría decidir correr este riesgo.
Por favor, ¡pruebe las características en fase beta y comparta sus comentarios! Una vez que salgan de la fase beta, sería más difícil hacer cambios.
Nivel estable:
El nombre de la versión es vX donde X es un entero.
Las versiones estables de las características aparecerán en los siguientes releases.
Grupos de API
Para que sea más fácil extender la API de Kubernetes, se han creado los grupos de API.
Estos grupos se especifican en una ruta REST y en la propiedad apiVersion de un objeto serializado.
Actualmente hay varios grupos de API en uso:
El grupo core (o group) en la ruta REST /api/v1 y usa apiVersion: v1.
Los grupos con entidad propia están en la ruta REST /apis/$NOMBRE_GRUPO/$VERSION y usan apiVersion: $NOMBRE_GRUPO/$VERSION.
(p. ej., apiVersion: batch/v1). La lista completa de los grupos soportados está disponible en la Referencia de la API.
Los usuarios que necesiten la semántica completa de la API pueden implementar su propio apiserver
usando el agregador para hacerlo
transparente para los clientes.
Activar los grupos de API
Ciertos recursos y grupos de API están activados por defecto. Pueden activarse o desactivarse con la opción --runtime-config en apiserver. --runtime-config acepta valores separados por coma. Por ejemplo, para desactivar batch/v1, use la opción
--runtime-config=batch/v1=false. Para activar batch/v2alpha1, pase la opción --runtime-config=batch/v2alpha1.
Esta opción acepta pares de clave=valor separados por coma que describen la configuración operativa del apiserver.
IMPORTANTE: Activar o desactivar grupos o recursos requiere reiniciar el apiserver y el controller-manager para que estos reconozcan los cambios a --runtime-config.
Activar recursos en los grupos
Los DaemonSets, Deployments, HorizontalPodAutoscalers, Ingresses, Jobs y ReplicaSets están activados por defecto.
Se pueden activar otros recursos con la opción --runtime-config del apiserver. Por ejemplo, como --runtime-config acepta valores separados por coma, puede desactivar los Deployments y los Ingress con la opción
--runtime-config=extensions/v1beta1/deployments=false,extensions/v1beta1/ingresses=false
3.1.4 - Objetos de Kubernetes
3.1.4.1 - Entender los Objetos de Kubernetes
Esta página explica cómo se representan los objetos de Kubernetes en la API de Kubernetes, y cómo puedes definirlos en formato .yaml.
Entender los Objetos de Kubernetes
Los Objetos de Kubernetes son entidades persistentes dentro del sistema de Kubernetes. Kubernetes utiliza estas entidades para representar el estado de tu clúster. Específicamente, pueden describir:
Qué aplicaciones corren en contenedores (y en qué nodos)
Los recursos disponibles para dichas aplicaciones
Las políticas acerca de cómo dichas aplicaciones se comportan, como las políticas de reinicio, actualización, y tolerancia a fallos
Un objeto de Kubernetes es un "registro de intención" -- una vez que has creado el objeto, el sistema de Kubernetes se pondrá en marcha para asegurar que el objeto existe. Al crear un objeto, en realidad le estás diciendo al sistema de Kubernetes cómo quieres que sea la carga de trabajo de tu clúster; esto es, el estado deseado de tu clúster.
Para trabajar con los objetos de Kubernetes -- sea para crearlos, modificarlos, o borrarlos -- necesitarás usar la API de Kubernetes. Cuando utilizas el interfaz de línea de comandos kubectl, por ejemplo, este realiza las llamadas necesarias a la API de Kubernetes en tu lugar. También puedes usar la API de Kubernetes directamente desde tus programas utilizando alguna de las Librerías de Cliente.
Alcance y Estado de un Objeto
Cada objeto de Kubernetes incluye dos campos como objetos anidados que determinan la configuración del objeto: el campo de objeto spec y el campo de objeto status. El campo spec, que es obligatorio, describe el estado deseado del objeto -- las características que quieres que tenga el objeto. El campo status describe el estado actual del objeto, y se suministra y actualiza directamente por el sistema de Kubernetes. En cualquier momento, el Plano de Control de Kubernetes gestiona de forma activa el estado actual del objeto para que coincida con el estado deseado requerido.
Por ejemplo, un Deployment de Kubernetes es un objeto que puede representar una aplicación de tu clúster. Cuando creas el Deployment, puedes especificar en el spec del Deployment que quieres correr tres réplicas de la aplicación. El sistema de Kubernetes lee el spec del Deployment y comienza a instanciar réplicas de tu aplicación -- actualizando el estado para conciliarlo con tu spec. Si cualquiera de las instancias falla (un cambio de estado), el sistema de Kubernetes soluciona la diferencia entre la spec y el estado llevando a cabo una correción -- en este caso, iniciando otra instancia de reemplazo.
Para obtener más información acerca de la spec, el status, y los metadatos de los objetos, echa un vistazo a las Normas de la API de Kubernetes.
Describir un Objeto de Kubernetes
Cuando creas un objeto en Kubernetes, debes especificar la spec del objeto que describe su estado deseado, así como información básica del mismo (como el nombre). Cuando usas la API de Kubernetes para crear el objeto (bien de forma directa o usando kubectl), dicha petición a la API debe incluir toda la información en formato JSON en el cuerpo de la petición. A menudo, le proporcionas la información a kubectl como un archivo .yaml.kubectl convierte esa información a JSON cuando realiza la llamada a la API.
Aquí hay un ejemplo de un archivo .yaml que muestra los campos requeridos y la spec del objeto Deployment de Kubernetes:
apiVersion:apps/v1# Usa apps/v1beta2 para versiones anteriores a 1.9.0kind:Deploymentmetadata:name:nginx-deploymentspec:selector:matchLabels:app:nginxreplicas:2# indica al controlador que ejecute 2 podstemplate:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.7.9ports:- containerPort:80
Una forma de crear un Deployment utilizando un archivo .yaml como el indicado arriba sería ejecutar el comando
kubectl apply
en el interfaz de línea de comandos, pasándole el archivo .yaml como argumento. Aquí tienes un ejemplo de cómo hacerlo:
En el archivo .yaml del objeto de Kubernetes que quieras crear, obligatoriamente tendrás que indicar los valores de los siguientes campos (como mínimo):
apiVersion - Qué versión de la API de Kubernetes estás usando para crear este objeto
kind - Qué clase de objeto quieres crear
metadata - Datos que permiten identificar unívocamente al objeto, incluyendo una cadena de texto para el name, UID, y opcionalmente el namespace
También deberás indicar el campo spec del objeto. El formato del campo spec es diferente según el tipo de objeto de Kubernetes, y contiene campos anidados específicos de cada objeto. La Referencia de la API de Kubernetes puede servirte de ayuda para encontrar el formato de la spec para cada uno de los objetos que puedes crear usando Kubernetes.
Por ejemplo, el formato de la spec para un objeto de tipo Pod lo puedes encontrar
aquí,
y el formato de la spec para un objeto de tipo Deployment lo puedes encontrar
aquí.
Siguientes pasos
Aprender más acerca de los objetos básicos más importantes de Kubernetes, como el Pod.
3.1.4.2 - Nombres
Todos los objetos de la API REST de Kubernetes se identifica de forma inequívoca mediante un Nombre y un UID.
Para aquellos atributos provistos por el usuario que no son únicos, Kubernetes provee de etiquetas y anotaciones.
Una cadena de caracteres proporcionada por el cliente que identifica un objeto en la URL de un recurso, como por ejemplo, /api/v1/pods/nombre-del-objeto.
Los nombres de los objetos son únicos para cada tipo de objeto. Sin embargo, si se elimina el objeto, se puede crear un nuevo objeto con el mismo nombre.
Por regla general, los nombres de los recursos de Kubernetes no deben exceder la longitud máxima de 253 caracteres y deben incluir caracteres alfanuméricos en minúscula, -, y .; aunque algunos recursos tienen restricciones más específicas.
UIDs
Una cadena de caracteres generada por Kubernetes para identificar objetos de forma única.
Cada objeto creado a lo largo de toda la vida de un clúster Kubernetes tiene un UID distinto. Está pensado para distinguir entre ocurrencias históricas de entidades similares.
3.1.4.3 - Espacios de nombres
Kubernetes soporta múltiples clústeres virtuales respaldados por el mismo clúster físico.
Estos clústeres virtuales se denominan espacios de nombres (namespaces).
Cuándo Usar Múltiple Espacios de Nombre
Los espacios de nombres están pensados para utilizarse en entornos con muchos usuarios
distribuidos entre múltiples equipos, o proyectos. Para aquellos clústeres con
unas pocas decenas de usuarios, no deberías necesitar crear o pensar en espacios de
nombres en absoluto. Empieza a usarlos solamente si necesitas las características
que proporcionan.
Los espacios de nombres proporcionan un campo de acción para los nombres. Los nombres de los recursos
tienen que ser únicos dentro de cada espacio de nombres, pero no entre dichos espacios de nombres.
Los espacios de nombres son una forma de dividir los recursos del clúster
entre múltiples usuarios (via cuotas de recursos).
En futuras versiones de Kubernetes, los objetos de un mismo espacio de nombres
tendrán las mismas políticas de control de acceso por defecto.
No es necesario usar múltiples espacios de nombres sólo para separar recursos
ligeramente diferentes, como versiones diferentes de la misma aplicación: para ello
utiliza etiquetas para distinguir tus recursos dentro
del mismo espacio de nombres.
Puedes listar los espacios de nombres actuales dentro de un clúster mediante:
kubectl get namespaces
NAME STATUS AGE
default Active 1d
kube-system Active 1d
kube-public Active 1d
Kubernetes arranca con tres espacios de nombres inicialmente:
default El espacio de nombres por defecto para aquellos objetos que no especifican ningún espacio de nombres
kube-system El espacio de nombres para aquellos objetos creados por el sistema de Kubernetes
kube-public Este espacio de nombres se crea de forma automática y es legible por todos los usuarios (incluyendo aquellos no autenticados).
Este espacio de nombres se reserva principalmente para uso interno del clúster, en caso de que algunos recursos necesiten ser visibles y legibles de forma pública para todo el clúster.
La naturaleza pública de este espacio de nombres es simplemente por convención, no es un requisito.
Establecer el espacio de nombres para una petición
Para indicar de forma temporal el espacio de nombres para una petición, usa la opción --namespace.
Por ejemplo:
kubectl --namespace=<insert-namespace-name-here> run nginx --image=nginx
kubectl --namespace=<insert-namespace-name-here> get pods
Establecer la preferencia de espacio de nombres
Puedes indicar de forma permanente el espacio de nombres para todas las llamadas futuras a comandos kubectl
en dicho contexto.
Cuando creas un Servicio, se crea una entrada DNS correspondiente.
Esta entrada tiene la forma <service-name>.<namespace-name>.svc.cluster.local, que significa
que si un contenedor simplemente usa <service-name>, se resolverá al servicio
que sea local al espacio de nombres. Esto es de utilidad para poder emplear la misma
configuración entre múltiples espacios de nombres como Development, Staging y Production.
Si quieres referenciar recursos entre distintos espacios de nombres, entonces
debes utilizar el nombre cualificado completo de dominio (FQDN).
No Todos los Objetos están en un Espacio de nombres
La mayoría de los recursos de Kubernetes (ej. pods, services, replication controllers, y otros) están
en algunos espacios de nombres. Sin embargo, los recursos que representan a los propios
espacios de nombres no están a su vez en espacios de nombres.
De forma similar, los recursos de bajo nivel, como los nodos y
los volúmenes persistentes, no están en ningún espacio de nombres.
Para comprobar qué recursos de Kubernetes están y no están en un espacio de nombres:
# In a namespace
kubectl api-resources --namespaced=true# Not in a namespace
kubectl api-resources --namespaced=false
3.1.4.4 - Etiquetas y Selectores
Las etiquetas son pares de clave/valor que se asocian a los objetos, como los pods.
El propósito de las etiquetas es permitir identificar atributos de los objetos que son relevantes y significativos para los usuarios, pero que no tienen significado para el sistema principal.
Se puede usar las etiquetas para organizar y seleccionar subconjuntos de objetos. Las etiquetas se pueden asociar a los objetos a la hora de crearlos y posteriormente modificarlas o añadir nuevas.
Cada objeto puede tener un conjunto de etiquetas clave/valor definidas, donde cada clave debe ser única para un mismo objeto.
Las etiquetas permiten consultar y monitorizar los objetos de forma más eficiente y son ideales para su uso en UIs y CLIs. El resto de información no identificada debe ser registrada usando anotaciones.
Motivación
Las etiquetas permiten que los usuarios mapeen sus estructuras organizacionales en los propios objetos sin acoplamiento, sin forzar a los clientes a almacenar estos mapeos.
Los despliegues de servicios y los procesos en lotes suelen requerir a menudo la gestión de entidades multi-dimensionales (ej., múltiples particiones o despliegues, múltiples entregas, múltiples capas, múltiples microservicios por capa). Tal gestión a menudo requiere de operaciones horizontales que rompen la encapsulación de representaciones estrictamente jerárquicas, especialmente jerarquías rígidas determinadas por la infraestructura en vez de por los usuarios.
Estos son sólo algunos ejemplos de etiquetas de uso común; eres libre de establecer tus propias normas. Ten en cuenta que la clave de cada etiqueta debe ser única dentro de cada objeto.
Sintaxis y conjunto de caracteres
Las etiquetas son pares de clave/valor. Las claves válidas de etiqueta tienen dos partes: un prefijo opcional y un nombre, separados por una barra (/). La parte del nombre es obligatoria y debe ser menor o igual a 63 caracteres, empezando y terminando con un carácter alfanumérico ([a-z0-9A-Z]), con guiones (-), guiones bajos (_), puntos (.), y cualquier carácter alfanumérico en medio. El prefijo es opcional. Si se indica, este debe ser un subdominio DNS: una serie de etiquetas DNS separadas por puntos (.), no mayores de 253 caracteres en total, seguidas de una barra (/).
Si se omite el prefijo, la clave de la etiqueta se entiende que es privada para el usuario. Los componentes automatizados del sistema (ej. kube-scheduler, kube-controller-manager, kube-apiserver, kubectl, u otros de terceras partes) que añaden etiquetas a los objetos de usuario deben especificar obligatoriamente un prefijo.
Los prefijos kubernetes.io/ y k8s.io/ están reservados para el sistema de Kubernetes.
Los valores de etiqueta válidos deben tener como máximo 63 caracteres y empezar y terminar con un carácter alfanumérico ([a-z0-9A-Z]), con guiones (-), guiones bajos (_), puntos (.), y cualquier carácter alfanumérico en medio.
Selectores de etiquetas
Al contrario que los nombres y UIDs, las etiquetas no garantizan la unicidad. En general, se espera que muchos objetos compartan la(s) misma(s) etiqueta(s).
A través del selector de etiqueta, el cliente/usuario puede identificar un conjunto de objetos. El selector de etiqueta es la primitiva principal de agrupación en Kubernetes.
La API actualmente soporta dos tipos de selectores: basados en igualdad y basados en conjunto.
Un selector de etiqueta puede componerse de múltiples requisitos separados por coma. En el caso de múltiples requisitos, todos ellos deben ser satisfechos de forma que las comas actúan como operadores AND (&&) lógicos.
La semántica de selectores vacíos o no espefificados es dependiente del contexto,
y los tipos de la API que utilizan los selectores deberían documentar su propia validación y significado.
Nota: Para algunos tipos de la API, como los ReplicaSets, los selectores de etiqueta de dos instancias no deben superponerse dentro del mismo espacio de nombres, ya que el controlador puede interpretarlos como un conflicto y no ser capaz de determinar cuántas réplicas debería haber finalmente.
Requisito basado en Igualdad
Los requisitos basados en Igualdad o Desigualdad permiten filtrar por claves y valores de etiqueta. Los objetos coincidentes deben satisfacer todas y cada una de las etiquetas indicadas, aunque puedan tener otras etiquetas adicionalmente.
Se permiten tres clases de operadores =,==,!=. Los dos primeros representan la igualdad (y son simplemente sinónimos), mientras que el último representa la desigualdad. Por ejemplo:
environment = production
tier != frontend
El primero selecciona todos los recursos cuya clave es igual a environment y su valor es igual a production.
El último selecciona todos los recursos cuya clave es igual a tier y su valor distinto de frontend, y todos los recursos que no tengan etiquetas con la clave tier.
Se podría filtrar los recursos de production que excluyan frontend usando comas: environment=production,tier!=frontend
Un escenario de uso de requisitos basados en igualdad es aquel donde los Pods pueden especificar
los criterios de selección de nodo. Por ejemplo, el Pod de abajo selecciona aquellos nodos con
la etiqueta "accelerator=nvidia-tesla-p100".
Los requisitos de etiqueta basados en Conjuntos permiten el filtro de claves en base a un conjunto de valores. Se puede utilizar tres tipos de operadores: in,notin y exists (sólo el identificador clave). Por ejemplo:
environment in (production, qa)
tier notin (frontend, backend)
partition
!partition
El primer ejemplo selecciona todos los recursos cuya clave es igual a environment y su valor es igual a production o qa.
El segundo ejemplo selecciona todos los recursos cuya clave es igual a tier y sus valores son distintos de frontend y backend, y todos los recursos que no tengan etiquetas con la clavetier.
El tercer ejemplo selecciona todos los recursos que incluyan una etiqueta con la clave partition; sin comprobar los valores.
El cuarto ejemplo selecciona todos los recursos que no incluyan una etiqueta con la clave partition; sin comprobar los valores.
De forma similar, el separador de coma actúa como un operador AND . Así, el filtro de recursos con una clave igual a partition (sin importar el valor) y con un environment distinto de qa puede expresarse como partition,environment notin (qa).
El selector basado en conjunto es una forma genérica de igualdad puesto que environment=production es equivalente a environment in (production); y lo mismo aplica para != y notin.
Los requisitos basados en conjunto pueden alternarse con aquellos basados en igualdad. Por ejemplo: partition in (customerA, customerB),environment!=qa.
API
Filtro con LIST y WATCH
Las operaciones LIST y WATCH pueden especificar selectores de etiqueta para filtrar el conjunto de objetos devueltos usando un parámetro de consulta. Ambos requisitos están permitidos (se presentan aquí como aparecerían en la cadena URL de consulta):
requisitios basados en igualdad: ?labelSelector=environment%3Dproduction,tier%3Dfrontend
requisitios basados en conjunto: ?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29
Es posible utilizar ambos estilos de selección de etiquetas para mostrar u observar recursos con un cliente REST. Por ejemplo, para enfocarse en apiserver con kubectl usando el estilo basado en igualdad se puede ejecutar:
kubectl get pods -l environment=production,tier=frontend
o usando requisitos basados en conjunto:
kubectl get pods -l 'environment in (production),tier in (frontend)'
Como ya se ha comentado, los requisitos basados en conjunto son más expresivos. Por ejemplo, se puede implementar el operador OR sobre valores:
kubectl get pods -l 'environment in (production, qa)'
o restringir la coincidencia negativa mediante el operador exists:
kubectl get pods -l 'environment,environment notin (frontend)'
Establecer referencias en los objetos de la API
Algunos objetos de Kubernetes, como los services y los replicationcontrollers, también hacen uso de los selectores de etiqueta para referirse a otros conjuntos de objetos, como los pods.
Service y ReplicationController
El conjunto de pods que un service expone se define con un selector de etiqueta. De forma similar, el conjunto de pods que un replicationcontroller debería gestionar se define con un selector de etiqueta.
Los selectores de etiqueta para ambos objetos se definen en los archivos json o yaml usando mapas, y únicamente se permite los selectores basados en igualad:
"selector": {
"component" : "redis",
}
ó
selector:component:redis
este selector (respectivamente en formato json o yaml) es equivalente a component=redis o component in (redis).
Recursos que soportan requisitos basados en conjunto
Algunos recursos más recientes, como el Job, el Deployment, el Replica Set, y el Daemon Set, sí permiten requisitos basados en conjunto.
matchLabels es un mapa de pares {key,value}. Una única combinación de {key,value} en el mapa matchLabels es equivalente a un elemento en matchExpressions donde el campo key es "key", el operator es "In", y la matriz values contiene únicamente "value". matchExpressions es una lista de requisitos de selección de pod. Los operadores permitidos son In, NotIn, Exists, y DoesNotExist. El conjunto de valores no puede ser vacío en el caso particular de In y NotIn. Todos los requisitos, tanto de matchLabels como de matchExpressions se combinan entre sí con el operador AND -- todos ellos deben ser satisfechos.
Seleccionar conjuntos de objetos
Un caso de uso de selección basada en etiquetas es la posibilidad de limitar los nodos en los que un pod puede desplegarse.
Ver la documentación sobre selección de nodo para más información.
3.1.4.5 - Anotaciones
Puedes usar las anotaciones de Kubernetes para adjuntar metadatos arbitrarios a los objetos, de tal forma que clientes como herramientas y librerías puedan obtener fácilmente dichos metadatos.
Adjuntar metadatos a los objetos
Puedes usar las etiquetas o anotaciones para adjuntar metadatos a los objetos de Kubernetes.
Las etiquetas pueden utilizarse para seleccionar objetos y para encontrar colecciones de objetos que satisfacen ciertas condiciones.
Por el contrario, las anotaciones no se utilizan para identificar y seleccionar objetos.
Los metadatos de una anotación pueden ser pequeños o grandes, estructurados o no estructurados,
y pueden incluir caracteres no permitidos en las etiquetas.
Las anotaciones, al igual que las etiquetas, son mapas de clave/valor:
Aquí se presentan algunos ejemplos de información que podría ser indicada como anotaciones:
Campos gestionados por una capa de configuración declarativa.
Adjuntando dichos campos como anotaciones permitiría diferenciarlos de los
valores por defecto establecidos por clientes o servidores, además de los
campos auto-generados y los campos modificados por sistemas de auto-escalado.
Información acerca de la construcción, entrega, o imagen como marcas de fecha, IDs de entrega, rama de Git,
número de PR, funciones hash de imágenes, y direcciones de registro.
Referencias a los repositorios de trazas, monitorización, analíticas, o auditoría.
Información de librería de cliente o herramienta que puede usarse con fines de depuración de código:
por ejemplo, nombre, versión, e información de construcción.
Información de usuario o procedencia de herramienta/sistema, como las URLs de los
objetos provenientes de otros componentes del ecosistema.
Metadatos para una herramienta ligera de lanzamiento de aplicaciones: por ejemplo, configuración o puntos de control.
Número de teléfono o contacto de las personas a cargo, o entradas de directorio que
especifican dónde puede encontrarse dicha información, como la página web de un equipo de trabajo.
Directivas del usuario final a las implementaciones para modificar el comportamiento
o solicitar funcionalidades no estándar.
En vez de usar anotaciones, podrías almacenar este tipo de información en una
base de datos externa o un directorio, pero eso complicaría enormemente la posibilidad
de crear librerías compartidas de cliente, así como herramientas para el
despliegue, gestión, introspección, y similares.
Sintaxis y conjunto de caracteres
Las Anotaciones son entradas clave/valor. Una clave válida para una anotación tiene dos partes: un prefijo opcional y un nombre, separados por una barra (/). La parte del nombre es obligatoria y debe tener 63 caracteres o menos, empezando y terminando con un carácter alfanumérico ([a-z0-9A-Z]) con guiones (-), guiones bajos (_), puntos (.) en medio. El prefijo es opcional. Si se indica,
el prefijo debe ser un subdominio DNS: una serie de etiquetas DNS separadas por puntos (.), no superior a 253 caracteres en total, seguida de una barra (/).
Si se omite el prefijo, la clave de la anotación se entiende que es privada para el usuario. Los componentes automatizados del sistema (e.g. kube-scheduler, kube-controller-manager, kube-apiserver, kubectl, u otros de terceros) que añaden anotaciones a los objetos de usuario deben, pues, especificar un prefijo.
Los prefijos kubernetes.io/ y k8s.io/ se reservan para el uso exclusivo de los componentes principales de Kubernetes.
Los selectores de campo te permiten seleccionar recursos de Kubernetes basados en el valor de uno o más campos del recurso. Aquí se presentan varios ejemplos de consultas de selectores de campo:
metadata.name=my-service
metadata.namespace!=default
status.phase=Pending
Este comando kubectl selecciona todos los Pods para los cuales el valor del campo status.phase es igual a Running:
kubectl get pods --field-selector status.phase=Running
Nota:
Los selectores de campo son esencialmente filtros de recursos. Por defecto, no se aplica ningún selector/filtro, lo que significa que todos los tipos de recursos son seleccionados. Esto hace que las siguientes consultas con kubectl sean equivalentes:
kubectl get pods
kubectl get pods --field-selector ""
Campos soportados
Los selectores de campos soportados varían según el tipo de recursos de Kubernetes. Todos los tipos de recursos permiten los campos metadata.name y metadata.namespace. El uso de un selector de campo no soportado provoca un error. Por ejemplo:
kubectl get ingress --field-selector foo.bar=baz
Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace"
Operadores soportados
Puedes usar los operadores =, ==, y != en los selectores de campo (= y == significan lo mismo). Este comando de kubectl, por ejemplo, selecciona todos los servicios de Kubernetes que no están en el espacio de nombres default:
kubectl get services --field-selector metadata.namespace!=default
Selectores anidados
De la misma manera que con una etiqueta y otros selectores, los selectores de campo pueden anidarse como una lista de elementos separados por coma. Este comando de kubectl selecciona todos los Pods para los que el campo status.phase no es igual a Running y el campo spec.restartPolicy es igual a Always:
kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
Múltiples tipos de recursos
Puedes usar los selectores de campo entre múltiples tipos de recursos. Este comando de kubectl selecciona todos los Statefulsets y Services que no están en el espacio de nombres default:
kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
3.1.4.7 - Etiquetas recomendadas
Puedes visualizar y gestionar los objetos de Kubernetes con herramientas adicionales a kubectl
y el propio tablero de control. Un conjunto común de etiquetas permite a dichas herramientas
trabajar de forma interoperable, describiendo los objetos de una forma común que todas las
herramientas puedan entender.
Además del soporte a herramientas, las etiquetas recomendadas describen las aplicaciones
de forma que puedan ser consultadas.
Los metadatos se organizan en torno al concepto de una aplicación. Kubernetes no es
una plataforma como servicio (PaaS) y ni tiene o restringe la definición formal de una aplicación.
Al contrario, las aplicaciones son informales y se describen mediante el uso de los metadatos.
La definición de lo que contiene una aplicación es imprecisa.
Nota: Estas son las etiquetas recomendadas. Estas facilitan la gestión de aplicaciones,
pero no son obligatorias para las herramientas en general.
Las etiquetas compartidas y las anotaciones comparten un prefijo común: app.kubernetes.io.
Las etiquetas sin un prefijo son privadas para los usuarios. El prefijo compartido
garantiza que las etiquetas compartidas no entran en conflicto con las etiquetas
personalizadas de usuario.
Etiquetas
Para beneficiarse al máximo del uso de estas etiquetas, estas deberían aplicarse a cada objeto de recurso.
Clave
Descripción
Ejemplo
Tipo
app.kubernetes.io/name
El nombre de la aplicación
mysql
string
app.kubernetes.io/instance
Un nombre único que identifique la instancia de la aplicación
wordpress-abcxzy
string
app.kubernetes.io/version
La versión actual de la aplicación (ej., la versión semántica, cadena hash de revisión, etc.)
5.7.21
string
app.kubernetes.io/component
El componente dentro de la arquitectura
database
string
app.kubernetes.io/part-of
El nombre de una aplicación de nivel superior de la cual es parte esta aplicación
wordpress
string
app.kubernetes.io/managed-by
La herramienta usada para gestionar la operativa de una aplicación
helm
string
Para ilustrar estas etiquetas en acción, consideremos el siguiente objeto StatefulSet:
Una misma aplicación puede desplegarse una o más veces en un clúster de Kubernetes e,
incluso, el mismo espacio de nombres. Por ejemplo, wordpress puede instalarse más de una
vez de forma que sitios web diferentes sean instalaciones diferentes de wordpress.
El nombre de una aplicación y el nombre de la instancia se almacenan de forma separada.
Por ejemplo, WordPress tiene un app.kubernetes.io/name igual a wordpress mientras que
tiene un nombre de instancia, representado como app.kubernetes.io/instance con un valor de
wordpress-abcxzy. Esto permite identificar tanto a la aplicación como a sus instancias.
Cada instancia de una aplicación tiene su propio nombre único.
Ejemplos
Para ilustrar las diferentes formas en que se puede utilizar las etiquetas, los siguientes ejemplos presentan distintas complejidades.
Un Servicio Simple sin Estado
Considera el caso de un servicio simple sin estado desplegado mediante el uso de un objeto Deployment y Service. Los dos siguientes extractos de código representan cómo usar las etiquetas de la forma más sencilla.
El objeto Deployment se utiliza para supervisar los pods que ejecutan la propia aplicación.
Considera una aplicación un poco más complicada: una aplicación web (WordPress)
que utiliza una base de datos (MySQL), instalada utilizando Helm. Los siguientes extractos
de código ilustran la parte inicial de los objetos utilizados para desplegar esta aplicación.
El comienzo del objeto Deployment siguiente se utiliza para WordPress:
Con los objetos StatefulSet y Service de MySQL te darás cuenta que se incluye la información acerca de MySQL y Wordpress, la aplicación global.
3.1.5 - Gestión de objetos usando kubectl
3.2 - Arquitectura de Kubernetes
3.2.1 - Nodos
Un nodo es una máquina de trabajo en Kubernetes, previamente conocida como minion. Un nodo puede ser una máquina virtual o física, dependiendo del tipo de clúster. Cada nodo está gestionado por el componente máster y contiene los servicios necesarios para ejecutar pods. Los servicios en un nodo incluyen el container runtime, kubelet y el kube-proxy. Accede a la sección The Kubernetes Node en el documento de diseño de arquitectura para más detalle.
Estado del Nodo
El estado de un nodo comprende la siguiente información:
El uso de estos campos varía dependiendo del proveedor de servicios en la nube y/o de la configuración en máquinas locales.
HostName: El nombre de la máquina huésped como aparece en el kernel del nodo. Puede ser reconfigurado a través del kubelet usando el parámetro --hostname-override.
ExternalIP: La dirección IP del nodo que es accesible externamente (que está disponible desde fuera del clúster).
InternalIP: La dirección IP del nodo que es accesible únicamente desde dentro del clúster.
Estados
El campo conditions describe el estado de todos los nodos en modo Running.
Estado
Descripción
OutOfDisk
True si no hay espacio suficiente en el nodo para añadir nuevos pods; sino False
Ready
True si el nodo está en buen estado y preparado para aceptar nuevos pods, Falso si no puede aceptar nuevos pods, y Unknown si el controlador aún no tiene constancia del nodo después del último node-monitor-grace-period (por defecto cada 40 segundos)
MemoryPressure
True si hay presión en la memoria del nodo -- es decir, si el consumo de memoria en el nodo es elevado; sino False
PIDPressure
True si el número de PIDs consumidos en el nodo es alto -- es decir, si hay demasiados procesos en el nodo; sino False
DiskPressure
True si hay presión en el tamaño del disco -- esto es, si la capacidad del disco es baja; sino False
NetworkUnavailable
True si la configuración de red del nodo no es correcta; sino False
El estado del nodo se representa como un objeto JSON. Por ejemplo, la siguiente respuesta describe un nodo en buen estado:
Si el status de la condición Ready se mantiene como Unknown o False por más tiempo de lo que dura un pod-eviction-timeout, se pasa un argumento al kube-controller-manager y todos los pods en el nodo se marcan para borrado por el controlador de nodos. El tiempo de desalojo por defecto es de cinco minutos. En algunos casos, cuando el nodo se encuentra inaccesible, el API Server no puede comunicar con el kubelet del nodo. La decisión de borrar pods no se le puede hacer llegar al kubelet hasta que la comunicación con el API Server se ha restablecido. Mientras tanto, los pods marcados para borrado pueden continuar ejecutándose en el nodo aislado.
En versiones de Kubernetes anteriores a 1.5, el controlador de nodos forzaba el borrado de dichos pods inaccesibles desde el API Server. Sin embargo, desde la versión 1.5, el nodo controlador no fuerza el borrado de pods hasta que se confirma que dichos pods han dejado de ejecutarse en el clúster. Pods que podrían estar ejecutándose en un nodo inalcanzable se muestran como Terminating o Unknown. En aquellos casos en los que Kubernetes no puede deducir si un nodo ha abandonado el clúster de forma permanente, puede que sea el administrador el que tenga que borrar el nodo de forma manual. Borrar un objeto Node en un clúster de Kubernetes provoca que los objetos Pod que se ejecutaban en el nodo sean eliminados en el API Server y libera sus nombres.
En la versión 1.12, la funcionalidad TaintNodesByCondition se eleva a beta, de forma que el controlador del ciclo de vida de nodos crea taints de forma automática, que representan estados de nodos.
De forma similar, el planificador de tareas ignora estados cuando evalúa un nodo; en su lugar mira los taints del nodo y las tolerancias de los pods.
En la actualidad, los usuarios pueden elegir entre la versión de planificación antigua y el nuevo, más flexible, modelo de planificación.
Un pod que no tiene definida ninguna tolerancia es planificado utilizando el modelo antiguo, pero si un nodo tiene definidas ciertas tolerancias, sólo puede ser asignado a un nodo que lo permita.
Precaución: Habilitar esta funcionalidad crea una pequeña demora entre que una condición es evaluada y un taint creado. Esta demora suele ser inferior a un segundo, pero puede incrementar el número de pods que se planifican con éxito pero que luego son rechazados por el kubelet.
Capacidad
Describe los recursos disponibles en el nodo: CPU, memoria, y el número máximo de pods que pueden ser planificados dentro del nodo.
Información
Información general sobre el nodo: versión del kernel, versión de Kubernetes (versiones del kubelet y del kube-proxy), versión de Docker (si se utiliza), nombre del sistema operativo. Toda esta información es recogida por el kubelet en el nodo.
Gestión
A diferencia de pods y services, los nodos no son creados por Kubernetes de forma inherente; o son creados de manera externa por los proveedores de servicios en la nube como Google Compute Engine, o existen en la colección de máquinas virtuales o físicas. De manera que cuando Kubernetes crea un nodo, crea un objeto que representa el nodo. Después de ser creado, Kubernetes comprueba si el nodo es válido o no. Por ejemplo, si intentas crear un nodo con el siguiente detalle:
Kubernetes crea un objeto Node internamente (la representación), y valida el nodo comprobando su salud en el campo metadata.name. Si el nodo es válido -- es decir, si todos los servicios necesarios están ejecutándose -- el nodo es elegible para correr un pod. Sino, es ignorado para cualquier actividad del clúster hasta que se convierte en un nodo válido.
Nota: Kubernetes conserva el objeto de un nodo inválido y continúa probando por si el nodo, en algún momento, entrase en servicio.
Para romper este ciclo deberás borrar el objeto Node explícitamente.
Actualmente, hay tres componentes que interactúan con la interfaz de nodos de Kubernetes: controlador de nodos, kubelet y kubectl.
Controlador de Nodos
El controlador de nodos es un componente maestro en Kubernetes que gestiona diferentes aspectos de los nodos.
El controlador juega múltiples papeles en la vida de un nodo. El primero es asignar un bloque CIDR (Class Inter-Domain Routing) al nodo cuando este se registra (si la asignación CIDR está activada) que contendrá las IPs disponibles para asignar a los objetos que se ejecutarán en ese nodo.
El segundo es mantener actualizada la lista interna del controlador con la lista de máquinas disponibles a través del proveedor de servicios en la nube. Cuando Kubernetes se ejecuta en la nube, si un nodo deja de responder, el controlador del nodo preguntará al proveedor si la máquina virtual de dicho nodo continúa estando disponible. Si no lo está, el controlador borrará dicho nodo de su lista interna.
El tercero es el de monitorizar la salud de los nodos. El controlador de nodos es el responsable de actualizar la condición NodeReady del campo NodeStatus a ConditionUnknown cuando un nodo deja de estar accesible (por ejemplo, si deja de recibir señales de vida del nodo indicando que está disponible, conocidas como latidos o hearbeats en inglés) y, también es responsable de posteriormente desalojar todos los pods del nodo si este continúa estando inalcanzable. Por defecto, cuando un nodo deja de responder, el controlador sigue reintentando contactar con el nodo durante 40 segundos antes de marcar el nodo con ConditionUnknown y, si el nodo no se recupera de ese estado pasados 5 minutos, empezará a drenar los pods del nodo para desplegarlos en otro nodo que esté disponible. El controlador comprueba el estado de cada nodo cada --node-monitor-period segundos.
En versiones de Kubernetes previas a 1.13, NodeStatus es el heartbeat del nodo. Empezando con 1.13 la funcionalidad de node lease se introduce como alfa (NodeLease,
KEP-0009). Cuando la funcionalidad está habilitada, cada nodo tiene un objeto Lease asociado en el namespace kube-node-lease que se renueva periódicamente y ambos, el NodeStatus y el Lease son considerados como hearbeats del nodo. Node leases se renuevan con frecuencia, mientras que NodeStatus se transmite desde el nodo al máster únicamente si hay cambios o si ha pasado cierto tiempo (por defecto, 1 minuto, que es más que la cuenta atrás por defecto de 40 segundos que marca un nodo como inalcanzable). Al ser los node lease más ligeros que NodeStatus, los hearbeats resultan más económicos desde las perspectivas de escalabilidad y de rendimiento.
En Kubernetes 1.4, se actualizó la lógica del controlador de nodos para gestionar mejor los casos en los que un gran número de nodos tiene problemas alcanzando el nodo máster (Por ejemplo, cuando el nodo máster es el que tiene un problema de red). Desde 1.4, el controlador de nodos observa el estado de todos los nodos en el clúster cuando toma decisiones sobre desalojo de pods.
En la mayoría de los casos, el controlador de nodos limita el ritmo de desalojo --node-eviction-rate (0.1 por defecto) por segundo, lo que significa que no desalojará pods de más de un nodo cada diez segundos.
El comportamiento de desalojo de nodos cambia cuando un nodo en una zona de disponibilidad tiene problemas. El controlador de nodos comprobará qué porcentaje de nodos en la zona no se encuentran en buen estado (es decir, que su condición NodeReady tiene un valor ConditionUnknown o ConditionFalse) al mismo tiempo. Si la fracción de nodos con problemas es de al menos --unhealthy-zone-threshold (0.55 por defecto) entonces se reduce el ratio de desalojos: si el clúster es pequeño (por ejemplo, tiene menos o los mismos nodos que --large-cluster-size-threshold - 50 por defecto) entonces los desalojos se paran. Sino, el ratio se reduce a --secondary-node-eviction-rate (0.01 por defecto) por segundo. La razón por la que estas políticas se implementan por zonas de disponibilidad es debido a que una zona puede quedarse aislada del nodo máster mientras que las demás continúan conectadas. Si un clúster no comprende más de una zona, todo el clúster se considera una única zona.
La razón principal por la que se distribuyen nodos entre varias zonas de disponibilidad es para que el volumen de trabajo se transfiera a aquellas zonas que se encuentren en buen estado cuando una de las zonas se caiga.
Por consiguiente, si todos los nodos de una zona se encuentran en mal estado, el nodo controlador desaloja al ritmo normal --node-eviction-rate. En el caso extremo de que todas las zonas se encuentran en mal estado (es decir, no responda ningún nodo del clúster), el controlador de nodos asume que hay algún tipo de problema con la conectividad del nodo máster y paraliza todos los desalojos hasta que se restablezca la conectividad.
Desde la versión 1.6 de Kubernetes el controlador de nodos también es el responsable de desalojar pods que están ejecutándose en nodos con NoExecute taints, cuando los pods no permiten dichos taints. De forma adicional, como una funcionalidad alfa que permanece deshabilitada por defecto, el NodeController es responsable de añadir taints que se corresponden con problemas en los nodos del tipo nodo inalcanzable o nodo no preparado. En esta sección de la documentación hay más detalles acerca de los taints NoExecute y de la funcionalidad alfa.
Desde la versión 1.8, el controlador de nodos puede ser responsable de la creación de taints que representan condiciones de nodos. Esta es una funcionalidad alfa en 1.8.
Auto-Registro de Nodos
Cuando el atributo del kubelet --register-node está habilitado (el valor por defecto), el kubelet intentará auto-registrarse con el API Server. Este es el patrón de diseño preferido, y utilizado por la mayoría de distribuciones.
Para auto-registro, el kubelet se inicia con las siguientes opciones:
--kubeconfig - La ruta a las credenciales para autentificarse con el API Server.
--cloud-provider - Cómo comunicarse con un proveedor de servicios para leer meta-datos sobre si mismo.
--register-node - Registro automático con el API Server.
--register-with-taints - Registro del nodo con la lista de taints proporcionada (separada por comas <key>=<value>:<effect>). Esta opción se ignora si el atributo--register-node no está habilitado.
--node-ip - La dirección IP del nodo.
--node-labels - Etiquetas para añadir al nodo durante el registro en el clúster (ver las restricciones que impone el NodeRestriction admission plugin en 1.13+).
--node-status-update-frequency - Especifica la frecuencia con la que el nodo envía información de estado al máster.
Los administradores del clúster pueden crear y modificar objetos Node.
Si un administrador desea crear objetos Node de forma manual, debe levantar kubelet con el atributo --register-node=false.
Los administradores del clúster pueden modificar recursos Node (independientemente del valor de --register-node). Dichas modificaciones incluyen crear etiquetas en el nodo y/o marcarlo como no-planificable (de forma que pods no pueden ser planificados para instalación en el nodo).
Etiquetas y selectores de nodos pueden utilizarse de forma conjunta para controlar las tareas de planificación, por ejemplo, para determinar un subconjunto de nodos elegibles para ejecutar un pod.
Marcar un nodo como no-planificable impide que nuevos pods sean planificados en dicho nodo, pero no afecta a ninguno de los pods que existían previamente en el nodo. Esto resulta de utilidad como paso preparatorio antes de reiniciar un nodo, etc. Por ejemplo, para marcar un nodo como no-planificable, se ejecuta el siguiente comando:
kubectl cordon $NODENAME
Nota: Los pods creados por un controlador DaemonSet ignoran el planificador de Kubernetes y no respetan el atributo no-planificable de un nodo. Se asume que los daemons pertenecen a la máquina huésped y que se ejecutan incluso cuando esta está siendo drenada de aplicaciones en preparación de un reinicio.
Capacidad del Nodo
La capacidad del nodo (número de CPUs y cantidad de memoria) es parte del objeto Node.
Normalmente, nodos se registran a sí mismos y declaran sus capacidades cuando el objeto Node es creado. Si se está haciendo administración manual, las capacidades deben configurarse en el momento de añadir el nodo.
El planificador de Kubernetes asegura la existencia de recursos suficientes para todos los pods que se ejecutan en un nodo. Comprueba que la suma recursos solicitados por los pods no exceda la capacidad del nodo. Incluye todos los pods iniciados por el kubelet, pero no tiene control sobre contenedores iniciados directamente por el runtime de contenedores ni sobre otros procesos que corren fuera de contenedores.
Un nodo es un recurso principal dentro de la REST API de Kubernetes. Más detalles sobre el objeto en la API se puede encontrar en: Object Node API.
3.2.2 - Comunicación Nodo-Maestro
Este documento cataloga las diferentes vías de comunicación entre el nodo máster (en realidad el apiserver) y el clúster de Kubernetes. La intención es permitir a los usuarios personalizar sus instalaciones para proteger sus configuraciones de red de forma que el clúster pueda ejecutarse en una red insegura. (o en un proveedor de servicios en la nube con direcciones IP públicas)
Clúster a Máster
Todos los canales de comunicación desde el clúster hacia el máster terminan en el apiserver (ningún otro componente del máster está diseñado para exponer servicios remotos). En un despliegue típico, el apiserver está configurado para escuchar conexiones remotas en un canal seguro cómo HTTPS en el puerto (443) con una o más formas de autenticación de clientes habilitada. Una o más formas de autorización deberían ser habilitadas, especialmente si se permiten peticiones anónimas
o tokens de cuenta de servicio.
Los nodos deben ser aprovisionados con el certificado raíz público del clúster de forma que puedan conectar de forma segura con el apiserver en conjunción con credenciales de cliente válidas. Por ejemplo, en un despliegue por defecto en GKE, las credenciales de cliente proporcionadas al kubelet están en la forma de certificados de cliente. Accede kubelet TLS bootstrapping para ver cómo aprovisionar certificados de cliente de forma automática.
Aquellos Pods que deseen conectar con el apiserver pueden hacerlo de forma segura a través de una cuenta de servicio, de esta forma Kubernetes inserta de forma automática el certificado raíz público y un bearer token válido en el pod cuando este es instanciado. El servicio kubernetes (en todos los namespaces) se configura con una dirección IP virtual que es redireccionada (via kube-proxy) al punto de acceso HTTPS en el apiserver.
Los componentes máster también se comunican con el apiserver del clúster a través de un puerto seguro.
Como resultado, el modo de operación por defecto para conexiones desde el clúster (nodos y pods ejecutándose en nodos) al máster es seguro por defecto y puede correr en redes públicas y/o inseguras.
Máster a Clúster
Hay dos vías de comunicación primaria desde el máster (apiserver) al clúster. La primera es desde el apiserver al proceso kubelet que se ejecuta en cada nodo del clúster. La segunda es desde el apiserver a cualquier nodo, pod, o servicio a través de la funcionalidad proxy del apiserver.
apiserver al kubelet
Las conexiones del apiserver al kubelet se utilizan para:
Recoger entradas de registro de pods.
Conectar (a través de kubectl) con pods en ejecución.
Facilitar la funcionalidad port-forwarding del kubelet.
Estas conexiones terminan en el endpoint HTTPS del kubelet. Por defecto, el apiserver no verifica el certificado del kubelet, por lo que la conexión es vulnerable a ataques del tipo man-in-the-middle, e insegura para conectar a través de redes públicas o de no confianza.
Para verificar esta conexión, se utiliza el atributo --kubeket-certificate-authority que provee el apiserver con un certificado raíz con el que verificar el certificado del kubelet.
Si esto no es posible, se utiliza un túnel SSH entre el apiserver y el kubelet para conectar a través de redes públicas o de no confianza.
Las conexiones desde el apiserver a un nodo, pod o servicio se realizan por defecto con HTTP y, por consiguiente, no son autentificadas o encriptadas. Pueden ser ejecutadas en una conexión HTTPS segura añadiendo el prefijo https: al nodo, pod o nombre de servicio en la API URL, pero los receptores no validan el certificado provisto por el endpoint HTTPS ni facilitan credenciales de cliente asi que, aunque la conexión esté encriptada, esta no ofrece garantía de integridad. Estas conexiones no son seguras para conectar a través de redes públicas o inseguras.
Túneles SSH
Kubernetes ofrece soporte para túneles SSH que protegen la comunicación Máster -> Clúster. En este modo de configuración, el apiserver inicia un túnel SSH a cada nodo en el clúster (conectando al servidor SSH en el puerto 22) y transfiere todo el tráfico destinado a un kubelet, nodo, pod o servicio a través del túnel. El túnel garantiza que dicho tráfico no es expuesto fuera de la red en la que se ejecutan los nodos.
Los túneles SSH se consideran obsoletos, y no deberían utilizarse a menos que se sepa lo que se está haciendo. Se está diseñando un reemplazo para este canal de comunicación.
3.2.3 - Conceptos subyacentes del Cloud Controller Manager
El concepto del Cloud Controller Manager (CCM) (no confundir con el ejecutable) fue creado originalmente para permitir que Kubernetes y el código específico de proveedores de servicios en la nube evolucionen de forma independiente. El Cloud Controller Manager se ejecuta a la par con otros componentes maestros como el Kubernetes Controller Manager, el API Server y el planificador. También puede ejecutarse como un extra, en cuyo caso se ejecuta por encima de Kubernetes.
El diseño del Cloud Controller Manager está basado en un sistema de plugins, lo que permite a nuevos proveedores de servicios integrarse de forma fácil con Kubernetes. Se está trabajando en implementar nuevos proveedores de servicios y para migrar los existentes del antiguo modelo al nuevo CCM.
Este documento describe los conceptos tras el Cloud Controller Manager y detalla sus funciones asociadas.
En la siguiente imagen, se puede visualizar la arquitectura de un cluster de Kubernetes que no utiliza el Cloud Controller Manager:
Diseño
En el diagrama anterior, Kubernetes y el proveedor de servicios en la nube están integrados a través de diferentes componentes:
Kubelet
Kubernetes controller manager
Kubernetes API server
El CCM consolida toda la lógica dependiente de la nube de estos tres componentes para crear un punto de integración único. La nueva arquitectura con CCM se muestra a continuación:
Componentes del CCM
El CCM secciona parte de la funcionalidad del Kubernetes Controller Manager (KCM) y la ejecuta como procesos independientes. Específicamente, aquellos controladores en el KCM que son dependientes de la nube:
Controlador de Nodos
Controlador de Volúmenes
Controlador de Rutas
Controlador de Servicios
En la versión 1.9, el CCM se encarga de la ejecución de los siguientes controladores:
Controlador de Nodos
Controlador de Rutas
Controlador de Servicios
Nota: El controlador de volúmenes se dejó fuera del CCM de forma explícita. Debido a la complejidad que ello requería y a los esfuerzos existentes para abstraer lógica de volúmenes específica a proveedores de servicios, se decidió que el controlador de volúmenes no fuese movido al CCM.
El plan original para habilitar volúmenes en CCM era utilizar volúmenes Flex con soporte para volúmenes intercambiables. Sin embargo, otro programa conocido como CSI (Container Storage Interface) se está planeando para reemplazar Flex.
Considerando todo lo anterior, se ha decidido esperar hasta que CSI esté listo.
Funciones del CCM
El CCM hereda sus funciones de componentes que son dependientes de un proveedor de servicios en la nube. Esta sección se ha estructurado basado en dichos componentes:
1. Kubernetes Controller Manager
La mayoría de las funciones del CCM derivan del KCM. Como se ha mencionado en la sección anterior, el CCM es responsable de los siguientes circuitos de control:
Controlador de Nodos
Controlador de Rutas
Controlador de Servicios
Controlador de Nodos
El controlador de nodos es responsable de inicializar un nodo obteniendo información del proveedor de servicios sobre los nodos ejecutándose en el clúster. El controlador de nodos lleva a cabo las siguientes funciones:
Inicializa un nodo con etiquetas de región y zona específicas del proveedor.
Inicializa un nodo con detalles de la instancia específicos del proveedor, como por ejemplo, el tipo o el tamaño.
Obtiene las direcciones de red del nodo y su hostname.
En caso de que el nodo deje de responder, comprueba la nube para ver si el nodo ha sido borrado. Si lo ha sido, borra el objeto nodo en Kubernetes.
Controlador de Rutas
El controlador de Rutas es responsable de configurar rutas en la nube para que contenedores en diferentes nodos dentro de un clúster kubernetes se puedan comunicar entre sí.
Controlador de Servicios
El controlador de servicios es responsable de monitorizar eventos de creación, actualización y borrado de servicios. Basándose en el estado actual de los servicios en el clúster Kubernetes, configura balanceadores de carga del proveedor (como Amazon ELB, Google LB, or Oracle Cloud Infrastructure Lb) de forma que estos reflejen los servicios definidos en Kubernetes. Adicionalmente, se asegura de que los sistemas de apoyo de servicios para balanceadores de carga en la nube se encuentren actualizados.
2. Kubelet
El controlador de nodos incluye la funcionalidad del kubelet que es dependiente de la nube. Previa a la introducción de CCM, el kubelet era responsable de inicializar un nodo con detalles específicos al proveedor como direcciones IP, etiquetas de región/zona y tipo de instancia. La introduccion de CCM transfiere esta inicialización del kubelet al CCM.
En este nuevo modelo, el kubelet inicializa un nodo sin información especifica del proveedor de servicios. Sin embargo, añade un taint al nodo recién creado de forma que este no esté disponible para el planificador hasta que el CCM completa el nodo con la información específica del proveedor. Sólo entonces elimina el taint y el nodo se vuelve accesible.
Mecanismo de Plugins (extensiones)
El Cloud Controller Manager utiliza interfaces Go(lang), lo que permite que implementaciones de cualquier proveedor de servicios sean conectadas. Específicamente, utiliza el CloudProvider Interface definido aquí.
La implementación de los cuatro controladores referenciados en este documento, algunas estructuras de inicialización junto con el interface CloudProvider, permanecerán como parte del núcleo de Kubernetes.
Para más información sobre el desarrollo de extensiones/plugins, consultar Desarrollo del CCM.
Autorización
Esta sección divide el nivel de acceso requerido por varios objetos API para que el CCM pueda llevar acabo sus operaciones.
Controlador de Nodos
El controlador de nodos sólo opera con objetos Nodo. Necesita de acceso total para obtener, listar, crear, actualizar, arreglar, monitorizar y borrar objetos Nodo.
v1/Node:
Get
List
Create
Update
Patch
Watch
Delete
Controlador de Rutas
El controlador de rutas permanece a la escucha de eventos de creación de nodos y configura sus rutas. Necesita acceso a los objetos Nodo.
v1/Node:
Get
Controlador de Servicios
El controlador de servicios permanece a la escucha de eventos de creación, actualización y borrado de objetos Servicio, y se encarga de configurar los endpoints para dichos servicios.
Para acceder a los objetos Servicio, necesita permisos para listar y monitorizar. Para el mantenimiento de servicios necesita permisos para parchear y actualizar.
Para configurar endpoints para los servicios necesita permisos para crear, listar, obtener, monitorizar y actualizar.
v1/Service:
List
Get
Watch
Patch
Update
Otros
La implementación del núcleo de CCM requiere acceso para crear eventos, y para asegurar la seguridad de operaciones; necesita acceso para crear ServiceAccounts.
v1/Event:
Create
Patch
Update
v1/ServiceAccount:
Create
El RBAC ClusterRole para CCM se muestra a continuación:
Instrucciones para configurar y ejecutar el CCM pueden encontrarse aquí.
3.3 - Contenedores
3.3.1 - RuntimeClass
FEATURE STATE:Kubernetes v1.20 [stable]
Esta página describe el recurso RuntimeClass y el mecanismo de selección del
motor de ejecución.
RuntimeClass es una característica que permite seleccionar la configuración del
motor de ejecución para los contenedores. La configuración del motor de ejecución para
los contenedores se utiliza para ejecutar los contenedores de un Pod.
Motivación
Se puede seleccionar un RuntimeClass diferente entre diferentes Pods para
proporcionar equilibrio entre rendimiento y seguridad. Por ejemplo, si parte de
la carga de trabajo requiere un alto nivel de garantía de seguridad, se podrían
planificar esos Pods para ejecutarse en un motor de ejecución que use
virtualización de hardware. Así se beneficiaría con un mayor aislamiento del motor
de ejecución alternativo, con el coste de alguna sobrecarga adicional.
También se puede utilizar el RuntimeClass para ejecutar distintos Pods con el
mismo motor de ejecución pero con distintos parámetros.
Configuración
Configurar la implementación del CRI en los nodos (depende del motor de
ejecución)
Crear los recursos RuntimeClass correspondientes.
1. Configurar la implementación del CRI en los nodos
La configuración disponible utilizando RuntimeClass dependen de la
implementación de la Interfaz del Motor de ejecución de Containers (CRI). Véase
la sección Configuración del CRI para más
información sobre cómo configurar la implementación del CRI.
Nota: RuntimeClass por defecto asume una configuración de nodos homogénea para todo el
clúster (lo que significa que todos los nodos están configurados de la misma
forma para el motor de ejecución de los contenedores). Para soportar configuraciones
heterogéneas de nodos, véase Planificación más abajo.
Las configuraciones tienen un nombre de handler (manipulador) correspondiente, referenciado
por la RuntimeClass. El handler debe ser una etiqueta DNS 1123 válida
(alfanumérico + caracter -).
2. Crear los recursos RuntimeClass correspondientes.
Cada configuración establecida en el paso 1 tiene un nombre de handler, que
identifica a dicha configuración. Para cada handler, hay que crear un objeto
RuntimeClass correspondiente.
Actualmente el recurso RuntimeClass sólo tiene dos campos significativos: el
nombre del RuntimeClass (metadata.name) y el handler. La
definición del objeto se parece a ésta:
apiVersion:node.k8s.io/v1 # La RuntimeClass se define en el grupo node.k8s.iokind:RuntimeClassmetadata:name:myclass # Nombre por el que se referenciará la RuntimeClass# no contiene espacio de nombreshandler:myconfiguration # El nombre de la configuración CRI correspondiente
Nota: Se recomienda que las operaciones de escritura de la RuntimeClass
(creación/modificación/parcheo/elimiación) se restrinjan al administrador del
clúster. Habitualmente es el valor por defecto. Véase Visión general de la
Autorización para más
detalles.
Uso
Una vez se han configurado las RuntimeClasses para el clúster, el utilizarlas es
muy sencillo. Solo se especifica un runtimeClassName en la especificación del Pod.
Por ejemplo:
Así se informa a Kubelet del nombre de la RuntimeClass a utilizar para
este pod. Si dicha RuntimeClass no existe, o el CRI no puede ejecutar el
handler correspondiente, el pod entrará en la
fase final Failed.
Se puede buscar por el correspondiente
evento
con el mensaje de error.
Si no se especifica ninguna runtimeClassName, se usará el RuntimeHandler por
defecto, lo que equivale al comportamiento cuando la opción RuntimeClass está
deshabilitada.
Configuración del CRI
Para más detalles sobre cómo configurar los motores de ejecución del CRI, véase
instalación del CRI.
dockershim
El CRI dockershim incorporado por Kubernetes no soporta manejadores del motor de
ejecución.
Los handlers del motor de ejecución se configuran mediante la configuración
de containerd en /etc/containerd/config.toml. Los handlers válidos se
configuran en la sección de motores de ejecución:
Los handlers del motor de ejecución se configuran a través de la
configuración del CRI-O en /etc/crio/crio.conf. Los manejadores válidos se
configuran en la tabla
crio.runtime
Especificando el campo scheduling en una RuntimeClass se pueden establecer
restricciones para asegurar que los Pods ejecutándose con dicha RuntimeClass se
planifican en los nodos que la soportan.
Para asegurar que los pods sean asignados en nodos que soportan una RuntimeClass
determinada, ese conjunto de nodos debe tener una etiqueta común que se
selecciona en el campo runtimeclass.scheduling.nodeSelector. El nodeSelector
de la RuntimeClass se combina con el nodeSelector del pod durante la admisión,
haciéndose efectiva la intersección del conjunto de nodos seleccionados por
ambos. Si hay conflicto, el pod se rechazará.
Si los nodos soportados se marcan para evitar que los pods con otra RuntimeClass
se ejecuten en el nodo, se pueden añadir tolerations al RuntimeClass. Igual
que con el nodeSelector, las tolerancias se mezclan con las tolerancias del
pod durante la admisión, haciéndose efectiva la unión del conjunto de nodos
tolerados por ambos.
Para saber más sobre configurar el selector de nodos y las tolerancias, véase
Asignando Pods a Nodos.
Sobrecarga del Pod
FEATURE STATE:Kubernetes v1.18 [beta]
Se pueden especificar recursos de sobrecarga adicional que se asocian a los
Pods que estén ejecutándose. Declarar la sobrecarga permite al clúster (incluido
el planificador) contabilizarlo al tomar decisiones sobre los Pods y los
recursos. Para utilizar la sobrecarga de pods, se debe haber habilitado la
feature gate
PodOverhead (lo está por defecto).
La sobrecarga de pods se define en la RuntimeClass a través del los campos de
overhead. Con estos campos se puede especificar la sobrecarga de los pods en
ejecución que utilizan esta RuntimeClass para asegurar que estas sobrecargas se
cuentan en Kubernetes.
Esta página explica los recursos disponibles para Containers dentro del entorno de un Container.
Entorno del Container
El entorno de los Containers de Kubernetes, añade múltiples recursos importantes a los Containers:
Un sistema de ficheros que es la combinación de una imagen y uno o más volúmenes.
Información sobre el propio Container.
Información sobre otros objetos en el clúster.
Información del Container
El hostname de un Container es el nombre del Pod donde el Container está funcionando.
Está disponible a través del comando hostname o con la función gethostname de la libc.
El nombre del Pod y el namespace están disponibles como variables de entorno a través de la
downward API.
Las variables de entorno definidas por el usuario en la definición del Pod están también disponibles en el Container,
así como cualquier variable de entorno definida de forma estática en la imagen de Docker.
Información del Cluster
Una lista de todos los servicios que se ejecutaban cuando se creó el Container está disponible a través de variables de entorno.
La sintaxis de estas variables de entorno coincide con la de los links de Docker.
Para un servicio llamado foo que mapea un Container llamado bar,
las siguientes variables de entorno estan definidas:
FOO_SERVICE_HOST=<El host donde está funcionando el servicio>
FOO_SERVICE_PORT=<El puerto dónde está funcionando el servicio>
Los servicios tienen direcciones IP dedicadas y están disponibles para el Container a través de DNS,
si el complemento para DNS está habilitado.
Siguientes pasos
Más información sobre cómo ejecutar código en respuesta a los cambios de etapa durante ciclo de vida de un contenedor la puedes encontrar en Container lifecycle hooks.
Esta página describe como los contenedores gestionados por kubelet pueden utilizar el framework Container lifecycle hook (hook del ciclo de vida del contenedor)
para ejecutar código disparado por eventos durante la gestión de su ciclo de vida (lifecycle).
Introducción
De manera análoga a muchos frameworks de lenguajes de programación que tienen componentes hooks de lifecycle, como Angular,
Kubernetes también proporciona esta funcionalidad para los contenedores.
Los hooks permiten a los contenedores conocer los eventos en su gestión de ciclo de vida
y ejecutar el código implementado en un controlador cuando el hook de ciclo de vida correspondiente es ejecutado.
Hooks de contenedores
Hay dos hooks expuestos en los contenedores:
PostStart
Este hook se ejecuta inmediatamente después de crear un contenedor.
Sin embargo, no es posible garantizar que el hook se ejecute antes del ENTRYPOINT del contenedor.
No se le pasa ningún parámetro.
PreStop
Este hook se llama inmediatamente antes de que se finalice un contenedor debido a una solicitud de API o evento de gestión como un fallo liveness, o contención de recursos entre otros. Una llamada al hook de Prestop falla si el contenedor ya está en estado terminated (finalizado) o completed (completado).
Es bloqueante, lo que significa que es sincrónico,
por lo que debe completarse antes de que la llamada para eliminar el contenedor pueda ser enviada.
No se le pasa ningún parámetro.
Puedes encontrar información más detallada sobre el comportamiento de finalización de un contenedor
Finalización de Pods.
Implementación de controladores de hooks
Los contenedores pueden acceder a un hook implementando y registrado en un controlador de este hook.
Hay dos tipos de controladores de hooks que se pueden implementar para los contenedores:
Exec: ejecuta un comando específico, como pre-stop.sh, dentro de cgroups y namespaces del contenedor.
Los recursos consumidos por el comando serán tomados en cuenta para el contenedor.
HTTP: ejecuta una petición HTTP contra un endpoint específico dentro del contenedor.
Ejecución de controladores de hooks
Cuando se llama un hook de gestión de ciclo de vida de un contenedor,
el sistema de gestión de Kubernetes ejecuta el controlador en el contenedor registrado para este hook.
Las llamadas al controlador de hooks son síncronas dentro del contexto del Pod que contiene el contenedor.
Esto significa que para un hook PostStart,
el ENTRYPOINT del contenedor y el hook se disparan de forma asíncrona.
Sin embargo, si el hook tarda demasiado en ejecutarse o se cuelga,
el contenedor no puede alcanzar el estado de running (en ejecución).
El comportamiento es similar para un hook PreStop.
Si el hook se cuelga durante la ejecución,
la fase del Pod permanece en un estado de terminating (finalizando) y se cancela después del terminationGracePeriodSeconds (finalización después del periodo de gracia) del pod en cuestión.
Si un hook PostStart o PreStop falla, se mata el contenedor.
Los usuarios deben hacer que sus controladores de hooks sean lo más livianos posible.
Hay casos, sin embargo, que los comandos de larga ejecución tienen sentido,
como cuando se guarda el estado antes de detener un contenedor.
Garantías de entrega de hooks
La entrega de un hook está destinada a ser enviada al menos una vez,
lo que significa que un hook puede ser llamado varias veces para cualquier evento dado,
tanto para PostStart como para PreStop.
Depende de la implementación del hook manejar esto correctamente.
En general, solo se realizan entregas individuales.
Si, por ejemplo, un receptor hook HTTP está inactivo y no puede recibir tráfico,
no hay ningún reintento.
Sin embargo, en algunos casos puede ocurrir una doble entrega.
Por ejemplo, si un Kubelet se reinicia durante la ejecución de envio de un hook,
el hook puede volver a enviarse después de que el kubelet se levante.
Depurando controladores de hooks
Los logs de un controlador de hooks no son expuestos en los eventos del Pod.
Si un controlador falla por alguna razón, emite un evento.
Para PostStart, es el evento FailedPostStartHook,
y para PreStop, el evento FailedPreStopHook.
Puedes ver que eventos están en ejecución con el comando kubectl describe pod <pod_name>.
El siguiente ejemplo muestra los eventos en ejecución a través del comando anterior:
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {default-scheduler } Normal Scheduled Successfully assigned test-1730497541-cq1d2 to gke-test-cluster-default-pool-a07e5d30-siqd
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulling pulling image "test:1.0"
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Created Created container with docker id 5c6a256a2567; Security:[seccomp=unconfined]
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Pulled Successfully pulled image "test:1.0"
1m 1m 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Started Started container with docker id 5c6a256a2567
38s 38s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 5c6a256a2567: PostStart handler: Error executing in Docker Container: 1
37s 37s 1 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Normal Killing Killing container with docker id 8df9fdfd7054: PostStart handler: Error executing in Docker Container: 1
38s 37s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} Warning FailedSync Error syncing pod, skipping: failed to "StartContainer" for "main" with RunContainerError: "PostStart handler: Error executing in Docker Container: 1"
1m 22s 2 {kubelet gke-test-cluster-default-pool-a07e5d30-siqd} spec.containers{main} Warning FailedPostStartHook
Los Pods son las unidades de computación desplegables más pequeñas que se pueden crear y gestionar en Kubernetes.
¿Qué és un Pod?
Un Pod (como en una vaina de ballenas o vaina de guisantes) es un grupo de uno o más contenedores (como contenedores Docker), con almacenamiento/red compartidos, y unas especificaciones de cómo ejecutar los contenedores. Los contenidos de un Pod son siempre coubicados, coprogramados y ejecutados en un contexto compartido. Un Pod modela un "host lógico" específico de la aplicación: contiene uno o más contenedores de aplicaciones relativamente entrelazados. Antes de la llegada de los contenedores, ejecutarse en la misma máquina física o virtual significaba ser ejecutado en el mismo host lógico.
Mientras que Kubernetes soporta más runtimes de contenedores a parte de Docker, este último es el más conocido y ayuda a describir Pods en términos de Docker.
El contexto compartido de un Pod es un conjunto de namespaces de Linux, cgroups y, potencialmente, otras facetas de aislamiento, las mismas cosas que aíslan un contenedor Docker. Dentro del contexto de un Pod, las aplicaciones individuales pueden tener más subaislamientos aplicados.
Los contenedores dentro de un Pod comparten dirección IP y puerto, y pueden encontrarse a través de localhost. También pueden comunicarse entre sí mediante comunicaciones estándar entre procesos, como semáforos de SystemV o la memoria compartida POSIX. Los contenedores en diferentes Pods tienen direcciones IP distintas y no pueden comunicarse por IPC sin configuración especial.
Estos contenedores normalmente se comunican entre sí a través de las direcciones IP del Pod.
Las aplicaciones dentro de un Pod también tienen acceso a volúmenes compartidos, que se definen como parte de un Pod y están disponibles para ser montados en el sistema de archivos de cada aplicación.
En términos de Docker, un Pod se modela como un grupo de contenedores de Docker con namespaces y volúmenes de sistemas de archivos compartidos.
Al igual que los contenedores de aplicaciones individuales, los Pods se consideran entidades relativamente efímeras (en lugar de duraderas). Como se explica en ciclo de vida del pod, los Pods se crean, se les asigna un identificador único (UID) y se planifican en nodos donde permanecen hasta su finalización (según la política de reinicio) o supresión. Si un nodo muere, los Pods programados para ese nodo se programan para su eliminación después de un período de tiempo de espera. Un Pod dado (definido por su UID) no se "replanifica" a un nuevo nodo; en su lugar, puede reemplazarse por un Pod idéntico, con incluso el mismo nombre si lo desea, pero con un nuevo UID (consulte controlador de replicación para obtener más detalles).
Cuando se dice que algo tiene la misma vida útil que un Pod, como un volumen, significa que existe mientras exista ese Pod (con ese UID). Si ese Pod se elimina por cualquier motivo, incluso si se crea un reemplazo idéntico, el recurso relacionado (por ejemplo, el volumen) también se destruye y se crea de nuevo.
Un Pod de múltiples contenedores que contiene un extractor de archivos y un servidor web que utiliza un volumen persistente para el almacenamiento compartido entre los contenedores.
Motivación para los Pods
Gestión
Los Pods son un modelo del patrón de múltiples procesos de cooperación que forman una unidad de servicio cohesiva. Simplifican la implementación y la administración de las aplicaciones proporcionando una abstracción de mayor nivel que el conjunto de las aplicaciones que lo constituyen. Los Pods sirven como unidad de despliegue, escalado horizontal y replicación. La colocación (coprogramación), el destino compartido (por ejemplo, la finalización), la replicación coordinada, el uso compartido de recursos y la gestión de dependencias se controlan automáticamente para los contenedores en un Pod.
Recursos compartidos y comunicación
Los Pods permiten el intercambio de datos y la comunicación entre los contenedores que lo constituyen.
Todas las aplicaciones en un Pod utilizan el mismo namespace de red (la misma IP y puerto) y, por lo tanto, pueden "encontrarse" entre sí y comunicarse utilizando localhost.
Debido a esto, las aplicaciones en un Pod deben coordinar su uso de puertos. Cada Pod tiene una dirección IP en un espacio de red compartido que tiene comunicación completa con otros servidores físicos y Pods a través de la red.
Los contenedores dentro del Pod ven que el hostname del sistema es el mismo que el nombre configurado para el Pod. Hay más información sobre esto en la sección networking.
Además de definir los contenedores de aplicaciones que se ejecutan en el Pod, el Pod especifica un conjunto de volúmenes de almacenamiento compartido. Los volúmenes permiten que los datos sobrevivan a reinicios de contenedores y se compartan entre las aplicaciones dentro del Pod.
Usos de Pods
Los Pods pueden ser usados para alojar pilas de aplicaciones integradas (por ejemplo, LAMP), pero su objetivo principal es apoyar los programas de ayuda coubicados y coadministrados, como:
sistemas de gestión de contenido, loaders de datos y archivos, gestores de caché locales, etc.
copia de seguridad de registro y punto de control, compresión, rotación, captura de imágenes, etc.
observadores de cambio de datos, adaptadores de registro y monitoreo, publicadores de eventos, etc.
proxies, bridges y adaptadores.
controladores, configuradores y actualizadores.
Los Pods individuales no están diseñados para ejecutar varias instancias de la misma aplicación, en general.
¿Por qué simplemente no ejecutar múltiples programas en un solo contenedor de Docker?
Transparencia. Hacer visibles los contenedores dentro del Pod
a la infraestructura permite que esta brinde servicios, como gestión de procesos
y monitoreo de recursos, a los contenedores, facilitando una
serie de comodidades a los usuarios.
Desacople de dependencias de software. Los contenedores individuales pueden ser
versionados, reconstruidos y redistribuidos independientemente. Kubernetes podría incluso apoyar
actualizaciones en vivo de contenedores individuales en un futuro.
Facilidad de uso. Los usuarios no necesitan ejecutar sus propios administradores de procesos,
para propagación de señales, códigos de salida, etc.
Eficiencia. Debido a que la infraestructura asume más responsabilidad,
los contenedores pueden ser más livianos.
¿Por qué no admitir la planificación conjunta de contenedores por afinidad?
Ese enfoque proporcionaría la ubicación conjunta, pero no la mayor parte de
beneficios de los Pods, como compartir recursos, IPC, compartir el destino garantizado y
gestión simplificada.
Durabilidad de pods (o su ausencia)
Los Pods no están destinados a ser tratados como entidades duraderas. No sobrevivirán a errores de planificación, caídas de nodo u otros desalojos, ya sea por falta de recursos o en el caso de mantenimiento de nodos.
En general, los usuarios no deberían necesitar crear Pods directamente, deberían
usar siempre controladores incluso para Pods individuales, como por ejemplo, los
Deployments.
Los controladores proporcionan autorecuperación con un alcance de clúster, así como replicación
y gestión de despliegue.
Otros controladores como los StatefulSet
pueden tambien proporcionar soporte para Pods que necesiten persistir el estado.
El uso de API colectivas como la principal primitiva de cara al usuario es relativamente común entre los sistemas de planificación de clúster, incluyendo Borg, Marathon, Aurora, y Tupperware.
El Pod se expone como primitiva para facilitar:
planificación y capacidad de conexión del controlador
soporte para operaciones a nivel de Pod sin la necesidad de "proxy" a través de las API del controlador
desacople de la vida útil del Pod de la vida útil del controlador, como para el arranque
desacople de controladores y servicios, el endpoint del controlador solo mira Pods
composición limpia de funcionalidad a nivel de Kubelet con funcionalidad a nivel de clúster, Kubelet es efectivamente el "controlador de Pod"
aplicaciones en alta disponibilidad, que esperan que los Pods sean reemplazados antes de su finalización y ciertamente antes de su eliminación, como en el caso de desalojos planificados o descarga previa de imágenes.
Finalización de Pods
Debido a que los Pods representan procesos en ejecución en los nodos del clúster, es importante permitir que esos procesos finalicen de forma correcta cuando ya no se necesiten (en lugar de ser detenidos bruscamente con una señal de KILL). Los usuarios deben poder solicitar la eliminación y saber cuándo finalizan los procesos, pero también deben poder asegurarse de que las eliminaciones finalmente se completen. Cuando un usuario solicita la eliminación de un Pod, el sistema registra el período de gracia previsto antes de que el Pod pueda ser eliminado de forma forzada, y se envía una señal TERM al proceso principal en cada contenedor. Una vez que el período de gracia ha expirado, la señal KILL se envía a esos procesos y el Pod se elimina del servidor API. Si se reinicia Kubelet o el administrador de contenedores mientras se espera que finalicen los procesos, la terminación se volverá a intentar con el período de gracia completo.
Un ejemplo del ciclo de terminación de un Pod:
El usuario envía un comando para eliminar Pod, con un período de gracia predeterminado (30s)
El Pod en el servidor API se actualiza con el tiempo a partir del cual el Pod se considera "muerto" junto con el período de gracia.
El Pod aparece como "Terminando" cuando aparece en los comandos del cliente
(simultáneo con 3) Cuando el Kubelet ve que un Pod se ha marcado como terminado porque se ha configurado el tiempo en 2, comienza el proceso de apagado del Pod.
Si uno de los contenedores del Pod ha definido un preStop hook, se invoca dentro del contenedor. Si el hook preStop todavía se está ejecutando después de que expire el período de gracia, el paso 2 se invoca con un pequeño período de gracia extendido (2s).
El contenedor recibe la señal TERM. Tenga en cuenta que no todos los contenedores en el Pod recibirán la señal TERM al mismo tiempo y cada uno puede requerir un hook preStop si el orden en el que se cierra es importante.
(simultáneo con 3) Pod se elimina de la lista de endponts del servicio, y ya no se considera parte del conjunto de Pods en ejecución para controladores de replicación. Los Pods que se apagan lentamente no pueden continuar sirviendo el tráfico ya que los balanceadores de carga (como el proxy de servicio) los eliminan de sus rotaciones.
Cuando expira el período de gracia, todos los procesos que todavía se ejecutan en el Pod se eliminan con SIGKILL.
El Kubelet terminará de eliminar el Pod en el servidor API configurando el período de gracia 0 (eliminación inmediata). El Pod desaparece de la API y ya no es visible desde el cliente.
Por defecto, todas las eliminaciones se realizan correctamente en 30 segundos. El comando kubectl delete admite la opción--grace-period = <seconds>que permite al usuario anular el valor predeterminado y especificar su propio valor. El valor 0forzar eliminación del Pod.
Debe especificar un indicador adicional --force junto con --grace-period = 0 para realizar eliminaciones forzadas.
Forzar destrucción de Pods
La eliminación forzada de un Pod se define como la eliminación de un Pod del estado del clúster y etcd inmediatamente. Cuando se realiza una eliminación forzada, el apiserver no espera la confirmación del kubelet de que el Pod ha finalizado en el nodo en el que se estaba ejecutando. Elimina el Pod en la API inmediatamente para que se pueda crear un nuevo Pod con el mismo nombre. En el nodo, los Pods que están configurados para terminar de inmediato recibirán un pequeño período de gracia antes de ser forzadas a matar.
Estas eliminaciones pueden ser potencialmente peligrosas para algunos Pods y deben realizarse con precaución. En el caso de Pods de StatefulSets, consulte la documentación de la tarea para eliminando Pods de un StatefulSet.
Modo privilegiado para Pods
Cualquier contenedor en un Pod puede habilitar el modo privilegiado, utilizando el indicador privilegiado en el contexto de seguridad de la especificación del contenedor. Esto es útil para contenedores que desean usar capacidades de Linux como manipular la pila de red y acceder a dispositivos. Los procesos dentro del contenedor obtienen casi los mismos privilegios que están disponibles para los procesos fuera de un contenedor. Con el modo privilegiado, debería ser más fácil escribir complementos de red y volumen como Pods separados que no necesitan compilarse en el kubelet.
Nota: El runtime de contenedores debe admitir el concepto de un contenedor privilegiado para que esta configuración sea relevante.
API
Pod es un recurso de nivel superior en la API REST de Kubernetes.
La definición de objeto de API Pod
describe el objeto en detalle.
3.4.1.2 - Pod Preset
FEATURE STATE:Kubernetes v1.6 [alpha]
Esta página provee una descripción general de los PodPresets, los cuales son
los objetos que se utilizan para inyectar cierta información en los Pods en
el momento de la creación. Esta información puede incluir secretos, volúmenes,
montajes de volúmenes y variables de entorno.
Entendiendo los Pod Presets
Un PodPreset es un recurso de la API utilizado para poder inyectar requerimientos
adicionales de tiempo de ejecución en un Pod en el momento de la creación.
Se utilizan los selectores de etiquetas
para especificar los Pods a los que se aplica un PodPreset determinado.
El uso de un PodPreset permite a los autores de plantillas de Pods no tener que proporcionar
explícitamente toda la información de cada Pod. De esta manera, los autores de plantillas de
Pods que consuman un determinado servicio no tendrán que conocer todos los detalles de ese servicio.
Habilitando un PodPreset en su clúster
Con el fin de utilizar los Pod Presets en un clúster debe asegurarse de lo siguiente:
Que se ha configurado el tipo de API settings.k8s.io/v1alpha1/podpreset. Esto se puede hacer,
por ejemplo, incluyendo settings.k8s.io/v1alpha1=true como valor de la opción --runtime-config
en el servidor API. En minikube se debe añadir el flag
--extra-config=apiserver.runtime-config=settings.k8s.io/v1alpha1=true cuando el clúster
se está iniciando.
Que se ha habilitado el controlador de admisión PodPreset. Una forma de hacer esto es incluir
PodPreset como valor de la opción --enable-admission-plugins especificada
para el servidor API. En minikube se debe añadir el flag
Kubernetes provee un controlador de admisión (PodPreset) que, cuando está habilitado,
aplica los Pod Presets a las peticiones de creación de Pods entrantes.
Cuando se realiza una solicitud de creación de Pods, el sistema hace lo siguiente:
Obtiene todos los PodPresets disponibles para usar.
Verifica si los selectores de etiquetas de cualquier PodPreset correspondan
con las etiquetas del Pod que se está creando.
Intenta fusionar los diversos recursos definidos por el PodPreset dentro del Pod
que se está creando.
Si se llegase a producir un error al intentar fusionar los recursos dentro del Pod,
lanza un evento que documente este error, luego crea el Pod sin ningún recurso que se
inyecte desde el PodPreset.
Escribe una nota descriptiva de la especificación de Pod modificada resultante para
indicar que ha sido modificada por un PodPreset. La nota descriptiva presenta la forma
podpreset.admission.kubernetes.io/podpreset-<pod-preset name>: "<resource version>".
Cada Pod puede ser correspondido por cero o más Pod Presets; y cada PodPreset puede ser
aplicado a cero o más Pods. Cuando se aplica un PodPreset a una o más Pods, Kubernetes
modifica la especificación del Pod. Para los cambios a env, envFrom, y volumeMounts,
Kubernetes modifica la especificación del Container para todos los Containers en el Pod;
para los cambios a volumes, Kubernetes modifica la especificación del Pod.
Nota:
Un Pod Preset es capaz de modificar los siguientes campos en las especificaciones de un Pod
en caso de ser necesario:
El campo .spec.containers.
El campo .spec.initContainers
Deshabilitar un Pod Preset para un Pod específico
Puede haber casos en los que se desee que un Pod no se vea alterado por ninguna posible
modificación del Pod Preset. En estos casos, se puede añadir una observación en el Pod
.spec de la siguiente forma: podpreset.admission.kubernetes.io/exclude: "true".
Esta página proporciona una descripción general de los Containers efímeros: un tipo especial de Container
que se ejecuta temporalmente en un Pod ya existente para cumplir las
acciones iniciadas por el usuario, como por ejemplo, la solución de problemas. En vez de ser utilizadas para
crear aplicaciones, los Containers efímeros se utilizan para examinar los servicios.
Advertencia: Los Containers efímeros se encuentran en una fase alfa inicial y no son aptos para clústers
de producción. Es de esperar que esta característica no funcione en algunas situaciones, por
ejemplo, al seleccionar los Namespaces de un Container. De acuerdo con la Política de
Deprecación de Kubernetes, esta característica
alfa puede variar significativamente en el futuro o ser eliminada por completo.
Entendiendo los Containers efímeros
Pods son el componente fundamental de las
aplicaciones de Kubernetes. Puesto que los Pods están previstos para ser desechables
y reemplazables, no se puede añadir un Container a un Pod una vez creado. Sin embargo, por lo
general se eliminan y se reemplazan los Pods de manera controlada utilizando
Deployments.
En ocasiones es necesario examinar el estado de un Pod existente, como por ejemplo,
para poder solucionar un error difícil de reproducir. Puede ejecutar en estos casos
un Container efímero en un Pod ya existente para examinar su estado y para ejecutar
comandos de manera arbitraria.
Qué es un Container efímero?
Los Containers efímeros se diferencian de otros Containers en que no garantizan ni los
recursos ni la ejecución, y en que nunca se reiniciarán automáticamente, de modo que no
son aptos para la construcción de aplicaciones. Los Containers efímeros se describen
usando la misma ContainerSpec que los Containers regulares, aunque muchos campos son
incompatibles y no están habilitados para los Containers efímeros.
Los Containers efímeros no pueden tener puertos, por lo que campos como ports,
livenessProbe, readinessProbe no están habilitados.
Las asignaciones de recursos del Pod son inmutables, por lo que no esta habilitado
configurar "resources".
Para obtener una lista completa de los campos habilitados, consulte la documentación
de referencia [EphemeralContainer] (/docs/reference/generated/kubernetes-api/v1.20/#ephemeralcontainer-v1-core).
En vez de añadirlos de forma directa al pod.spec, los Containers efímeros se crean usando un
controlador especial de la API, ephemeralcontainers, por lo tanto no es posible añadir un
Container efímero utilizando kubectl edit.
Al igual en el caso de los Containers regulares, no se puede modificar o remover un Container
efímero después de haberlo agregado a un Pod.
Casos de uso para los Containers efímeros
Los Containers efímeros resultan útiles para la solución interactiva de incidencias cuando
kubectl exec es insuficiente tanto porque un container se ha caído, como porque la imagen de un
Container no incluye las utilidades de depuración.
En particular, las imágenes distroless
le permiten desplegar imágenes de Containers mínimos que disminuyen la superficie de ataque
y la exposición a errores y vulnerabilidades. Ya que las imágenes distroless no contienen un
shell ni ninguna utilidad de depuración, resulta difícil solucionar los problemas de las imágenes
distroless usando solamente kubectl exec.
Cuando utilice Containers efímeros, es conveniente habilitar el proceso Namespace de uso
compartido para poder ver los
procesos en otros containers.
Ejemplos
Nota: Los ejemplos de esta sección requieren que los EphemeralContainersfeature
gate estén habilitados
y que tanto el cliente como el servidor de Kubernetes tengan la version v1.16 o posterior.
En los ejemplos de esta sección muestran la forma en que los Containers efímeros se
presentan en la API. Los usuarios normalmente usarían un plugin kubectl para la solución
de problemas que automatizaría estos pasos.
Los Containers efímeros son creados utilizando el subrecurso ephemeralcontainers del Pod,
que puede ser visto utilizando kubectl --raw. En primer lugar describa el Container
efímero a añadir como una lista de EphemeralContainers:
Se puede conectar al nuevo Container efímero usando kubectl attach:
kubectl attach -it example-pod -c debugger
Si el proceso Namespace de uso compartido está habilitado, se pueden visualizar los procesos de todos los Containers de ese Pod.
Por ejemplo, después de haber conectado, ejecute ps en el debugger del container:
ps auxww
La respuesta es semejante a:
PID USER TIME COMMAND
1 root 0:00 /pause
6 root 0:00 nginx: master process nginx -g daemon off;
11 101 0:00 nginx: worker process
12 101 0:00 nginx: worker process
13 101 0:00 nginx: worker process
14 101 0:00 nginx: worker process
15 101 0:00 nginx: worker process
16 101 0:00 nginx: worker process
17 101 0:00 nginx: worker process
18 101 0:00 nginx: worker process
19 root 0:00 /pause
24 root 0:00 sh
29 root 0:00 ps auxww
3.4.2 - Controladores
3.4.2.1 - ReplicaSet
El objeto de un ReplicaSet es el de mantener un conjunto estable de réplicas de Pods ejecutándose
en todo momento. Así, se usa en numerosas ocasiones para garantizar la disponibilidad de un
número específico de Pods idénticos.
Cómo funciona un ReplicaSet
Un ReplicaSet se define con campos, incluyendo un selector que indica cómo identificar a los Pods que puede adquirir,
un número de réplicas indicando cuántos Pods debería gestionar, y una plantilla pod especificando los datos de los nuevos Pods
que debería crear para conseguir el número de réplicas esperado. Un ReplicaSet alcanza entonces su propósito
mediante la creación y eliminación de los Pods que sea necesario para alcanzar el número esperado.
Cuando un ReplicaSet necesita crear nuevos Pods, utiliza su plantilla Pod.
El enlace que un ReplicaSet tiene hacia sus Pods es a través del campo del Pod denominado metadata.ownerReferences,
el cual indica qué recurso es el propietario del objeto actual. Todos los Pods adquiridos por un ReplicaSet tienen su propia
información de identificación del ReplicaSet en su campo ownerReferences. Y es a través de este enlace
cómo el ReplicaSet conoce el estado de los Pods que está gestionando y actúa en consecuencia.
Un ReplicaSet identifica los nuevos Pods a adquirir usando su selector. Si hay un Pod que no tiene OwnerReference
o donde OwnerReference no es un controlador, pero coincide con el selector del ReplicaSet,
este será inmediatamente adquirido por dicho ReplicaSet.
Cuándo usar un ReplicaSet
Un ReplicaSet garantiza que un número específico de réplicas de un pod se está ejecutando en todo momento.
Sin embargo, un Deployment es un concepto de más alto nivel que gestiona ReplicaSets y
proporciona actualizaciones de forma declarativa de los Pods junto con muchas otras características útiles.
Por lo tanto, se recomienda el uso de Deployments en vez del uso directo de ReplicaSets, a no ser
que se necesite una orquestración personalizada de actualización o no se necesite las actualizaciones en absoluto.
En realidad, esto quiere decir que puede que nunca necesites manipular los objetos ReplicaSet:
en vez de ello, usa un Deployment, y define tu aplicación en la sección spec.
apiVersion:apps/v1kind:ReplicaSetmetadata:name:frontendlabels:app:guestbooktier:frontendspec:# modifica las réplicas según tu caso de usoreplicas:3selector:matchLabels:tier:frontendtemplate:metadata:labels:tier:frontendspec:containers:- name:php-redisimage:gcr.io/google_samples/gb-frontend:v3
Si guardas este manifiesto en un archivo llamado frontend.yaml y lo lanzas en un clúster de Kubernetes,
se creará el ReplicaSet definido y los Pods que maneja.
También puedes comprobar el estado del replicaset:
kubectl describe rs/frontend
Y verás una salida parecida a la siguiente:
Name: frontend
Namespace: default
Selector: tier=frontend,tier in (frontend)
Labels: app=guestbook
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=guestbook
tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: 80/TCP
Requests:
cpu: 100m
memory: 100Mi
Environment:
GET_HOSTS_FROM: dns
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1{replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh
1m 1m 1{replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy
1m 1m 1{replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l
Y por último, puedes comprobar los Pods que ha arrancado:
kubectl get Pods
Deberías ver la información de cada Pod similar a:
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
También puedes verificar que la referencia de propietario de dichos pods está puesta al ReplicaSet frontend.
Para ello, obtén el yaml de uno de los Pods ejecutándose:
kubectl get pods frontend-9si5l -o yaml
La salida será parecida a esta, donde la información sobre el ReplicaSet aparece en el campo ownerReferences de los metadatos:
Aunque puedes crear Pods simples sin problemas, se recomienda encarecidamente asegurarse de que dichos Pods no tienen
etiquetas que puedan coincidir con el selector de alguno de tus ReplicaSets.
La razón de esta recomendación es que un ReplicaSet no se limita a poseer los Pods
especificados en su plantilla -- sino que puede adquirir otros Pods como se explicó en secciones anteriores.
Toma el ejemplo anterior del ReplicaSet frontend, y los Pods especificados en el siguiente manifiesto:
Como estos Pods no tienen un Controlador (o cualquier otro objeto) como referencia de propietario
y como además su selector coincide con el del ReplicaSet frontend, este último los terminará adquiriendo de forma inmediata.
Supón que creas los Pods después de que el ReplicaSet frontend haya desplegado los suyos
para satisfacer su requisito de cuenta de réplicas:
Verás que el ReplicaSet ha adquirido dichos Pods y simplemente ha creado tantos nuevos
como necesarios para cumplir con su especificación hasta que el número de
sus nuevos Pods y los originales coincidan con la cuenta deseado. Al obtener los Pods:
kubectl get Pods
Veremos su salida:
NAME READY STATUS RESTARTS AGE
frontend-pxj4r 1/1 Running 0 5s
pod1 1/1 Running 0 13s
pod2 1/1 Running 0 13s
De esta forma, un ReplicaSet puede poseer un conjunto no homogéneo de Pods
Escribir un manifiesto de ReplicaSet
Al igual que con el esto de los objeto de la API de Kubernetes, un ReplicaSet necesita los campos
apiVersion, kind, y metadata. Para los ReplicaSets, el tipo es siempre ReplicaSet.
En la versión 1.9 de Kubernetes, la versión apps/v1 de la API en un tipo ReplicaSet es la versión actual y está habilitada por defecto.
La versión apps/v1beta2 de la API se ha desaprobado.
Consulta las primeras líneas del ejemplo frontend.yaml como guía.
El campo .spec.template es una plantilla pod que es
también necesita obligatoriamente tener etiquetas definidas. En nuestro ejemplo frontend.yaml teníamos una etiqueta: tier: frontend.
Lleva cuidado de que no se entremezcle con los selectores de otros controladores, no sea que traten de adquirir este Pod.
Para el campo de regla de reinicio de la plantilla,
.spec.template.spec.restartPolicy, el único valor permitido es Always, que es el valor predeterminado.
Selector de Pod
El campo .spec.selector es un selector de etiqueta.
Como se explicó anteriormente, estas son las etiquetas que se usan para
identificar los Pods potenciales a adquirir. En nuestro ejemplo frontend.yaml, el selector era:
matchLabels:
tier: frontend
El el ReplicaSet, .spec.template.metadata.labels debe coincidir con spec.selector, o será
rechazado por la API.
Nota: Cuando 2 ReplicaSets especifican el mismo campo .spec.selector, pero los campos
.spec.template.metadata.labels y .spec.template.spec diferentes, cada ReplicaSet
ignora los Pods creados por el otro ReplicaSet.
Réplicas
Puedes configurar cuántos Pods deberían ejecutarse de forma concurrente indicando el campo .spec.replicas.
El ReplicaSet creará/eliminará sus Pods para alcanzar este número.
Si no indicas el valor del campo .spec.replicas, entonces por defecto se inicializa a 1.
Trabajar con ReplicaSets
Eliminar un ReplicaSet y sus Pods
Para eliminar un ReplicaSet y todos sus Pods, utiliza el comando kubectl delete.
El Recolector de basura eliminará automáticamente
todos los Pods subordinados por defecto.
Cuando se usa la API REST o la librería client-go, se debe poner el valor de propagationPolicy a Background o
Foreground en la opción -d.
Por ejemplo:
Se puede eliminar un ReplicaSet sin afectar a ninguno de sus Pods usando el comando kubectl delete con la opción --cascade=false.
Cuando se usa la API REST o la librería client-go, se debe poner propagationPolicy a Orphan.
Por ejemplo:
Una vez que se ha eliminado el original, se puede crear un nuevo ReplicaSet para sustituirlo.
Mientras el viejo y el nuevo .spec.selector sean el mismo, el nuevo adoptará a los viejos Pods.
Sin embargo, no se esforzará en conseguir que los Pods existentes coincidan con una plantilla pod nueva, diferente.
Para actualizar dichos Pods a la nueva especificación de forma controlada,
usa una actualización en línea.
Aislar Pods de un ReplicaSet
Es posible aislar Pods de un ReplicaSet cambiando sus etiquetas. Esta técnica puede usarse
para eliminar Pods de un servicio para poder depurar, recuperar datos, etc. Los Pods
que se eliminar de esta forma serán sustituidos de forma automática (siempre que el
número de réplicas no haya cambiado).
Escalar un ReplicaSet
Se puede aumentar o reducir fácilmente un ReplicaSet simplemente actualizando el campo .spec.replicas.
El controlador del ReplicaSet se asegura de que el número deseado de Pods con un selector
de etiquetas coincidente está disponible y operacional.
ReplicaSet como blanco de un Horizontal Pod Autoscaler
Un ReplicaSet puede también ser el blanco de un
Horizontal Pod Autoscalers (HPA). Esto es,
un ReplicaSet puede auto-escalarse mediante un HPA. Aquí se muestra un ejemplo de HPA dirigido
al ReplicaSet que creamos en el ejemplo anterior.
Si guardas este manifiesto en un archivo hpa-rs.yaml y lo lanzas contra el clúster de Kubernetes,
debería crear el HPA definido que auto-escala el ReplicaSet destino dependiendo del uso
de CPU de los Pods replicados.
Alternativamente, puedes usar el comando kubectl autoscale para conseguir el mismo objetivo
(¡y mucho más fácil!)
kubectl autoscale rs frontend --max=10
Alternativas al ReplicaSet
Deployment (recomendado)
UnDeployment es un objeto que puede poseer ReplicaSets
y actualizar a estos y a sus Pods mediante actualizaciones en línea declarativas en el servidor.
Aunque que los ReplicaSets puede usarse independientemente, hoy en día se usan principalmente a través de los Deployments
como el mecanismo para orquestrar la creación, eliminación y actualización de los Pods.
Cuando usas Deployments no tienes que preocuparte de gestionar los ReplicaSets que crean.
Los Deployments poseen y gestionan sus ReplicaSets.
Por tanto, se recomienda que se use Deployments cuando se quiera ReplicaSets.
Pods simples
A diferencia del caso en que un usuario creaba Pods de forma directa, un ReplicaSet sustituye los Pods que se eliminan
o se terminan por la razón que sea, como en el caso de un fallo de un nodo o
una intervención disruptiva de mantenimiento, como una actualización de kernel.
Por esta razón, se recomienda que se use un ReplicaSet incluso cuando la aplicación
sólo necesita un único Pod. Entiéndelo de forma similar a un proceso supervisor,
donde se supervisa múltiples Pods entre múltiples nodos en vez de procesos individuales
en un único nodo. Un ReplicaSet delega los reinicios del contenedor local a algún agente
del nodo (por ejemplo, Kubelet o Docker).
Job
Usa un Job en vez de un ReplicaSet para
aquellos Pods que se esperan que terminen por ellos mismos (esto es, trabajos por lotes).
DaemonSet
Usa un DaemonSet en vez de un ReplicaSet para aquellos
Pods que proporcionan funcionalidad a nivel de servidor, como monitorización de servidor o
logging de servidor. Estos Pods tienen un ciclo de vida asociado al del servidor mismo:
el Pod necesita ejecutarse en el servidor antes de que los otros Pods comiencen, y es seguro
que terminen cuando el servidor esté listo para ser reiniciado/apagado.
ReplicationController
Los ReplicaSets son los sucesores de los ReplicationControllers.
Los dos sirven al mismo propósito, y se comportan de forma similar, excepto porque un ReplicationController
no soporta los requisitos del selector basado en conjunto, como se describe en la guía de usuario de etiquetas.
Por ello, se prefiere los ReplicaSets a los ReplicationControllers.
3.4.2.2 - ReplicationController
Nota: hoy en día la forma recomendada de configurar la replicación es con un Deployment que configura un ReplicaSet.
Un ReplicationController garantiza que un número determinado de réplicas se estén ejecutando
en todo momento. En otras palabras, un ReplicationController se asegura que un pod o un conjunto homogéneo de pods
siempre esté arriba y disponible.
Cómo Funciona un ReplicationController
Si hay muchos pods, el ReplicationController termina los pods extra. Si hay muy pocos, el
ReplicationController arranca más pods. A difrencia de los pods creados manualmente, los pods mantenidos por un
ReplicationController se sustituyen de forma automática si fallan, se borran, o se terminan.
Por ejemplo, tus pods se re-crean en un nodo durante una intervención disruptiva de mantenimiento como una actualización del kernel.
Por esta razón, deberías usar un ReplicationController incluso cuando tu aplicación sólo necesita
un único pod. Un ReplicationController es parecido a un supervisor de procesos,
pero en vez de supervisar procesos individuales en un único nodo,
el ReplicationController supervisa múltiples pods entre múltiples nodos.
A menudo nos referimos a un ReplicationController de forma abreviada como "rc" o "rcs", así como
atajo en los comandos de kubectl.
Un caso simple es crear un objeto ReplicationController para ejecutar de manera fiable una instancia
de un Pod indefinidamente. Un caso de uso más complejo es ejecutar varias réplicas idénticas
de un servicio replicado, como los servidores web.
Ejecutar un ejemplo de ReplicationController
Esta configuración de un ReplicationController de ejemplo ejecuta tres copias del servidor web nginx.
Comprueba el estado del ReplicationController con este comando:
kubectl describe replicationcontrollers/nginx
Name: nginx
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 0 Running / 3 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- ---- ------ -------
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-qrm3m
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-3ntk0
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-4ok8v
Como se puede observar, se han creado tres pods, pero ninguno se está ejecutándose todavía,
puede que porque la imagen todavía se está descargando.
Unos momentos después, el mismo comando puede que muestre:
Para listar todos los pods que pertenecen al ReplicationController de forma legible,
puedes usar un comando como el siguiente:
pods=$(kubectl get pods --selector=app=nginx --output=jsonpath={.items..metadata.name})echo$pods
nginx-3ntk0 nginx-4ok8v nginx-qrm3m
Como se puede ver, el selector es el mismo que el selector del ReplicationController (mostrado en la salida de
kubectl describe), y con una forma diferente a lo definido en el archivo replication.yaml.
La opción --output=jsonpath especifica una expresión que simplemente muestra el nombre
de cada pod en la lista devuelta.
Escribir una especificación de ReplicationController
Al igual que con el resto de configuraciones de Kubernetes, un ReplicationController necesita los campos apiVersion, kind, y metadata.
Para información general acerca del trabajo con archivos de configuración, ver la gestión de objetos.
Un ReplicationController también necesita un sección .spec.
Plantilla Pod
El campo .spec.template es el único campo requerido de .spec.
El campo .spec.template es una plantilla pod.
Tiene exactamente el mismo esquema que un pod, excepto por el hecho de que está anidado y no tiene los campos apiVersion ni kind.
Además de los campos obligatorios de un Pod, una plantilla pod de un ReplicationController debe especificar las etiquetas apropiadas
y la regla de reinicio apropiada. En el caso de las etiquetas, asegúrate que no se entremezclan con otros controladores. Ver el selector de pod.
Para los reinicios locales de los contenedores, los ReplicationControllers delegan en los agentes del nodo,
por ejmplo el Kubelet o Docker.
Etiquetas en los ReplicationController
los ReplicationController puede tener sus propias (.metadata.labels). Normalmente, se indicaría dichas etiquetas
con los mismos valores que el campo .spec.template.metadata.labels; si el campo .metadata.labels no se indica,
entonces se predetermina al valor de .spec.template.metadata.labels. Sin embargo, se permite que sean diferentes,
y el valor de .metadata.labels no afecta al comportamiento del ReplicationController.
Selector de Pod
El campo .spec.selector es un selector de etiqueta. Un ReplicationController
gestiona todos los pods con etiquetas que coinciden con el selector. No distingue entre
pods que creó o eliminó, y pods que otra persona o proceso creó o eliminó. Esto permite sustituir al ReplicationController sin impactar a ninguno de sus pods que se esté ejecutando.
Si se indica, el valor de .spec.template.metadata.labels debe ser igual al de .spec.selector, o será rechazado por la API.
Si no se indica el valor de .spec.selector, se tomará como predeterminado el de .spec.template.metadata.labels.
Tampoco deberías crear ningún pod cuyas etiquetas coincidan con las de este selector, ni directamente con
otro ReplicationController, ni con otro controlador como un Job. Si lo haces, el
ReplicationController piensa que el creó también los otros pods. Kubernetes no te impide hacerlo.
Si al final terminas con múltiples controladores que tienen selectores que se entremezclan,
tendrás que gestionar la eliminación tú mismo (ver abajo).
Múltiples Réplicas
Puedes configurar cuántos pods deberían ejecutarse de forma concurrente poniendo el valor de .spec.replicas al número
de pods que te gustaría tener ejecutándose a la vez. El número de ejecuciones en cualquier momento puede que sea superior
o inferior, dependiendo de si las réplicas se han incrementado o decrementado, o si un pod se ha apagado de forma controlada,
y su sustituto arranca más pronto.
Si no se indica el valor de .spec.replicas, entonces se predetermina a 1.
Trabajar con ReplicationControllers
Eliminar un ReplicationController y sus Pods
Para eliminar un ReplicationController y todos sus pods, usa el comando kubectl delete. Kubectl reducirá el ReplicationController a cero y esperará
que elimine cada pod antes de eliminar al ReplicationController mismo. Si este comando kubectl
se interrumpe, puede ser reiniciado.
Cuando uses la API REST o la librería Go, necesitas realizar los pasos de forma explícita (reducir las réplicas a cero,
esperar a que se eliminen los pods, y entonces eliminar el ReplicationController).
Eliminar sólo el ReplicationController
Puedes eliminar un ReplicationController sin impactar a ninguno de sus Pods.
Usando kubectl, indica la opción --cascade=false en el comando kubectl delete.
Cuando uses la API REST o la librería Go, simplemente elimina objeto ReplicationController.
Una vez que el objeto original se ha eliminado, puedes crear un nuevo ReplicationController para sustituirlo.
Mientras el viejo y el nuevo valor del .spec.selector sea el mismo, el nuevo adoptará a los viejos pods.
Sin embargo, no se molestará en hacer que los pods actuales coincidan con una plantilla pod nueva, diferente.
Para actualizar los pods con una nueva especificación de forma controlada, utiliza la actualización en línea.
Aislar pods de un ReplicationController
Se puede aislar Pods del conjunto destino de un ReplicationController cambiando sus etiquetas.
Esta técnica puede usarse para eliminar pods de un servicio para poder depurarlos, recuperar datos, etc.
Los Pods que se eliminan de esta forma serán sustituidos de forma automática (asumiendo que el número de réplicas no ha cambiado tampoco).
Patrones comunes de uso
Reprogramación
Como se comentó arriba, cuando tienes 1 pod que quieres mantener ejecutándose, o 1000, un ReplicationController se asegura de que el número indicado de pods exista,
incluso si falla un nodo o se termina algún pod (por ejemplo, debido a alguna acción de otro agente de control).
Escalado
El ReplicationController facilita el escalado del número de réplicas tanto para su aumento como para su disminución,
bien manualmente o mediante un agente de auto-escalado, simplemente actualizando el campo replicas.
Actualizaciones en línea
El ReplicationController se ha diseñado para facilitar las actualizaciones en línea de un servicio mediante la sustitución de sus pods uno por uno.
Cómo se explicó en #1353, la estrategia recomendada es crear un nuevo ReplicationController con 1 réplica,
escalar el nuevo (+1) y el viejo (-1) controlador uno por uno, y entonces eliminar el viejo controlador una vez que alcanza las 0 réplicas.
Esto actualiza de forma predecible el conjunto de pods independientemente de que se produzcan fallos inesperados.
De forma ideal, el controlador de actualización en línea tendrá en cuenta si la aplicación está lista, y
se asegurará de que un número suficiente de pods está en servicio en todo momento.
Los dos ReplicationControllers necesitarán crear pods con al menos una etiqueta diferenciadora, como la etiqueta de imagen del contenedor primario del pod,
ya que las actualizaciones de imagen son las que normalmente desencadenan las actualizaciones en línea.
Además de llevar a cabo múltiples despliegues de una aplicación cuando una actualización en línea está en progreso,
es común ejecutar varios despliegues durante un período extendido de tiempo, o incluso de forma contínua, usando múltiples operaciones de despliegue. Dichas operaciones se diferenciarían por etiquetas.
Por ejemplo, un servicio puede que exponga todos los pods con etiquetas tier in (frontend), environment in (prod). Ahora digamos que tenemos 10 pods replicados que forman este grupo.
Pero queremos poder desplegar una nueva versión 'canary' de este component. Se podría configurar un ReplicationController con el valor de replicas puesto a 9 para la mayor parte de las réplicas,
con etiquetas tier=frontend, environment=prod, track=stable, y otro ReplicationController con el valor de replicas puesto a 1 para el 'canary',
con las etiquetas tier=frontend, environment=prod, track=canary. Así el servicio cubriría tanto los pods canary como el resto.
Pero también es posible trastear con los ReplicationControllers de forma separada para probar cosas, monitorizar los resultados, etc.
Usar ReplicationControllers con servicios
Un único servicio puede exponer múltiples ReplicationControllers, de forma que, por ejemplo, algo de tráfico
vaya a la versión vieja, y otro tanto vaya a la versión nueva.
Un ReplicationController nunca se terminará por sí mismo, pero tampoco se espera que se ejecute permanentemente como los servicios.
Los servicios puede que estén compuestos de pods controlados por múltiples ReplicationControllers,
y se espera que muchos ReplicationControllers se creen y se destruyan durante el ciclo de vida de un servicio (por ejemplo,
para realizar una actualización de los pods que ejecutan el servicio). Ambos servicios mismos y sus clientes deberían permanecer
ajenos a los ReplicationControllers que mantienen los pods que proporcionan los servicios.
Escribir aplicaciones que se repliquen
Los Pods creados por un ReplicationController están pensados para que sean intercambiables y semánticamente idénticos,
aunque sus configuraciones puede que sean heterogéneas a lo largo del tiempo. Este es un ajuste obvio para los servidores sin estado replicados,
pero los ReplicationControllers también pueden utilizarse para mantener la disponibilidad de aplicaciones que se elijen por un maestro, las particionadas, y las de grupos de trabajadores.
Dichas aplicaciones deberían usar los mecanismos de asignación dinámica de trabajo, como las colas de trabajo RabbitMQ,
en vez de la personalización estática/de una sola vez en la configuración de cada pod,
ya que se considera un anti-patrón. Cualquier personalización de pod que se haga, como el calibrado vertical automático de recursos (por ejemplo, cpu o memoria),
debería realizarse a través de otro proceso de controlador en línea, no con el mismo ReplicationController.
Responsabilidades de un ReplicationController
El ReplicationController simplemente garantiza que el número deseado de pods coincide con su selector de etiqueta y que son operacionales.
Actualmente, sólo los pods que han terminado se excluyen de la cuenta. En el futuro, la disponibilidad y otra información disponible en el sistema
se tendrá en cuenta, se añadirá más controles sobre la regla de sussitución, y se está planificando
emitir eventos que podrían ser aprovechados por clientes externos para implementar reglas complejas de sustitución y escalado de forma arbitraria.
El ReplicationController está siempre condicionado a esta reducida responsabilidad.
Él mismo no llevará a cabo ni pruebas de estar listo ni vivo. En vez de aplicar el auto-escalado,
se pretende que este sea realizado por un auto-escalador externo (como se vio en #492), que sería el encargado de cambiar su campo replicas.
No se añadirá reglas de programación (por ejemplo, propagación) al ReplicationController.
Ni se debería validar que los pods controlados coincidan con la plantilla actual especificada, ya que eso obstruiría el auto-calibrado y otros procesos automáticos.
De forma similar, los vencimientos de término, las dependencias de orden, la extensión de la configuración, y otras características se aplican en otro lado.
Incluso se plantea excluir el mecanismo de creación de pods a granel (#170).
El ReplicationController está pensado para ser una primitiva de bloques is intended to be a composable building-block primitive. We expect higher-level APIs and/or tools to be built on top of it and other complementary primitives for user convenience in the future. The "macro" operations currently supported by kubectl (run, scale, rolling-update) are proof-of-concept examples of this. For instance, we could imagine something like Asgard managing ReplicationControllers, auto-scalers, services, scheduling policies, canaries, etc.
Objeto API
El ReplicationController es un recurso de alto nivel en la API REST de Kubernetes. Más detalles acerca del
objeto API se pueden encontrar aquí:
Objeto API ReplicationController.
Alternativas al ReplicationController
ReplicaSet
El ReplicaSet es el ReplicationController de nueva generación que soporta el nuevo selector de etiqueta basado en conjunto.
Se usa principalmente por el Deployment como un mecanismo para orquestrar la creación de pods, la eliminación y las actualizaciones.
Nótese que se recomienda usar Deployments en vez de directamente usar los ReplicaSets, a menos que necesites una orquestración personalizada de actualizaciones o no quieras actualizaciones en absoluto.
Deployment (Recomendado)
El Deployment es un objeto de alto nivel de la API que actualiza sus ReplicaSets subyacenetes y sus Pods
de forma similar a cómo lo hace el comando kubectl rolling-update. Se recomienda el uso de Deployments si se quiere esta functionalidad de actualización en línea,
porque a diferencia del comando kubectl rolling-update, son declarativos, se ejecutan del lado del servidor, y tienen características adicionales.
Pods simples
A diferencia del caso en que un usuario ha creado directamente pods, un ReplicationController sustituye los pods que han sido eliminador o terminados por cualquier motivo,
como en el caso de un fallo de un nodo o una intervención disruptiva de mantenimiento, como la actualización del kernel.
Por esta razón, se recomienda que se usa un ReplicationController incluso si tu aplicación sólo necesita un único pod.
Piensa que es similar a un supervisor de proceso, sólo que supervisa múltiples pods entre múltiples nodos en vez de
procesos individuales en un único nodo. Un ReplicationController delega los reinicios locales de
los contenedores a algún agente del nodo (por ejemplo, Kubelet o Docker).
Job
Usa un Job en vez de un ReplicationController para aquellos pods que se espera que terminen por sí mismos
(esto es, trabajos por lotes).
DaemonSet
Usa un DaemonSet en vez de un ReplicationController para aquellos pods que proporcionan
una función a nivel de servidor, como la monitorización o el loggin de servidor. Estos pods tienen un ciclo de vida que está asociado
al del servidor: el pod necesita ejecutarse en el servidor antes que los otros pods arranquen, y es seguro
terminarlo cuando el servidor está listo para reiniciarse/apagarse.
Un controlador de Deployment proporciona actualizaciones declarativas para los Pods y los
ReplicaSets.
Cuando describes el estado deseado en un objeto Deployment, el controlador del Deployment se encarga de cambiar el estado actual al estado deseado de forma controlada.
Puedes definir Deployments para crear nuevos ReplicaSets, o eliminar Deployments existentes y adoptar todos sus recursos con nuevos Deployments.
Nota: No deberías gestionar directamente los ReplicaSets que pertenecen a un Deployment.
Todos los casos de uso deberían cubrirse manipulando el objeto Deployment.
Considera la posibilidad de abrir un incidente en el repositorio principal de Kubernetes si tu caso de uso no está soportado por el motivo que sea.
Casos de uso
A continuación se presentan los casos de uso típicos de los Deployments:
Declarar el nuevo estado de los Pods actualizando el PodTemplateSpec del Deployment. Ello crea un nuevo ReplicaSet y el Deployment gestiona el cambio de los Pods del viejo ReplicaSet al nuevo de forma controlada. Cada nuevo ReplicaSet actualiza la revisión del Deployment.
Se crea un Deployment denominado nginx-deployment, indicado a través del campo .metadata.name.
El Deployment crea tres Pods replicados, indicado a través del campo replicas.
El campo selector define cómo el Deployment identifica los Pods que debe gestionar.
En este caso, simplemente seleccionas una etiqueta que se define en la plantilla Pod (app: nginx).
Sin embargo, es posible definir reglas de selección más sofisticadas,
siempre que la plantilla Pod misma satisfaga la regla.
Nota:matchLabels es un mapa de entradas {clave,valor}. Una entrada simple {clave,valor} en el mapa matchLabels
es equivalente a un elemento de matchExpressions cuyo campo sea la "clave", el operador sea "In",
y la matriz de valores contenga únicamente un "valor". Todos los requisitos se concatenan con AND.
El campo template contiene los siguientes sub-campos:
Los Pods se etiquetan como app: nginx usando el campo labels.
La especificación de la plantilla Pod, o el campo .template.spec, indica
que los Pods ejecutan un contenedor, nginx, que utiliza la versión 1.7.9 de la imagen de nginx de
Docker Hub.
Crea un contenedor y lo llamar nginx usando el campo name.
Ejecuta la imagen nginx en su versión 1.7.9.
Abre el puerto 80 para que el contenedor pueda enviar y recibir tráfico.
Para crear este Deployment, ejecuta el siguiente comando:
Nota: Debes indicar el parámetro --record para registrar el comando ejecutado en la anotación de recurso kubernetes.io/change-cause.
Esto es útil para futuras introspecciones, por ejemplo para comprobar qué comando se ha ejecutado en cada revisión del Deployment.
A continuación, ejecuta el comando kubectl get deployments. La salida debe ser parecida a la siguiente:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3000 1s
Cuando inspeccionas los Deployments de tu clúster, se muestran los siguientes campos:
NAME enumera los nombre de los Deployments del clúster.
DESIRED muestra el número deseado de réplicas de la aplicación, que se define
cuando se crea el Deployment. Esto se conoce como el estado deseado.
CURRENT muestra cuántas réplicas se están ejecutando actualment.
UP-TO-DATE muestra el número de réplicas que se ha actualizado para alcanzar el estado deseado.
AVAILABLE muestra cuántas réplicas de la aplicación están disponibles para los usuarios.
AGE muestra la cantidad de tiempo que la aplicación lleva ejecutándose.
Nótese cómo los valores de cada campo corresponden a los valores de la especificación del Deployment:
El número de réplicas deseadas es 3 de acuerdo con el campo .spec.replicas.
El número de réplicas actuales es 0 de acuerdo con el campo .status.replicas.
El número de réplicas actualizadas es 0 de acuerdo con el campo .status.updatedReplicas.
El número de réplicas disponibles es 0 de acuerdo con el campo .status.availableReplicas.
Para ver el estado del Deployment, ejecuta el comando kubectl rollout status deployment.v1.apps/nginx-deployment. Este comando devuelve el siguiente resultado:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
Ejecuta de nuevo el comando kubectl get deployments unos segundos más tarde:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3333 18s
Fíjate que el Deployment ha creado todas las tres réplicas, y que todas las réplicas están actualizadas (contienen
la última plantilla Pod) y están disponibles (el estado del Pod tiene el valor Ready al menos para el campo .spec.minReadySeconds del Deployment).
Para ver el ReplicaSet (rs) creado por el Deployment, ejecuta el comando kubectl get rs:
NAME DESIRED CURRENT READY AGE
nginx-deployment-75675f5897 333 18s
Fíjate que el nombre del ReplicaSet siempre se formatea con el patrón [DEPLOYMENT-NAME]-[RANDOM-STRING]. La cadena aleatoria se
genera de forma aleatoria y usa el pod-template-hash como semilla.
Para ver las etiquetas generadas automáticamente en cada pod, ejecuta el comando kubectl get pods --show-labels. Se devuelve la siguiente salida:
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
El ReplicaSet creado garantiza que hay tres Pods de nginx ejecutándose en todo momento.
Nota: En un Deployment, debes especificar un selector apropiado y etiquetas de plantilla Pod (en este caso,
app: nginx). No entremezcles etiquetas o selectores con otros controladores (incluyendo otros Deployments y StatefulSets).
Kubernetes no te impide que lo hagas, pero en el caso de que múltiples controladores tengan selectores mezclados, dichos controladores pueden entrar en conflicto y provocar resultados inesperados.
Etiqueta pod-template-hash
Nota: No cambies esta etiqueta.
La etiqueta pod-template-hash es añadida por el controlador del Deployment a cada ReplicaSet que el Deployment crea o adopta.
Esta etiqueta garantiza que todos los hijos ReplicaSets de un Deployment no se entremezclan. Se genera mediante una función hash aplicada al PodTemplate del ReplicaSet
y usando el resultado de la función hash como el valor de la etiqueta que se añade al selector del ReplicaSet, en las etiquetas de la plantilla Pod,
y en cualquier Pod existente que el ReplicaSet tenga.
Actualizar un Deployment
Nota: El lanzamiento de un Deployment se activa si y sólo si la plantilla Pod del Deployment (esto es, .spec.template)
se cambia, por ejemplo si se actualiza las etiquetas o las imágenes de contenedor de la plantilla.
Otras actualizaciones, como el escalado del Deployment, no conllevan un lanzamiento de despliegue.
Asumiendo que ahora quieres actualizar los Pods nginx para que usen la imagen nginx:1.9.1
en vez de la imagen nginx:1.7.9.
kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
image updated
De forma alternativa, puedes editar el Deployment y cambiar el valor del campo .spec.template.spec.containers[0].image de nginx:1.7.9 a nginx:1.9.1:
kubectl edit deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment edited
Para ver el estado del despliegue, ejecuta:
kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
Cuando el despliegue funciona, puede que quieras obtener el Deployment:
kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 36s
El número de réplicas actualizadas indica que el Deployment ha actualizado las réplicas según la última configuración.
Las réplicas actuales indican el total de réplicas que gestiona este Deployment, y las réplicas disponibles indican
el número de réplicas actuales que están disponibles.
Puedes ejecutar el comando kubectl get rs para ver que el Deployment actualizó los Pods creando un nuevo ReplicaSet y escalándolo
hasta las 3 réplicas, así como escalando el viejo ReplicaSet a 0 réplicas.
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 6s
nginx-deployment-2035384211 0 0 0 36s
Si ejecutas el comando get pods deberías ver los nuevos Pods:
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-khku8 1/1 Running 0 14s
nginx-deployment-1564180365-nacti 1/1 Running 0 14s
nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
La próxima vez que quieras actualizar estos Pods, sólo necesitas actualizar la plantilla Pod del Deployment otra vez.
El Deployment permite garantizar que sólo un número determinado de Pods puede eliminarse mientras se están actualizando.
Por defecto, garantiza que al menos el 25% menos del número deseado de Pods se está ejecutando (máx. 25% no disponible).
El Deployment tmabién permite garantizar que sólo un número determinado de Pods puede crearse por encima del número deseado de
Pods. Por defecto, garantiza que al menos el 25% más del número deseado de Pods se está ejecutando (máx. 25% de aumento).
Por ejemplo, si miras detenidamente el Deployment de arriba, verás que primero creó un Pod,
luego eliminó algunos viejos Pods y creó otros nuevos. No elimina los viejos Pods hasta que un número suficiente de
nuevos Pods han arrancado, y no crea nuevos Pods hasta que un número suficiente de viejos Pods se han eliminado.
De esta forma, asegura que el número de Pods disponibles siempre es al menos 2, y el número de Pods totales es cómo máximo 4.
kubectl describe deployments
Name: nginx-deployment
Namespace: default
CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=2
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
Aquí puedes ver que cuando creaste por primera vez el Deployment, este creó un ReplicaSet (nginx-deployment-2035384211)
y lo escaló a 3 réplicas directamente. Cuando actualizaste el Deployment, creó un nuevo ReplicaSet
(nginx-deployment-1564180365) y lo escaló a 1 y entonces escaló el viejo ReplicaSet a 2, de forma que al menos
hubiera 2 Pods disponibles y como mucho 4 Pods en total en todo momento. Entonces, continuó escalando
el nuevo y el viejo ReplicaSet con la misma estrategia de actualización continua. Finalmente, el nuevo ReplicaSet acaba con 3 réplicas
disponibles, y el viejo ReplicaSet se escala a 0.
Sobrescritura (o sea, múltiples actualizaciones a la vez)
Cada vez que el controlador del Deployment observa un nuevo objeto de despliegue, se crea un ReplicaSet para arrancar
los Pods deseados si es que no existe otro ReplicaSet haciéndolo. Los ReplicaSet existentes que controlan los Pods cuyas etiquetas
coinciden con el valor del campo .spec.selector, pero cuya plantilla no coincide con el valor del campo .spec.template se reducen. Al final,
el nuevo ReplicaSet se escala hasta el valor del campo .spec.replicas y todos los viejos ReplicaSets se escalan a 0.
Si actualizas un Deployment mientras otro despliegue está en curso, el Deployment creará un nuevo ReplicaSet
como consecuencia de la actualización y comenzará a escalarlo, y sobrescribirá al ReplicaSet que estaba escalando anteriormente
-- lo añadirá a su lista de viejos ReplicaSets y comenzará a reducirlos.
Por ejemplo, supongamos que creamos un Deployment para crear 5 réplicas de nginx:1.7.9,
pero entonces actualizamos el Deployment para crear 5 réplicas de nginx:1.9.1 cuando sólo se ha creado 3
réplicas de nginx:1.7.9. En este caso, el Deployment comenzará automáticamente a matar los 3 Pods de nginx:1.7.9
que había creado, y empezará a crear los Pods de nginx:1.9.1. Es decir, no esperará a que se creen las 5 réplicas de nginx:1.7.9
antes de aplicar la nueva configuración.
Actualizaciones del selector de etiquetas
No se recomienda hacer cambios al selector del etiquetas y, por ello, se aconseja encarecidamente planificar el valor de dichos selectores por adelantado.
En cualquier caso, si necesitas cambiar un selector de etiquetas, hazlo con mucho cuidado y asegúrate que entiendes todas sus implicaciones.
Nota: En la versión apps/v1 de la API, el selector de etiquetas del Deployment es inmutable una vez se ha creado.
Las adiciones posteriores al selector obligan también a actualizar las etiquetas de la plantilla Pod en la especificación del Deployment con los nuevos valores,
ya que de lo contrario se devolvería un error. Este cambio no es de superposición, es decir, que el nuevo selector
no selecciona los ReplicaSets y Pods creados con el viejo selector, lo que provoca que todos los viejos ReplicaSets se marquen como huérfanos y
la creación de un nuevo ReplicaSet.
Las actualizaciones de selector -- esto es, cambiar el valor actual en una clave de selector -- provocan el mismo comportamiento que las adiciones.
Las eliminaciones de selector -- esto es, eliminar una clave actual del selector del Deployment -- no necesitan de cambios en las etiquetas de la plantilla Pod.
No se marca ningún ReplicaSet existente como huérfano, y no se crea ningún ReplicaSet nuevo, pero debe tenerse en cuenta que
la etiqueta eliminada todavía existe en los Pods y ReplicaSets que se están ejecutando.
Revertir un Deployment
En ocasiones necesitas revertir un Deployment; por ejemplo, cuando el Deployment no es estable, como cuando no para de reiniciarse.
Por defecto, toda la historia de despliegue del Deployment se mantiene en el sistema de forma que puedes revertir en cualquier momento
(se puede modificar este comportamiento cambiando el límite de la historia de revisiones de modificaciones).
Nota: Cuando se lanza el despligue de un Deployment, se crea una nueva revisión. Esto quiere decir que
la nueva revisión se crea si y sólo si la plantilla Pod del Deployment (.spec.template) se cambia;
por ejemplo, si cambias las etiquetas o la imagen del contenedor de la plantilla.
Otras actualizaciones, como escalar el Deployment,
no generan una nueva revisión del Deployment, para poder facilitar el escalado manual simultáneo - o auto-escalado.
Esto significa que cuando reviertes a una versión anterior, sólo la parte de la plantilla Pod del Deployment se revierte.
Vamos a suponer que hemos cometido un error al actualizar el Deployment, poniendo como nombre de imagen nginx:1.91 en vez de nginx:1.9.1:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true
deployment.apps/nginx-deployment image updated
El despliegue se atasca y no progresa.
kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
Presiona Ctrl-C para detener la monitorización del despliegue de arriba. Para obtener más información sobre despliegues atascados,
lee más aquí.
Verás que el número de réplicas viejas (nginx-deployment-1564180365 y nginx-deployment-2035384211) es 2, y el número de nuevas réplicas (nginx-deployment-3066724191) es 1.
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 25s
nginx-deployment-2035384211 0 0 0 36s
nginx-deployment-3066724191 1 1 0 6s
Echando un vistazo a los Pods creados, verás que uno de los Pods creados por el nuevo ReplicaSet está atascado en un bucle intentando bajar la imagen:
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-70iae 1/1 Running 0 25s
nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s
nginx-deployment-1564180365-hysrc 1/1 Running 0 25s
nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
Nota: El controlador del Deployment parará el despliegue erróneo de forma automática, y detendrá el escalado del nuevo
ReplicaSet. Esto depende de los parámetros del rollingUpdate (maxUnavailable específicamente) que hayas configurado.
Kubernetes por defecto establece el valor en el 25%.
kubectl describe deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
Labels: app=nginx
Selector: app=nginx
Replicas: 3 desired | 1 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.91
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
OldReplicaSets: nginx-deployment-1564180365 (3/3 replicas created)
NewReplicaSet: nginx-deployment-3066724191 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 1
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
Para arreglar este problema, necesitas volver a una revisión previa del Deployment que sea estable.
Comprobar la Historia de Despliegues de un Deployment
Primero, comprobemos las revisiones de este despliegue:
kubectl rollout history deployment.v1.apps/nginx-deployment
En el momento de la creación, el mensaje en CHANGE-CAUSE se copia de la anotación kubernetes.io/change-cause del Deployment a sus revisiones. Podrías indicar el mensaje CHANGE-CAUSE:
Anotando el Deployment con el comando kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image updated to 1.9.1"
Añadiendo el parámetro --record para registrar el comando kubectl que está haciendo cambios en el recurso.
Manualmente editando el manifiesto del recursos.
Para ver más detalles de cada revisión, ejecuta:
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
Para más detalles acerca de los comandos relacionados con las revisiones de un Deployment, echa un vistazo a kubectl rollout.
El Deployment se ha revertido ahora a una revisión previa estable. Como se puede comprobar, el controlador del Deployment genera un evento DeploymentRollback
al retroceder a la revisión 2.
kubectl get deployment nginx-deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 30m
kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=4
kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-c4747d96c (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-75675f5897 to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 0
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-595696685f to 1
Normal DeploymentRollback 15s deployment-controller Rolled back deployment "nginx-deployment" to revision 2
Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-595696685f to 0
Escalar un Deployment
Puedes escalar un Deployment usando el siguiente comando:
Asumiendo que se ha habilitado el escalado horizontal de pod
en tu clúster, puedes configurar un auto-escalado para tu Deployment y elegir el mínimo y máximo número de Pods
que quieres ejecutar en base al uso de CPU de tus Pods actuales.
La actualización continua de los Deployments permite la ejecución de múltiples versiones de una aplicación al mismo tiempo.
Cuando tú o un auto-escalado escala un Deployment con actualización continua que está en medio de otro despliegue (bien en curso o pausado),
entonces el controlador del Deployment balanceará las réplicas adicionales de los ReplicaSets activos (ReplicaSets con Pods)
para así poder mitigar el riesgo. Esto se conoce como escalado proporcional.
Por ejemplo, imagina que estás ejecutando un Deployment con 10 réplicas, donde maxSurge=3, y maxUnavailable=2.
kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 10 10 10 10 50s
Si actualizas a una nueva imagen que no puede descargarse desde el clúster:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:sometag
deployment.apps/nginx-deployment image updated
La actualización de la imagen arranca un nuevo despliegue con el ReplicaSet nginx-deployment-1989198191,
pero se bloquea debido al requisito maxUnavailable indicado arriba:
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 5 5 0 9s
nginx-deployment-618515232 8 8 8 1m
Y entonces se origina una nueva petición de escalado para el Deployment. El auto-escalado incrementa las réplicas del Deployment
a 15. El controlador del Deployment necesita ahora decidir dónde añadir esas nuevas 5 réplicas.
Si no estuvieras usando el escalado proporcional, las 5 se añadirían al nuevo ReplicaSet. Pero con el escalado proporcional,
las réplicas adicionales se distribuyen entre todos los ReplicaSets. Las partes más grandes van a los ReplicaSets
con el mayor número de réplicas y las partes más pequeñas van a los ReplicaSets con menos réplicas. Cualquier resto sobrante se añade
al ReplicaSet con mayor número de réplicas. Aquellos ReplicaSets con 0 réplicas no se escalan.
En nuestro ejemplo anterior, se añadirán 3 réplicas al viejo ReplicaSet y 2 réplicas al nuevo ReplicaSet.
EL proceso de despliegue debería al final mover todas las réplicas al nuevo ReplicaSet, siempre que las nuevas
réplicas arranquen positivamente.
kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
Pausar y Reanudar un Deployment
Puedes pausar un Deployment antes de arrancar una o más modificaciones y luego reanudarlo. Esto te permite aplicar múltiples arreglos
entre la pausa y la reanudación sin necesidad de arrancar despliegues innecesarios.
Por ejemplo, con un Deployment que acaba de crearse:
kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 3 1m
kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 1m
El estado inicial del Deployment anterior a la pausa continuará su función, pero las nuevas modificaciones
del Deployment no tendrán efecto ya que el Deployment está pausado.
Al final, reanuda el Deployment y observa cómo se genera un nuevo ReplicaSet con todos los cambios:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 28s
Nota: No se puede revertir un Deployment pausado hasta que se vuelve a reanudar.
Estado del Deployment
Un Deployment pasa por varios estados a lo largo de su ciclo de vida. Así, puede estar progresando mientras
se despliega un nuevo ReplicaSet, puede estar completo, o puede quedar en estado fallido.
Progresar un Deployment
Kubernetes marca un Deployment como progresando cuando se realiza cualquiera de las siguientes tareas:
El Deployment crea un nuevo ReplicaSet.
El Deployment está escalando su ReplicaSet más nuevo.
El Deployment está reduciendo su(s) ReplicaSet(s) más antiguo(s).
Hay nuevos Pods disponibles y listos (listo por lo menos MinReadySeconds).
Puedes monitorizar el progreso de un Deployment usando el comando kubectl rollout status.
Completar un Deployment
Kubernetes marca un Deployment como completado cuando presenta las siguientes características:
Todas las réplicas asociadas con el Deployment han sido actualizadas a la última versión indicada, lo cual quiere decir
que todas las actualizaciones se han completado.
Todas las réplicas asociadas con el Deployment están disponibles.
No están ejecutándose viejas réplicas del Deployment.
Puedes comprobar si un Deployment se ha completado usando el comando kubectl rollout status. Si el despliegue se ha completado
de forma satisfactoria, el comando kubectl rollout status devuelve un código 0 de salida.
kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
$ echo $?
0
Deployment fallido
Tu Deployment puede quedarse bloqueado intentando desplegar su nuevo ReplicaSet sin nunca completarse. Esto puede ocurrir
debido a algunos de los factores siguientes:
Cuota insuficiente
Fallos en la prueba de estar listo
Errores en la descarga de imágenes
Permisos insuficientes
Rangos de límites de recursos
Mala configuración del motor de ejecución de la aplicación
Una forma de detectar este tipo de situación es especificar un parámetro de vencimiento en la especificación de tu Deployment:
(.spec.progressDeadlineSeconds). .spec.progressDeadlineSeconds denota el número
de segundos que el controlador del Deployment debe esperar antes de indicar (en el estado del Deployment) que el
Deployment no avanza.
El siguiente comando kubectl configura el campo progressDeadlineSeconds para forzar al controlador a
informar de la falta de avance de un Deployment después de 10 minutos:
Una vez que se ha excedido el vencimiento, el controlador del Deployment añade una DeploymentCondition
con los siguientes atributos al campo .status.conditions del Deployment:
Nota: Kubernetes no emprenderá ninguna acción ante un Deployment parado que no sea la de reportar el estado mediante
Reason=ProgressDeadlineExceeded. Los orquestradores de alto nivel pueden aprovecharse y actuar consecuentemente, por ejemplo,
retrocediendo el Deployment a su versión previa.
Nota: Si pausas un Deployment, Kubernetes no comprueba el avance en base al vencimiento indicado. Así, es posible pausar
de forma segura un Deployment en medio de un despliegue y reanudarlo sin que se arranque el estado de exceso de vencimiento.
Puede que notes errores transitorios en tus Deployments, bien debido a un tiempo de vencimiento muy pequeño que hayas configurado
o bien a cualquier otro tipo de error que puede considerarse como transitorio. Por ejemplo,
supongamos que no tienes suficiente cuota. Si describes el Deployment, te darás cuenta de la sección siguiente:
kubectl describe deployment nginx-deployment
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
Si ejecutas el comando kubectl get deployment nginx-deployment -o yaml, el estado del Deployment puede parecerse a:
Al final, una vez que se supera el vencimiento del progreso del Deployment, Kubernetes actualiza el estado
y la razón de el estado de progreso:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
Puedes solucionar un problema de cuota insuficiente simplemente reduciendo el número de réplicas de tu Deployment, reduciendo
otros controladores que puedas estar ejecutando, o incrementando la cuota en tu espacio de nombres. Si una vez satisfechas las condiciones de tu cuota,
el controlador del Deployment completa el despliegue, entonces verás que el estado del Deployment se actualiza al estado satisfactorio (Status=True y Reason=NewReplicaSetAvailable).
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Type=Available con Status=True significa que tu Deployment tiene disponibilidad mínima. La disponibilidad mínima se prescribe
mediante los parámetros indicados en la estrategia de despligue. Type=Progressing con Status=True significa que tu Deployment
está bien en medio de un despliegue y está progresando o bien que se ha completado de forma satisfactoria y el número mínimo
requerido de nuevas réplicas ya está disponible (ver la Razón del estado para cada caso particular - en nuestro caso
Reason=NewReplicaSetAvailable significa que el Deployment se ha completado).
Puedes comprobar si un Deployment ha fallado en su progreso usando el comando kubectl rollout status. kubectl rollout status
devuelve un código de salida distinto de 0 si el Deployment ha excedido su tiempo de vencimiento.
kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
$ echo $?
1
Actuar ante un despliegue fallido
Todas las acciones que aplican a un Deployment completado también aplican a un Deployment fallido. Puedes escalarlo/reducirlo, retrocederlo
a una revisión previa, o incluso pausarlo si necesitas realizar múltiples cambios a la plantilla Pod del Deployment.
Regla de Limpieza
Puedes configurar el campo .spec.revisionHistoryLimit de un Deployment para especificar cuántos ReplicaSets viejos quieres conservar
para este Deployment. El resto será eliminado en segundo plano. Por defecto, es 10.
Nota: Poner este campo de forma explícita a 0 resulta en la limpieza de toda la historia de tu Deployment,
por lo que tu Deployment no podrá retroceder a revisiones previas.
Casos de Uso
Despligue Canary
Si quieres desplegar nuevas versiones a un sub-conjunto de usuarios o servidores usando el Deployment,
puedes hacerlo creando múltiples Deployments, uno para cada versión nueva, siguiendo el patrón canary descrito en
gestionar recursos.
Escribir una especificación de Deployment
Al igual que con el resto de configuraciones de Kubernetes, un Deployment requiere los campos apiVersion, kind, y metadata.
Para información general acerca de cómo trabajar con ficheros de configuración, ver los documentos acerca de desplegar aplicaciones,
configurar contenedores, y usar kubectl para gestionar recursos.
Tanto .spec.template como .spec.selector sin campos obligatorios dentro de .spec.
El campo .spec.template es una plantilla Pod. Tiene exactamente el mismo esquema que un Pod,
excepto por el hecho de que está anidado y no tiene apiVersion ni kind.
Junto con los campos obligatorios de un Pod, una plantilla Pod de un Deployment debe indicar las etiquetas
y las reglas de reinicio apropiadas. Para el caso de las etiquetas, asegúrate que no se entremezclan con otros controladores. Ver selector).
.spec.replicas es un campo opcional que indica el número de Pods deseados. Su valor por defecto es 1.
Selector
.spec.selector es un campo opcional que indica un selector de etiquetas
para los Pods objetivo del deployment.
.spec.selector debe coincidir con .spec.template.metadata.labels, o será descartado por la API.
A partir de la versión apps/v1 de la API, .spec.selector y .metadata.labels no toman como valor por defecto el valor de .spec.template.metadata.labels si no se indica.
Por ello, debe especificarse de forma explícita. Además hay que mencionar que .spec.selector es inmutable tras la creación del Deployment en apps/v1.
Un Deployment puede finalizar aquellos Pods cuyas etiquetas coincidan con el selector si su plantilla es diferente
de .spec.template o si el número total de dichos Pods excede .spec.replicas. Arranca nuevos
Pods con .spec.template si el número de Pods es menor que el número deseado.
Nota: No deberías crear otros Pods cuyas etiquetas coincidan con este selector, ni directamente creando
otro Deployment, ni creando otro controlador como un ReplicaSet o un ReplicationController. Si lo haces,
el primer Deployment pensará que también creó esos otros Pods. Kubernetes no te impide hacerlo.
Si tienes múltiples controladores que entremezclan sus selectores, dichos controladores competirán entre ellos
y no se comportarán de forma correcta.
Estrategia
.spec.strategy especifica la estrategia usada para remplazar los Pods viejos con los nuevos.
.spec.strategy.type puede tener el valor "Recreate" o "RollingUpdate". "RollingUpdate" el valor predeterminado.
Despliegue mediante recreación
Todos los Pods actuales se eliminan antes de que los nuevos se creen cuando .spec.strategy.type==Recreate.
Despliegue mediante actualización continua
El Deployment actualiza los Pods en modo de actualización continua
cuando .spec.strategy.type==RollingUpdate. Puedes configurar los valores de maxUnavailable y maxSurge
para controlar el proceso de actualización continua.
Número máximo de pods no disponibles
.spec.strategy.rollingUpdate.maxUnavailable es un campo opcional que indica el número máximo
de Pods que pueden no estar disponibles durante el proceso de actualización. El valor puede ser un número absoluto (por ejemplo, 5)
o un porcentaje de los Pods deseados (por ejemplo, 10%). El número absoluto se calcula a partir del porcentaje
con redondeo a la baja. El valor no puede ser 0 si .spec.strategy.rollingUpdate.maxSurge es 0. El valor predeterminado es 25%.
Por ejemplo, cuando este valor es 30%, el ReplicaSet viejo puede escalarse al 70% de los
Pods deseados de forma inmediata tras comenzar el proceso de actualización. Una vez que los Pods están listos,
el ReplicaSet viejo puede reducirse aún mas, seguido de un escalado del nuevo ReplicaSet,
asegurándose que el número total de Pods disponibles en todo momento durante la actualización
es de al menos el 70% de los Pods deseados.
Número máximo de pods por encima del número deseado
.spec.strategy.rollingUpdate.maxSurge es un campo opcional que indica el número máximo de Pods
que puede crearse por encima del número deseado de Pods. El valor puede ser un número absoluto (por ejemplo, 5)
o un porcentaje de los Pods deseados (por ejemplo, 10%). El valor no puede ser 0 si MaxUnavailable es 0.
El número absoluto se calcula a partir del porcentaje con redondeo al alza. El valor predeterminado es 25%.
Por ejemplo, cuando este valor es 30%, el nuevo ReplicaSet puede escalarse inmediatamente cuando
comienza la actualización continua, de forma que el número total de Pods viejos y nuevos no
excede el 130% de los Pods deseados. Una vez que los viejos Pods se han eliminado, el nuevo ReplicaSet
puede seguir escalándose, asegurándose que el número total de Pods ejecutándose en todo momento
durante la actualización es como mucho del 130% de los Pods deseados.
Segundos para vencimiento del progreso
.spec.progressDeadlineSeconds es un campo opcional que indica el número de segundos que quieres
esperar a que tu Deployment avance antes de que el sistema reporte que dicho Deployment
ha fallado en su avance - expresado como un estado con Type=Progressing, Status=False.
y Reason=ProgressDeadlineExceeded en el recurso. El controlador del Deployment seguirá intentando
el despliegue. En el futuro, una vez que se implemente el retroceso automático, el controlador del Deployment
retrocederá el despliegue en cuanto detecte ese estado.
Si se especifica, este campo debe ser mayor que .spec.minReadySeconds.
Tiempo mínimo para considerar el Pod disponible
.spec.minReadySeconds es un campo opcional que indica el número mínimo de segundos en que
un Pod recién creado debería estar listo sin que falle ninguno de sus contenedores, para que se considere disponible.
Por defecto su valor es 0 (el Pod se considera disponible en el momento que está listo). Para aprender más acerca de
cuándo un Pod se considera que está listo, ver las pruebas de contenedor.
Vuelta atrás
El campo .spec.rollbackTo se ha quitado de las versiones extensions/v1beta1 y apps/v1beta1 de la API, y ya no se permite en las versiones de la API a partir de apps/v1beta2.
En su caso, se debería usar kubectl rollout undo, tal y como se explicó en Retroceder a una Revisión Previa.
Límite del histórico de revisiones
La historia de revisiones de un Deployment se almacena en los ReplicaSets que este controla.
.spec.revisionHistoryLimit es un campo opcional que indica el número de ReplicaSets viejos a retener
para permitir los retrocesos. Estos ReplicaSets viejos consumen recursos en etcd y rebosan la salida de kubectl get rs.
La configuración de cada revisión de Deployment se almacena en sus ReplicaSets;
por lo tanto, una vez que se elimina el ReplicaSet viejo, se pierde la posibilidad de retroceder a dicha revisión del Deployment.
Por defecto, se retienen hasta 10 ReplicaSets viejos; pero su valor ideal depende de la frecuencia y la estabilidad de los nuevos Deployments.
De forma más específica, si ponemos este campo a cero quiere decir que todos los ReplicaSets viejos con 0 réplicas se limpiarán.
En este caso, el nuevo despliegue del Deployment no se puede deshacer, ya que su historia de revisiones se habrá limpiado.
Pausa
.spec.paused es un campo booleano opcional para pausar y reanudar un Deployment. La única diferencia entre
un Deployment pausado y otro que no lo está es que cualquier cambio al PodTemplateSpec del Deployment pausado
no generará nuevos despliegues mientras esté pausado. Un Deployment se pausa de forma predeterminada cuando se crea.
Alternativa a los Deployments
kubectl rolling update
kubectl rolling update actualiza los Pods y los ReplicationControllers
de forma similar. Pero se recomienda el uso de Deployments porque se declaran del lado del servidor, y proporcionan características adicionales
como la posibilidad de retroceder a revisiones anteriores incluso después de haber terminado una actualización continua.
3.4.2.4 - StatefulSets
Un StatefulSet es el objeto de la API workload que se usa para gestionar aplicaciones con estado.
Nota: Los StatefulSets son estables (GA) en la versión 1.9.
Gestiona el despliegue y escalado de un conjunto de Pods,
y garantiza el orden y unicidad de dichos Pods.
Al igual que un Deployment, un StatefulSet gestiona Pods
que se basan en una especificación idéntica de contenedor. A diferencia de un Deployment, un
StatefulSet mantiene una identidad asociada a sus Pods. Estos pods se crean a partir de la
misma especificación, pero no pueden intercambiarse; cada uno tiene su propio identificador persistente
que mantiene a lo largo de cualquier re-programación.
Un StatefulSet opera bajo el mismo patrón que cualquier otro controlador.
Se define el estado deseado en un objeto StatefulSet, y el controlador del StatefulSet efectúa
las actualizaciones que sean necesarias para alcanzarlo a partir del estado actual.
Usar StatefulSets
Los StatefulSets son valiosos para aquellas aplicaciones que necesitan uno o más de los siguientes:
Identificadores de red estables, únicos.
Almacenamiento estable, persistente.
Despliegue y escalado ordenado, controlado.
Actualizaciones en línea ordenadas, automatizadas.
De los de arriba, estable es sinónimo de persistencia entre (re)programaciones de Pods.
Si una aplicación no necesita ningún identificador estable o despliegue,
eliminación, o escalado ordenado, deberías desplegar tu aplicación con un controlador que
proporcione un conjunto de réplicas sin estado, como un
Deployment o un
ReplicaSet, ya que están mejor preparados
para tus necesidades sin estado.
Limitaciones
El almacenamiento de un determinado Pod debe provisionarse por un Provisionador de PersistentVolume basado en la storage class requerida, o pre-provisionarse por un administrador.
Eliminar y/o reducir un StatefulSet no eliminará los volúmenes asociados con el StatefulSet. Este comportamiento es intencional y sirve para garantizar la seguridad de los datos, que da más valor que la purga automática de los recursos relacionados del StatefulSet.
Los StatefulSets actualmente necesitan un Servicio Headless como responsable de la identidad de red de los Pods. Es tu responsabilidad crear este Service.
Los StatefulSets no proporcionan ninguna garantía de la terminación de los pods cuando se elimina un StatefulSet. Para conseguir un término de los pods ordenado y controlado en el StatefulSet, es posible reducir el StatefulSet a 0 réplicas justo antes de eliminarlo.
El ejemplo de abajo demuestra los componentes de un StatefulSet:
Un servicio Headless, llamado nginx, se usa para controlar el dominio de red.
Un StatefulSet, llamado web, que tiene una especificación que indica que se lanzarán 3 réplicas del contenedor nginx en Pods únicos.
Un volumeClaimTemplate que proporciona almacenamiento estable por medio de PersistentVolumes provisionados por un provisionador de tipo PersistentVolume.
apiVersion:v1kind:Servicemetadata:name:nginxlabels:app:nginxspec:ports:- port:80name:webclusterIP:Noneselector:app:nginx---apiVersion:apps/v1kind:StatefulSetmetadata:name:webspec:selector:matchLabels:app:nginx# tiene que coincidir con .spec.template.metadata.labelsserviceName:"nginx"replicas:3# por defecto es 1template:metadata:labels:app:nginx# tiene que coincidir con .spec.selector.matchLabelsspec:terminationGracePeriodSeconds:10containers:- name:nginximage:k8s.gcr.io/nginx-slim:0.8ports:- containerPort:80name:webvolumeMounts:- name:wwwmountPath:/usr/share/nginx/htmlvolumeClaimTemplates:- metadata:name:wwwspec:accessModes:["ReadWriteOnce"]storageClassName:"my-storage-class"resources:requests:storage:1Gi
Selector de Pod
Debes poner el valor del campo .spec.selector de un StatefulSet para que coincida con las etiquetas de su campo .spec.template.metadata.labels. Antes de Kubernetes 1.8,
el campo .spec.selector se predeterminaba cuando se omitía. A partir de la versión 1.8, si no se especifica un selector de coincidencia de Pods, se produce un error de validación
durante la creación del StatefulSet.
Identidad de Pod
Los Pods de un StatefulSet tienen una identidad única que está formada por un ordinal,
una identidad estable de red, y almacenamiento estable. La identidad se asocia al Pod,
independientemente del nodo en que haya sido (re)programado.
Índice Ordinal
Para un StatefulSet con N réplicas, a cada Pod del StatefulSet se le asignará
un número entero ordinal, desde 0 hasta N-1, y que es único para el conjunto.
ID estable de Red
El nombre de anfitrión (hostname) de cada Pod de un StatefulSet se deriva del nombre del StatefulSet
y del número ordinal del Pod. El patrón para construir dicho hostname
es $(statefulset name)-$(ordinal). Así, el ejemplo de arriba creará tres Pods
denominados web-0,web-1,web-2.
Un StatefulSet puede usar un Servicio Headless
para controlar el nombre de dominio de sus Pods. El nombre de dominio gestionado por este Service tiene la forma:
$(service name).$(namespace).svc.cluster.local, donde "cluster.local" es el nombre de dominio del clúster.
Conforme se crea cada Pod, se le asigna un nombre DNS correspondiente de subdominio, que tiene la forma:
$(podname).$(governing service domain), donde el servicio en funciones se define por el campo
serviceName del StatefulSet.
Como se indicó en la sección limitaciones, la creación del
Servicio Headless
encargado de la identidad de red de los pods es enteramente tu responsabilidad.
Aquí se muestran algunos ejemplos de elecciones de nombres de Cluster Domain, nombres de Service,
nombres de StatefulSet, y cómo impactan en los nombres DNS de los Pods del StatefulSet:
Kubernetes crea un PersistentVolume para cada
VolumeClaimTemplate. En el ejemplo de nginx de arriba, cada Pod recibirá un único PersistentVolume
con una StorageClass igual a my-storage-class y 1 Gib de almacenamiento provisionado. Si no se indica ninguna StorageClass,
entonces se usa la StorageClass por defecto. Cuando un Pod se (re)programa
en un nodo, sus volumeMounts montan los PersistentVolumes asociados con sus
PersistentVolume Claims. Nótese que los PersistentVolumes asociados con los
PersistentVolume Claims de los Pods no se eliminan cuando los Pods, o los StatefulSet se eliminan.
Esto debe realizarse manualmente.
Etiqueta de Nombre de Pod
Cuando el controlador del StatefulSet crea un Pod, añade una etiqueta, statefulset.kubernetes.io/pod-name,
que toma el valor del nombre del Pod. Esta etiqueta te permite enlazar un Service a un Pod específico
en el StatefulSet.
Garantías de Despliegue y Escalado
Para un StatefulSet con N réplicas, cuando los Pods se despliegan, se crean secuencialmente, en orden de {0..N-1}.
Cuando se eliminan los Pods, se terminan en orden opuesto, de {N-1..0}.
Antes de que una operación de escalado se aplique a un Pod, todos sus predecesores deben estar Running y Ready.
Antes de que se termine un Pod, todos sus sucesores deben haberse apagado completamente.
El StatefulSet no debería tener que indicar un valor 0 para el campo pod.Spec.TerminationGracePeriodSeconds.
Esta práctica no es segura y se aconseja no hacerlo. Para una explicación más detallada, por favor echa un vistazo a cómo forzar la eliminación de Pods de un StatefulSet.
Cuando el ejemplo nginx de arriba se crea, se despliegan tres Pods en el orden
web-0, web-1, web-2. web-1 no se desplegará hasta que web-0 no esté
Running y Ready, y web-2 no se desplegará hasta que
web-1 esté Running y Ready. En caso de que web-0 fallase, después de que web-1 estuviera Running y Ready, pero antes
de que se desplegara web-2, web-2 no se desplegaría hasta que web-0 se redesplegase con éxito y estuviera
Running y Ready.
Si un usuario fuera a escalar el ejemplo desplegado parcheando el StatefulSet de forma que
replicas=1, web-2 se terminaría primero. web-1 no se terminaría hasta que web-2
no se hubiera apagado y eliminado por completo. Si web-0 fallase después de que web-2 se hubiera terminado y
apagado completamente, pero antes del término de web-1, entonces web-1 no se terminaría hasta
que web-0 estuviera Running y Ready.
Reglas de Gestión de Pods
En Kubernetes 1.7 y versiones posteriores, el StatefulSet permite flexibilizar sus garantías de ordenación
al mismo tiempo que preservar su garantía de singularidad e identidad a través del campo .spec.podManagementPolicy.
Gestión de tipo OrderedReady de Pods
La gestión de tipo OrderedReady de pods es la predeterminada para los StatefulSets. Implementa el comportamiento
descrito arriba.
Gestión de tipo Parallel de Pods
La gestión de tipo Parallel de pods le dice al controlador del StatefulSet que lance y termine
todos los Pods en paralelo, y que no espere a que los Pods estén Running
y Ready o completamente terminados antes de lanzar o terminar otro Pod.
Estrategias de Actualización
En Kubernetes 1.7 y a posteriori, el campo .spec.updateStrategy del StatefulSet permite configurar
y deshabilitar las actualizaciones automátizadas en línea para los contenedores, etiquetas, peticiones/límites de recursos,
y anotaciones de los Pods del StatefulSet.
On Delete
La estrategia de actualización OnDelete implementa el funcionamiento tradicional (1.6 y previo). Cuando el campo
.spec.updateStrategy.type de un StatefulSet se pone al valor OnDelete, el controlador del StatefulSet no actualizará automáticamente
los Pods del StatefulSet. Los usuarios deben eliminar manualmente los Pods para forzar al controlador a crear
nuevos Pods que reflejen las modificaciones hechas al campo .spec.template del StatefulSet.
Rolling Updates
La estrategia de actualización RollingUpdate implementa una actualización automatizada en línea de los Pods del
StatefulSet. Es la estrategia por defecto cuando el campo .spec.updateStrategy se deja sin valor. Cuando el campo .spec.updateStrategy.type de un StatefulSet
se pone al valor RollingUpdate, el controlador del StatefulSet lo eliminará y recreará cada Pod en el StatefulSet. Procederá
en el mismo orden en que ha terminado los Pod (del número ordinal más grande al más pequeño), actualizando
cada Pod uno por uno. Esperará a que el Pod actualizado esté Running y Ready antes de
actualizar su predecesor.
Particiones
La estrategia de actualización RollingUpdate puede particionarse, indicando el valor del campo
.spec.updateStrategy.rollingUpdate.partition. Si se indica una partición, todos los Pods con un
número ordinal mayor o igual que el de la partición serán actualizados cuando el campo .spec.template
del StatefulSet se actualice. Todos los Pods con un número ordinal que sea menor que el de la partición
no serán actualizados, e incluso si son eliminados, serán recreados con la versión anterior. Si el campo
.spec.updateStrategy.rollingUpdate.partition de un StatefulSet es mayor que el valor del campo .spec.replicas,
las modificaciones al campo .spec.template no se propagarán a sus Pods.
En la mayoría de ocasiones, no necesitarás usar una partición, pero pueden resultar útiles si quieres preparar una actualización,
realizar un despliegue tipo canary, o llevar a cabo un despliegue en fases.
Retroceso Forzado
Cuando se usa Actualizaciones en línea con el valor de la
Regla de Gestión de Pod (OrderedReady) por defecto,
es posible acabar en un estado inconsistente que requiera de una intervención manual para arreglarlo.
Si actualizas la plantilla Pod a una configuración que nunca llega a Running y
Ready (por ejemplo, debido a un binario incorrecto o un error de configuración a nivel de aplicación),
el StatefulSet detendrá el despliegue y esperará.
En este estado, no es suficiente con revertir la plantilla Pod a la configuración buena.
Debido a un problema conocido,
el StatefulSet seguirá esperando a que los Pod estropeados se pongan en Ready
(lo que nunca ocurre) antes de intentar revertirla a la configuración que funcionaba.
Antes de revertir la plantilla, debes también eliminar cualquier Pod que el StatefulSet haya
intentando ejecutar con la configuración incorrecta.
El StatefulSet comenzará entonces a recrear los Pods usando la plantilla revertida.
Un DaemonSet garantiza que todos (o algunos) de los nodos ejecuten una copia de un Pod. Conforme se añade más nodos
al clúster, nuevos Pods son añadidos a los mismos. Conforme se elimina nodos del clúster, dichos Pods se destruyen.
Al eliminar un DaemonSet se limpian todos los Pods que han sido creados.
Algunos casos de uso típicos de un DaemonSet son:
ejecutar un proceso de almacenamiento en el clúster, como glusterd, ceph, en cada nodo.
ejecutar un proceso de recolección de logs en cada nodo, como fluentd o logstash.
De forma básica, se debería usar un DaemonSet, cubriendo todos los nodos, por cada tipo de proceso.
En configuraciones más complejas se podría usar múltiples DaemonSets para un único tipo de proceso,
pero con diferentes parámetros y/o diferentes peticiones de CPU y memoria según el tipo de hardware.
Escribir una especificación de DaemonSet
Crear un DaemonSet
Un DaemonSet se describe por medio de un archivo YAML. Por ejemplo, el archivo daemonset.yaml de abajo describe un DaemonSet que ejecuta la imagen Docker de fluentd-elasticsearch:
El campo .spec.template es uno de los campos obligatorios de la sección .spec.
El campo .spec.template es una plantilla Pod. Tiene exactamente el mismo esquema que un Pod,
excepto por el hecho de que está anidado y no tiene los campos apiVersion o kind.
Además de los campos obligatorios de un Pod, la plantilla Pod para un DaemonSet debe especificar
las etiquetas apropiadas (ver selector de pod).
Una plantilla Pod para un DaemonSet debe tener una RestartPolicy
igual a Always, o no indicarse, lo cual asume por defecto el valor Always.
Selector de Pod
El campo .spec.selector es un selector de pod. Funciona igual que el campo .spec.selector
de un Job.
A partir de Kubernetes 1.8, se debe configurar un selector de pod que coincida con las
etiquetas definidas en el .spec.template. Así, el selector de pod ya no asume valores por defecto cuando no se indica.
Dichos valores por defecto no eran compatibles con kubectl apply. Además, una vez que se ha creado el DaemonSet,
su campo .spec.selector no puede alterarse porque, si fuera el caso, ello podría resultar
en Pods huérfanos, lo cual confundiría a los usuarios.
El campo .spec.selector es un objeto que, a su vez, consiste en dos campos:
matchLabels - funciona igual que el campo .spec.selector de un ReplicationController.
matchExpressions - permite construir selectores más sofisticados indicando la clave,
la lista de valores y un operador para relacionar la clave y los valores.
Cuando se configura ambos campos, el resultado es conjuntivo (AND).
Si se especifica el campo .spec.selector, entonces debe coincidir con el campo .spec.template.metadata.labels. Aquellas configuraciones que no coinciden, son rechazadas por la API.
Además, normalmente no se debería crear ningún Pod con etiquetas que coincidan con el selector, bien sea de forma directa, via otro
DaemonSet, o via otro controlador como un ReplicaSet. De ser así, el controlador del DaemonSet
pensará que dichos Pods fueron en realidad creados por él mismo. Kubernetes, en cualquier caso, no te impide realizar esta
operación. Un caso donde puede que necesites hacer esto es cuando quieres crear manualmente un Pod con un valor diferente en un nodo para pruebas.
Ejecutar Pods sólo en algunos Nodos
Si se configura un .spec.template.spec.nodeSelector, entonces el controlador del DaemonSet
creará los Pods en aquellos nodos que coincidan con el selector de nodo indicado.
De forma similar, si se configura una .spec.template.spec.affinity,
entonces el controlador del DaemonSet creará los Pods en aquellos nodos que coincidan con la afinidad de nodo indicada.
Si no se configura ninguno de los dos, entonces el controlador del DaemonSet creará los Pods en todos los nodos.
Cómo se planifican los Pods procesos
Planificados por el controlador del DaemonSet (deshabilitado por defecto a partir de 1.12)
Normalmente, el planificador de Kubernetes determina la máquina donde se ejecuta un Pod. Sin embargo, los Pods
creados por el controlador del DaemonSet ya tienen la máquina seleccionada (puesto que cuando se crea el Pod,
se indica el campo .spec.nodeName, y por ello el planificador los ignora). Por lo tanto:
El controlador del DaemonSet no tiene en cuenta el campo unschedulable de un nodo.
El controlador del DaemonSet puede crear Pods incluso cuando el planificador no ha arrancado, lo cual puede ayudar en el arranque del propio clúster.
Planificados por el planificador por defecto de Kubernetes (habilitado por defecto desde 1.12)
FEATURE STATE:Kubernetes v1.20 [beta]
Un DaemonSet garantiza que todos los nodos elegibles ejecuten una copia de un Pod.
Normalmente, es el planificador de Kubernetes quien determina el nodo donde se ejecuta un Pod. Sin embargo,
los pods del DaemonSet son creados y planificados por el mismo controlador del DaemonSet.
Esto introduce los siguientes inconvenientes:
Comportamiento inconsistente de los Pods: Los Pods normales que están esperando
a ser creados, se encuentran en estado Pending, pero los pods del DaemonSet no pasan por el estado Pending.
Esto confunde a los usuarios.
La prioridad y el comportamiento de apropiación de Pods
se maneja por el planificador por defecto. Cuando se habilita la contaminación, el controlador del DaemonSet
tomará la decisiones de planificación sin considerar ni la prioridad ni la contaminación del pod.
ScheduleDaemonSetPods permite planificar DaemonSets usando el planificador por defecto
en vez del controlador del DaemonSet, añadiendo la condición NodeAffinity
a los pods del DaemonSet, en vez de la condición .spec.nodeName. El planificador por defecto
se usa entonces para asociar el pod a su servidor destino. Si la afinidad de nodo del
pod del DaemonSet ya existe, se sustituye. El controlador del DaemonSet sólo realiza
estas operaciones cuando crea o modifica los pods del DaemonSet, y no se realizan cambios
al spec.template del DaemonSet.
Adicionalmente, se añade de forma automática la tolerancia node.kubernetes.io/unschedulable:NoSchedule
a los Pods del DaemonSet. Así, el planificador por defecto ignora los nodos
unschedulable cuando planifica los Pods del DaemonSet.
Contaminaciones (taints) y Tolerancias (tolerations)
A pesar de que los Pods de proceso respetan las
contaminaciones y tolerancias,
la siguientes tolerancias son añadidas a los Pods del DaemonSet de forma automática
según las siguientes características:
Clave de tolerancia
Efecto
Versión
Descripción
node.kubernetes.io/not-ready
NoExecute
1.13+
Los pods del DaemonSet no son expulsados cuando hay problemas de nodo como una partición de red.
node.kubernetes.io/unreachable
NoExecute
1.13+
Los pods del DaemonSet no son expulsados cuando hay problemas de nodo como una partición de red.
node.kubernetes.io/disk-pressure
NoSchedule
1.8+
Los pods del DaemonSet no son expulsados cuando hay problemas de nodo como la falta de espacio en disco.
node.kubernetes.io/memory-pressure
NoSchedule
1.8+
Los pods del DaemonSet no son expulsados cuando hay problemas de nodo como la falta de memoria.
node.kubernetes.io/unschedulable
NoSchedule
1.12+
Los pods del DaemonSet toleran los atributos unschedulable del planificador por defecto.
node.kubernetes.io/network-unavailable
NoSchedule
1.12+
Los pods del DaemonSet, que usan la red del servidor anfitrión, toleran los atributos network-unavailable del planificador por defecto.
Comunicarse con los Pods de los DaemonSets
Algunos patrones posibles para la comunicación con los Pods de un DaemonSet son:
Push: Los Pods del DaemonSet se configuran para enviar actualizaciones a otro servicio,
como una base de datos de estadísticas. No tienen clientes.
NodeIP y Known Port: Los Pods del DaemonSet pueden usar un hostPort, de forma que se les puede alcanzar via las IPs del nodo. Los clientes conocen la lista de IPs del nodo de algún modo,
y conocen el puerto acordado.
DNS: Se crea un servicio headless con el mismo selector de pod,
y entonces se descubre a los DaemonSets usando los recursos endpoints o mediante múltiples registros de tipo A en el DNS.
Service: Se crea un servicio con el mismo selector de Pod, y se usa el servicio para llegar al proceso de uno de los nodos. (No hay forma de determinar el nodo exacto.)
Actualizar un DaemonSet
Si se cambian las etiquetas de nodo, el DaemonSet comenzará de forma inmediata a añadir Pods a los nuevos nodos que coincidan y a eliminar
los Pods de aquellos nuevos nodos donde no coincidan.
Puedes modificar los Pods que crea un DaemonSet. Sin embargo, no se permite actualizar todos los campos de los Pods.
Además, el controlador del DaemonSet utilizará la plantilla original la próxima vez que se cree un nodo (incluso con el mismo nombre).
Puedes eliminar un DaemonSet. Si indicas el parámetro --cascade=false al usar kubectl,
entonces los Pods continuarán ejecutándose en los nodos. Así, puedes crear entonces un nuevo DaemonSet con una plantilla diferente.
El nuevo DaemonSet con la plantilla diferente reconocerá a todos los Pods existentes que tengan etiquetas coincidentes y
no modificará o eliminará ningún Pod aunque la plantilla no coincida con los Pods desplegados.
Entonces, deberás forzar la creación del nuevo Pod eliminando el Pod mismo o el nodo.
Aunque es perfectamente posible ejecutar procesos arrancándolos directamente en un nodo (ej. usando
init, upstartd, o systemd), existen numerosas ventajas si se realiza via un DaemonSet:
Capacidad de monitorizar y gestionar los logs de los procesos del mismo modo que para las aplicaciones.
Mismo lenguaje y herramientas de configuración (ej. plantillas de Pod, kubectl) tanto para los procesos como para las aplicaciones.
Los procesos que se ejecutan en contenedores con límitaciones de recursos aumentan el aislamiento entre dichos procesos y el resto de contenedores de aplicaciones.
Sin embargo, esto también se podría conseguir ejecutando los procesos en un contenedor en vez de un Pod
(ej. arrancarlos directamente via Docker).
Pods individuales
Es posible crear Pods directamente sin indicar el nodo donde ejecutarse. Sin embargo,
la ventaja del DaemonSet es que sustituye los Pods que se eliminan o terminan por cualquier razón, como en el caso
de un fallo del nodo o una intervención disruptiva de mantenimiento del nodo, como la actualización del kernel.
Por esta razón, deberías siempre utilizar un DaemonSet en vez de crear Pods individuales.
Pods estáticos
Es posible crear Pods a partir de archivos en el directorio donde está escuchando el proceso Kubelet.
Este tipo de Pods se denomina pods estáticos.
A diferencia del DaemonSet, los Pods estáticos no se pueden gestionar con kubectl
o cualquier otro cliente de la API de Kubernetes. Los Pods estáticos no dependen del apiserver, lo cual los hace
convenientes para el arranque inicial del clúster. Además, puede que los Pods estáticos se deprecien en el futuro.
Deployments
Los DaemonSets son similares a los Deployments en el sentido que
ambos crean Pods, y que dichos Pods tienen procesos que no se espera que terminen (ej. servidores web,
servidores de almacenamiento).
Utiliza un Deployment para definir servicios sin estado, como las interfaces de usuario, donde el escalado vertical y horizontal
del número de réplicas y las actualizaciones continuas son mucho más importantes que el control exacto del servidor donde se ejecuta el Pod.
Utiliza un DaemonSet cuando es importante que una copia de un Pod siempre se ejecute en cada uno de los nodos,
y cuando se necesite que arranque antes que el resto de Pods.
3.4.2.6 - Recolección de Basura
El papel del recolector de basura de Kubernetes es el de eliminar determinados objetos
que en algún momento tuvieron un propietario, pero que ahora ya no.
Propietarios y subordinados
Algunos objetos de Kubernetes son propietarios de otros objetos. Por ejemplo, un ReplicaSet
es el propietario de un conjunto de Pods. Los objetos que se poseen se denominan subordinados del
objeto propietario. Cada objeto subordinado tiene un campo metadata.ownerReferences
que apunta al objeto propietario.
En ocasiones, Kubernetes pone el valor del campo ownerReference automáticamente.
Por ejemplo, cuando creas un ReplicaSet, Kubernetes automáticamente pone el valor del campo
ownerReference de cada Pod en el ReplicaSet. A partir de la versión 1.8, Kubernetes
automáticamente pone el valor de ownerReference para los objetos creados o adoptados
por un ReplicationController, ReplicaSet, StatefulSet, DaemonSet, Deployment, Job
y CronJob.
También puedes configurar las relaciones entre los propietarios y sus subordinados
de forma manual indicando el valor del campo ownerReference.
Aquí se muestra un archivo de configuración para un ReplicaSet que tiene tres Pods:
No se recomienda el uso de OwnerReferences entre Namespaces por diseño. Esto quiere decir que:
Los subordinados dentro del ámbito de Namespaces sólo pueden definir propietarios en ese mismo Namespace,
y propietarios dentro del ámbito de clúster.
Los subordinados dentro del ámbito del clúster sólo pueden definir propietarios dentro del ámbito del clúster, pero no
propietarios dentro del ámbito de Namespaces.
Controlar cómo el recolector de basura elimina los subordinados
Cuando eliminas un objeto, puedes indicar si sus subordinados deben eliminarse también
de forma automática. Eliminar los subordinados automáticamente se denomina borrado en cascada. Hay dos modos de borrado en cascada: en segundo plano y en primer plano.
Si eliminas un objeto sin borrar sus subordinados de forma automática,
dichos subordinados se convierten en huérfanos.
Borrado en cascada en primer plano
En el borrado en cascada en primer plano, el objeto raíz primero entra en un estado
llamado "deletion in progress". En este estado "deletion in progress",
se cumplen las siguientes premisas:
El objeto todavía es visible a través de la API REST
Se pone el valor del campo deletionTimestamp del objeto
El campo metadata.finalizers del objeto contiene el valor "foregroundDeletion".
Una vez que se pone el estado "deletion in progress", el recolector de basura elimina
los subordinados del objeto. Una vez que el recolector de basura ha eliminado todos
los subordinados "bloqueantes" (los objetos con ownerReference.blockOwnerDeletion=true), elimina
el objeto propietario.
Cabe mencionar que usando "foregroundDeletion", sólo los subordinados con valor en
ownerReference.blockOwnerDeletion bloquean la eliminación del objeto propietario.
A partir de la versión 1.7, Kubernetes añadió un controlador de admisión
que controla el acceso de usuario cuando se intenta poner el campo blockOwnerDeletion a true
con base a los permisos de borrado del objeto propietario, de forma que aquellos subordinados no autorizados
no puedan retrasar la eliminación del objeto propietario.
Si un controlador (como un Deployment o un ReplicaSet) establece el valor del campo ownerReferences de un objeto,
se pone blockOwnerDeletion automáticamente y no se necesita modificar de forma manual este campo.
Borrado en cascada en segundo plano
En el borrado en cascada en segundo plano, Kubernetes elimina el objeto propietario
inmediatamente y es el recolector de basura quien se encarga de eliminar los subordinados en segundo plano.
Configurar la regla de borrado en cascada
Para controlar la regla de borrado en cascada, configura el campo propagationPolicy
del parámetro deleteOptions cuando elimines un objeto. Los valores posibles incluyen "Orphan",
"Foreground", o "Background".
Antes de la versión 1.9 de Kubernetes, la regla predeterminada del recolector de basura para la mayoría de controladores era orphan.
Esto incluía al ReplicationController, ReplicaSet, StatefulSet, DaemonSet, y al Deployment.
Para los tipos dentro de las versiones de grupo extensions/v1beta1, apps/v1beta1, y apps/v1beta2, a menos que
se indique de otra manera, los objetos subordinados se quedan huérfanos por defecto.
En Kubernetes 1.9, para todos los tipos de la versión de grupo apps/v1, los objetos subordinados se eliminan por defecto.
Aquí se muestra un ejemplo que elimina los subordinados en segundo plano:
kubectl también permite el borrado en cascada.
Para eliminar los subordinados automáticamente, utiliza el parámetro --cascade a true.
Usa false para subordinados huérfanos. Por defecto, el valor de --cascade
es true.
Aquí se muestra un ejemplo de huérfanos de subordinados de un ReplicaSet:
Antes de la versión 1.7, cuando se usaba el borrado en cascada con Deployments se debía usar propagationPolicy: Foreground
para eliminar no sólo los ReplicaSets creados, sino también sus Pods correspondientes. Si este tipo de propagationPolicy
no se usa, solo se elimina los ReplicaSets, y los Pods se quedan huérfanos.
Ver kubeadm/#149 para más información.
3.4.2.7 - Controlador TTL para Recursos Finalizados
FEATURE STATE:Kubernetes v1.12 [alpha]
El controlador TTL proporciona un mecanismo TTL para limitar el tiempo de vida de los objetos
de recurso que ya han terminado su ejecución. El controlador TTL sólo se ocupa de los
Jobs por el momento,
y puede que se extienda para gestionar otros recursos que terminen su ejecución,
como los Pods y los recursos personalizados.
Descargo de responsabilidad Alpha: esta característica está actualmente en versión alpha, y puede habilitarse mediante el
feature gateTTLAfterFinished.
Controlador TTL
El controlador TTL sólo soporta los Jobs por ahora. Un operador del clúster puede usar esta funcionalidad para limpiar
los Jobs terminados (bien Complete o Failed) automáticamente especificando el valor del campo
.spec.ttlSecondsAfterFinished del Job, como en este
ejemplo.
El controlador TTL asumirá que un recurso es candidato a ser limpiado
TTL segundos después de que el recurso haya terminado; dicho de otra forma, cuando el TTL haya expirado.
Cuando el controlador TTL limpia un recursos, lo elimina en cascada, esto es, borra
sus objetos subordinados juntos. Nótese que cuando se elimina un recurso,
se respetan las garantías de su ciclo de vida, como con los finalizadores.
Los segundos TTL pueden ser configurados en cualquier momento. Aquí se muestran algunos ejemplos para poner valores al campo
.spec.ttlSecondsAfterFinished de un Job:
Indicando este campo en el manifiesto de los recursos, de forma que se pueda limpiar un Job
automáticamente un tiempo después de que haya finalizado.
Haciendo que el campo de los recursos existentes, ya finalizados, adopte esta nueva característica.
Usando un mutating admission webhook
para poner el valor de este campo dinámicamente en el momento de la creación del recursos. Los administradores del clúster pueden
usar este enfoque para forzar una regla TTL para los recursos terminados.
Usando un
mutating admission webhook
para poner el valor de este campo dinámicamente después de que el recurso haya terminado,
y eligiendo diferentes valores TTL basados en los estados de los recursos, etiquetas, etc.
Advertencia
Actualizar los segundos TTL
Cabe señalar que el período TTL , ej. campo .spec.ttlSecondsAfterFinished de los Jobs,
puede modificarse después de que el recurso haya sido creado o terminado. Sin embargo, una vez
que el Job se convierte en candidato para ser eliminado (cuando el TTL ha expirado), el sistema
no garantiza que se mantendrán los Jobs, incluso si una modificación para extender el TTL
devuelve una respuesta API satisfactoria.
Diferencia horaria
Como el controlador TTL usa marcas de fecha/hora almacenadas en los recursos de Kubernetes
para determinar si el TTL ha expirado o no, esta funcionalidad es sensible a las
diferencias horarias del clúster, lo que puede provocar que el controlador TTL limpie recursos
en momentos equivocados.
En Kubernetes, se necesita ejecutar NTP en todos los nodos
(ver #6159)
para evitar este problema. Los relojes no siempre son correctos, pero la diferencia debería ser muy pequeña.
Ten presente este riesgo cuando pongas un valor distinto de cero para el TTL.
Un Job crea uno o más Pods y se asegura de que un número específico de ellos termina de forma satisfactoria.
Conforme los pods terminan satisfactoriamente, el Job realiza el seguimiento de las ejecuciones satisfactorias.
Cuando se alcanza un número específico de ejecuciones satisfactorias, la tarea (esto es, el Job) se completa.
Al eliminar un Job se eliminan los Pods que haya creado.
Un caso simple de uso es crear un objeto Job para que se ejecute un Pod de manera fiable hasta el final.
El objeto Job arrancará un nuevo Pod si el primer Pod falla o se elimina (por ejemplo
como consecuencia de un fallo de hardware o un reinicio en un nodo).
También se puede usar un Job para ejecutar múltiples Pods en paralelo.
Ejecutar un Job de ejemplo
Aquí se muestra un ejemplo de configuración de Job. Este ejemplo calcula los primeros 2000 decimales de π y los imprime por pantalla.
Tarda unos 10s en completarse.
Para ver los Pods de un Job que se han completado, usa kubectl get pods.
Para listar todos los Pods que pertenecen a un Job de forma que sea legible, puedes usar un comando como:
pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}')echo$pods
pi-aiw0a
En este caso, el selector es el mismo que el selector del Job. La opción --output=jsonpath indica un expresión
que simplemente obtiene el nombre de cada Pod en la lista devuelta.
El campo .spec.template es el único campo obligatorio de .spec.
El campo .spec.template es una plantilla Pod. Tiene exactamente el mismo esquema que un pod,
excepto por el hecho de que está anidado y no tiene el campo apiVersion o kind.
Además de los campos olbigatorios de un Pod, una plantilla Pod de un Job debe indicar las etiquetas apropiadas
(ver selector de pod) y una regla de reinicio apropiada.
Sólo se permite los valores Never o OnFailure para RestartPolicy.
Selector de Pod
El campo .spec.selector es opcional. En la práctica mayoría de los casos no deberías configurarlo.
Mira la sección sobre configurar tu propio selector de pod.
Jobs en paralelo
Hay tres tipos principales de tarea aptos para ejecutarse como un Job:
Jobs no paralelos
normalmente, sólo se arranca un Pod, a menos que el Pod falle.
el Job se completa tan pronto como su Pod termine de forma satisfactoria.
Jobs en paralelo con un cupo fijo de terminación:
se configura un valor positivo distinto de cero para el campo .spec.completions.
el Job representa la tarea en general, y se completa cuando hay una ejecución satisfactoria de un Pod por cada valor dentro del rango de 1 a .spec.completions.
no implementado todavía: A cada Pod se le pasa un índice diferenente dentro del rango de 1 a .spec.completions.
Jobs en paralelo con una cola de trabajo:
no se especifica el campo .spec.completions, por defecto .spec.parallelism.
los Pods deben coordinarse entre ellos mismos o a través de un servicio externo que determine quién debe trabajar en qué.
Por ejemplo, un Pod podría ir a buscar un lote de hasta N ítems de una cola de trabajo.
cada Pod es capaz de forma independiente de determinar si sus compañeros han terminado o no, y como consecuencia el Job entero ha terminado.
cuando cualquier Pod del Job termina con éxito, no se crean nuevos Pods.
una vez que al menos uno de los Pods ha terminado con éxito y todos los Pods han terminado, entonces el Job termina con éxito.
una vez que cualquier Pod ha terminado con éxito, ningún otro Pod debería continuar trabajando en la misma tarea o escribiendo ningún resultado. Todos ellos deberían estar en proceso de terminarse.
En un Job no paralelo, no debes indicar el valor de .spec.completions ni .spec.parallelism. Cuando ambos se dejan
sin valor, ambos se predeterminan a 1.
En un Job con cupo fijo de terminación, deberías poner el valor de .spec.completions al número de terminaciones que se necesiten.
Puedes dar un valor a .spec.parallelism, o dejarlo sin valor, en cuyo caso se predetermina a 1.
En un Job con cola de trabajo, no debes indicar el valor de .spec.completions, y poner el valor de .spec.parallelism a
un entero no negativo.
Para más información acerca de cómo usar los distintos tipos de Job, ver la sección de patrones de job.
Controlar el paralelismo
El paralelismo solicitado (.spec.parallelism) puede usar cualquier valor no negativo.
Si no se indica, se predeterminad a 1.
Si se indica como 0, entonces el Job se pausa de forma efectiva hasta que se incremente.
El paralelismo actual (número de pods ejecutándose en cada momento) puede que sea mayor o menor que el solicitado,
por los siguientes motivos:
Para los Jobs con cupo fijo de terminaciones, el número actual de pods ejecutándose en paralelo no excede el número de terminaciones pendientes.
Los valores superiores de .spec.parallelism se ignoran.
Para los Jobs con cola de trabajo, no se arranca nuevos Pods después de que cualquier Pod se haya completado -- sin embargo, se permite que se completen los Pods pendientes.
Cuando el controlador no ha tenido tiempo para reaccionar.
Cuando el controlador no pudo crear los Pods por el motivo que fuera (falta de ResourceQuota, falta de permisos, etc.),
entonces puede que haya menos pods que los solicitados.
El controlador puede que regule la creación de nuevos Pods debido al excesivo número de fallos anteriores en el mismo Job.
Cuando un Pod se para de forma controlada, lleva tiempo pararlo.
Gestionar Fallos de Pod y Contenedor
Un contenedor de un Pod puede fallar por cualquier motivo, como porque el proceso que se estaba ejecutando termina con un código de salida distinto de cero,
o porque se mató el contenedor por exceder un límite de memoria, etc. Si esto ocurre, y se tiene
.spec.template.spec.restartPolicy = "OnFailure", entonces el Pod permance en el nodo,
pero el contenedor se vuelve a ejecutar. Por lo tanto, tu aplicación debe poder gestionar el caso en que se reinicia de forma local,
o bien especificar .spec.template.spec.restartPolicy = "Never".
Ver el ciclo de vida de un pod para más información sobre restartPolicy.
Un Pod entero puede también fallar por cualquier motivo, como cuando se expulsa al Pod del nodo
(porque el nodo se actualiza, reinicia, elimina, etc.), o si un contenedor del Pod falla
cuando .spec.template.spec.restartPolicy = "Never". Cuando un Pod falla, entonces el controlador del Job
arranca un nuevo Pod. Esto quiere decir que tu aplicación debe ser capaz de gestionar el caso en que se reinicia en un nuevo pod.
En particular, debe ser capaz de gestionar los ficheros temporales, los bloqueos, los resultados incompletos, y cualquier otra dependencia
de ejecuciones previas.
Nótese que incluso si se configura .spec.parallelism = 1 y .spec.completions = 1 y
.spec.template.spec.restartPolicy = "Never", el mismo programa puede arrancarse dos veces.
Si se especifica .spec.parallelism y .spec.completions con valores mayores que 1,
entonces puede que haya múltiples pods ejecutándose a la vez. Por ello, tus pods deben tolerar la concurrencia.
Regla de retroceso de Pod por fallo
Hay situaciones en que quieres que el Job falle después de intentar ejecutarlo unas cuantas veces debido
a un error lógico en la configuración, etc.
Para hacerlo, pon el valor de .spec.backoffLimit al número de reintentos que quieres
antes de considerar el Job como fallido. El límite de retroceso se predetermina a 6.
Los Pods fallidos asociados al Job son recreados por el controlador del Job con un
retroceso exponencial (10s, 20s, 40s ...) limitado a seis minutos. El contador
de retroceso se resetea si no aparecen Pods fallidos antes del siguiente chequeo de estado del Job.
Nota: El problema #54870 todavía existe en las versiones de Kubernetes anteriores a la versión 1.12
Terminación y Limpieza de un Job
Cuando un Job se completa, ya no se crea ningún Pod, pero tampoco se elimina los Pods. Guardarlos permite
ver todavía los logs de los pods acabados para comprobar errores, avisos, o cualquier otro resultado de diagnóstico.
El objeto job también se conserva una vez que se ha completado para que se pueda ver su estado. Es decisión del usuario si elimina
los viejos jobs después de comprobar su estado. Eliminar el job con el comando kubectl (ej. kubectl delete jobs/pi o kubectl delete -f ./job.yaml).
Cuando eliminas un job usando el comando kubectl, todos los pods que creó se eliminan también.
Por defecto, un Job se ejecutará de forma ininterrumpida a menos que uno de los Pods falle, en cuyo caso el Job se fija en el valor de
.spec.backoffLimit descrito arriba. Otra forma de acabar un Job es poniéndole un vencimiento activo.
Haz esto poniendo el valor del campo .spec.activeDeadlineSeconds del Job a un número de segundos.
El campo activeDeadlineSeconds se aplica a la duración del job, independientemente de cuántos Pods se hayan creado.
Una vez que el Job alcanza activeDeadlineSeconds, se terminan todos sus Pods y el estado del Job se pone como type: Failed con reason: DeadlineExceeded.
Fíjate que el campo .spec.activeDeadlineSeconds de un Job tiene precedencia sobre el campo .spec.backoffLimit.
Por lo tanto, un Job que está reintentando uno o más Pods fallidos no desplegará nuevos Pods una vez que alcance el límite de tiempo especificado por activeDeadlineSeconds,
incluso si todavía no se ha alcanzado el backoffLimit.
Fíjate que tanto la especificación del Job como la especificación de la plantilla Pod
dentro del Job tienen un campo activeDeadlineSeconds. Asegúrate que pones el valor de este campo de forma adecuada.
Limpiar los Jobs terminados automáticamente
Normalmente, los Jobs que han terminado ya no se necesitan en el sistema. Conservarlos sólo añade
más presión al servidor API. Si dichos Jobs no se gestionan de forma directa por un controlador de más alto nivel,
como los CronJobs, los Jobs pueden
limpiarse por medio de CronJobs en base a la regla de limpieza basada en capacidad que se haya especificado.
Mecanismo TTL para Jobs terminados
FEATURE STATE:Kubernetes v1.12 [alpha]
Otra forma de limpiar los Jobs terminados (bien Complete o Failed)
de forma automática es usando un mecanismo TTL proporcionado por un
controlador TTL de recursos finalizados,
indicando el valor .spec.ttlSecondsAfterFinished del Job.
Cuando el controlador TTL limpia el Job, lo eliminará en cascada,
esto es, eliminará sus objetos subordinados, como Pods, junto con el Job. Nótese
que cuando se elimina el Job, sus garantías de ciclo de vida, como los finalizadores,
se tendrán en cuenta.
Aquí el Job pi-with-ttl será candidato a ser automáticamente eliminado, 100
segundos después de que termine.
Si el campo se pone a 0, el Job será candidato a ser automáticamente eliminado
inmediatamente después de haber terminado. Si no se pone valor al campo, este Job no será eliminado
por el controlador TTL una vez concluya.
Nótese que este mecanismo TTL está todavía en alpha, a través de la característica denominada TTLAfterFinished.
Para más información, ver la documentación del controlador TTL para
recursos terminados.
Patrones de Job
El objeto Job puede usarse para dar soporte a la ejecución fiable de Pods en paralelo. El objeto Job
no se diseñó para dar soporte a procesos paralelos estrechamente comunicados, como los que comúnmente
se encuentran en la computación científica. Eso sí, permite el proceso paralelo de un conjunto de ítems de trabajo independientes, pero relacionados entre sí.
Estos pueden ser correos a enviar, marcos a renderizar, archivos a codificar, rangos de claves en una base de datos NoSQL a escanear, y demás.
En un sistema complejo, puede haber múltiples diferentes conjuntos de ítems de trabajo. Aquí sólo se está
considerando un conjunto de ítems de trabajo que el usuario quiere gestionar de forma conjunta — un proceso por lotes.
Hay varios patrones diferentes para computación en paralelo, cada uno con sus fortalezas y sus debilidades.
Los sacrificios a tener en cuenta son:
Un objeto Job para cada ítem de trabajo vs. un objeto Job simple para todos los ítems de trabajo. El último es mejor
para grandes números de ítems de trabajo. El primero añade sobrecarga para el usuario y para el sistema
al tener que gestionar grandes números de objetos Job.
El número de pods creados es igual al número de ítems de trabajo vs. cada Pod puede procesar múltiplese ítems de trabajo.
El primero típicamente requiere menos modificaciones al código existente y a los contenedores.
El último es mejor cuanto mayor sea el número de ítems de trabajo, por las mismas razones que antes..
Varios enfoques usan una cola de trabajo. Ello requiere ejecutar un servicio de colas,
y modificaciones a las aplicaciones o contenedores existentes para que hagan uso de la cola de trabajo.
Otras estrategias son más fáciles de adaptar a una aplicación ya usando contenedores.
Los sacrificios a tener en cuenta se indican a continuación, donde las columnas 2 a 4 representan los sacrificios de arriba.
Los nombres de los patrones son también enlaces a ejemplos e información más detallada.
Cuando se especifican terminaciones con .spec.completions, cada Pod creado por el controlado del Job
tiene un specidéntico.
Esto significa que todos los pods de una tarea tendrán la misma línea de comandos y la
misma imagne, los mismo volúmenes, y (casi) las mismas variables de entorno.
Estos patrones otorgan diferentes formas de organizar los pods para que trabajen en cosas distintas.
Esta tabla muestra la configuración necesaria para .spec.parallelism y .spec.completions para cada uno de los patrones.
Aquí, T es el número de ítems de trabajo.
Normalmente, cuando creas un objeto Job, no especificas el campo .spec.selector.
La lógica por defecto del sistema añade este campo cuando se crea el Job.
Se elige un valor de selector que no se entremezcle con otras tareas.
Sin embargo, en algunos casos, puede que necesites sobreescribir este selector que se configura de forma automática.
Para ello, puedes indicar el valor de .spec.selector en el Job.
Pero ten mucho cuidado cuando lo hagas. Si configuras un selector de etiquta que no
es único para los pods de ese Job, y que selecciona Pods que no tienen que ver,
entonces estos últimos pueden ser eliminados, o este Job puede contar los otros
Pods para terminarse, o uno o ambos Jobs pueden negarse a crear Pods o ejecutarse hasta el final.
Si se elige un selector que no es único, entonces otros controladores (ej. ReplicationController)
y sus Pods puede comportarse de forma impredecibles también. Kubernetes no te impide cometer un error
especificando el .spec.selector.
Aquí se muestra un ejemplo de un caso en que puede que necesites usar esta característica.
Digamos que el Job viejo todavía está ejeuctándose. Quieres que los Pods existentes
sigan corriendo, pero quieres que el resto de los Pods que se creen
usen una plantilla pod diferente y que el Job tenga un nombre nuevo.
Como no puedes modificar el Job porque esos campos no son modificables, eliminas el Job old,
pero dejas sus pods ejecutándose mediante el comando kubectl delete jobs/old --cascade=false.
Antes de eliminarlo, apúntate el selector actual que está usando:
Entonces, creas un nuevo Job con el nombre nuevo y le configuras explícitamente el mismo selector.
Puesto que los Pods existentes tienen la etiqueta job-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002,
son controlados por el Job nuevo igualmente.
Necesitas configurar manualSelector: true en el nuevo Job, ya qye no estás usando
el selector que normalmente se genera de forma automática por el sistema.
El mismo Job nuevo tendrá un uid distinto a a8f3d00d-c6d2-11e5-9f87-42010af00002.
Poniendo manualSelector: true le dice al sistema que sabes lo que estás haciendo
y que te permita hacer este desajuste.
Alternativas
Pods simples
Cuando el nodo donde un Pod simple se estaba ejecutando se reinicia o falla, dicho pod se termina
y no será reinicado. Sin embargo, un Job creará nuevos Pods para sustituir a los que se han terminando.
Por esta razón, se recomienda que se use un Job en vez de un Pod simple, incluso si tu aplicación
sólo necesita un único Pod.
Replication Controller
Los Jobs son complementarios a los Replication Controllers.
Un Replication Controller gestiona aquellos Pods que se espera que no terminen (ej. servidores web), y un Job
gestiona aquellos Pods que se espera que terminen (ej. tareas por lotes).
Como se discutió en el Ciclo de vida de un Pod, un Jobsólo es apropiado
para aquellos pods con RestartPolicy igual a OnFailure o Never.
(Nota: Si RestartPolicy no se pone, el valor predeterminado es Always.)
Job simple arranca que arranca un controlador de Pod
Otro patrón es aquel donde un Job simple crea un Pod que, a su vez, crea otros Pods, actuando como una especie
de controlador personalizado para esos Pods. Esto da la máxima flexibilidad, pero puede que
cueste un poco más de entender y ofrece menos integración con Kubernetes.
Un ejemplo de este patrón sería un Job que arranca un Pod que ejecuta una secuencia de comandos que, a su vez,
arranca un controlador maestro de Spark (ver el ejemplo de spark),
ejecuta un manejador de spark, y a continuación lo limpia todo.
Una ventaja de este enfoque es que el proceso general obtiene la garantía del objeto Job,
además del control completo de los Pods que se crean y cómo se les asigna trabajo.
Cron Jobs
Puedes utilizar un CronJob para crear un Job que se ejecute en una hora/fecha determinadas, de forma similar
a la herramienta cron de Unix.
3.4.2.9 - CronJob
Un Cron Job ejecuta tareas, Jobs, a intervalos regulares.
Un objeto CronJob es como una línea de un archivo crontab (tabla cron). Ejecuta un trabajo de forma periódica
según un horario programado escrito en formato Cron.
Nota: Todos los horariosCronJob se basan en la zona horaria del máster donde se inicia el trabajo.
Un trabajo programado crea un objeto job como mínimo una vez por cada ejecución de su programación. Decimos "como mínimo" porque
hay determinadas circunstancias bajo las cuales dos trabajos pueden crearse, o ninguno de ellos se crea. Se intenta que estos casos sean residuales,
pero no pueden evitarse completamente. Por lo tanto, los trabajos deberían ser idempotentes, es decir, que se pueden ejecutar más de una vez con el mismo resultado.
Si el valor de startingDeadlineSeconds se establece a un valor grande o se deja sin especificar (por defecto)
y si el valor de concurrencyPolicy se establece a Allow, los trabajos siempre se ejecutarán por lo menos una vez.
Para cada CronJob, el controlador de CronJob verifica cuántas programaciones se han perdido desde la última programación hasta el momento actual.
Si hay más de 100 programaciones perdidas, entonces ya no vuelve a ejecutar el trabajo y registra el error:
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
Es importante destacar que si el campo startingDeadlineSeconds está configurado, es decir, no es nulo (nil), el controlador cuenta cuántos trabajos perdidos se produjeron desde el valor de startingDeadlineSeconds
hasta el momento actual, en vez de la última programación. Por ejemplo, si startingDeadlineSeconds es 200, el controlador cuenta cuántos trabajos perdidos se produjeron en los últimos 200 segundos.
Se cuenta un CronJob como perdido si no se ha podido crear a la hora programada. Por ejemplo, si establecemos el valor de concurrencyPolicy a Forbid y se intentó programar
un CronJob cuando otro previamente programado estaba todavía ejecutándose, entonces contará como perdido.
Por ejemplo, imagina que un CronJob se configura para programar un nuevo Job cada minuto a partir de las 08:30:00, y su campo
startingDeadlineSeconds no se configura. Si el controlador del CronJob no estuviera disponible de 08:29:00 a 10:21:00,
el trabajo no comenzaría porque el número de trabajos perdidos que se habría perdido en su programación sería superior a 100.
Para ilustrar este concepto mejor, vamos a suponer que programamos un CronJob para que ejecute un nuevo Job cada minuto comenzando a las 08:30:00, y establecemos el valor del campo
startingDeadlineSeconds a 200 segundos. Si el controlador del CronJob no se encuentra disponible
durante el mismo período que en el ejemplo anterior (08:29:00 a 10:21:00,) aún así el Job comenzará a las 10:22:00.
Esto ocurre porque el controlador en este caso comprueba cuántas programaciones perdidas ha habido en los últimos 200 segundos (esto es, 3 programaciones que no se han ejecutado), en vez de comprobarlo a partir de la última programación hasta el momento actual.
El CronJob es únicamente responsable de crear los Jobs que coinciden con su programación, y
el Job por otro lado es el responsable de gestionar los Pods que representa.
3.5 - Servicios, balanceo de carga y redes
3.6 - Almacenamiento
3.7 - Configuración
3.7.1 - ConfigMaps
Un configmap es un objeto de la API utilizado para almacenar datos no confidenciales en el formato clave-valor. Los Pods pueden utilizar los ConfigMaps como variables de entorno, argumentos de la linea de comandos o como ficheros de configuración en un Volumen.
Un ConfigMap te permite desacoplar la configuración de un entorno específico de una imagen de contenedor, así las aplicaciones son fácilmente portables.
Precaución: ConfigMap no proporciona encriptación.
Si los datos que quieres almacenar son confidenciales, utiliza un
Secret en lugar de un ConfigMap,
o utiliza otras herramientas externas para mantener los datos seguros.
Motivo
Utiliza un ConfigMap para crear una configuración separada del código de la aplicación.
Por ejemplo, imagina que estás desarrollando una aplicación que puedes correr en
tu propio equipo (para desarrollo) y en el cloud (para mantener tráfico real).
Escribes el código para configurar una variable llamada DATABASE_HOST.
En tu equipo configuras la variable con el valor localhost.
En el cloud, la configuras con referencia a un kubernetes
Service que expone el componente
de la base de datos en tu cluster.
Esto permite tener una imagen corriendo en un cloud y
tener el mismo código localmente para checkearlo si es necesario.
Objeto ConfigMap
Un ConfigMap es un objeto de la API
que permite almacenar la configuración de otros objetos utilizados. Aunque muchos
objetos de kubernetes que tienen un spec, un ConfigMap tiene una sección data para
almacenar items, identificados por una clave, y sus valores.
Puedes escribir un Pod spec y referenciarlo a un ConfigMap y configurar el contenedor(es)
de ese Pod en base a los datos del ConfigMap. El Pod y el ConfigMap deben estar en
el mismo Namespace.
Este es un ejemplo de ConfigMap que tiene algunas claves con un valor simple,
y otras claves donde el valor tiene un formato de un fragmento de configuración.
apiVersion:v1kind:ConfigMapmetadata:name:game-demodata:# property-like keys; each key maps to a simple valueplayer_initial_lives:"3"ui_properties_file_name:"user-interface.properties"## file-like keysgame.properties:| enemy.types=aliens,monsters
player.maximum-lives=5user-interface.properties:| color.good=purple
color.bad=yellow
allow.textmode=true
Hay cuatro maneras diferentes de usar un ConfigMap para configurar
un contenedor dentro de un Pod:
Argumento en la linea de comandos como entrypoint de un contenedor
Variable de enorno de un contenedor
Como fichero en un volumen de solo lectura, para que lo lea la aplicación
Escribir el código para ejecutar dentro de un Pod que utiliza la API para leer el ConfigMap
Estos diferentes mecanismos permiten utilizar diferentes métodos para modelar
los datos que se van a usar.
Para los primeros tres mecanismos, el
kubelet utiliza la información
del ConfigMap cuando lanza un contenedor (o varios) en un Pod.
Para el cuarto método, tienes que escribir el código para leer el ConfigMap y sus datos.
Sin embargo, como estás utilizando la API de kubernetes directamente, la aplicación puede
suscribirse para obtener actualizaciones cuando el ConfigMap cambie, y reaccionar
cuando esto ocurra. Accediendo directamente a la API de kubernetes, esta
técnica también permite acceder al ConfigMap en diferentes namespaces.
En el siguiente ejemplo el Pod utiliza los valores de game-demo para configurar el contenedor:
apiVersion:v1kind:Podmetadata:name:configmap-demo-podspec:containers:- name:demoimage:game.example/demo-gameenv:# Define the environment variable- name:PLAYER_INITIAL_LIVES# Notice that the case is different here# from the key name in the ConfigMap.valueFrom:configMapKeyRef:name:game-demo # The ConfigMap this value comes from.key:player_initial_lives# The key to fetch.- name:UI_PROPERTIES_FILE_NAMEvalueFrom:configMapKeyRef:name:game-demokey:ui_properties_file_namevolumeMounts:- name:configmountPath:"/config"readOnly:truevolumes:# You set volumes at the Pod level, then mount them into containers inside that Pod- name:configconfigMap:# Provide the name of the ConfigMap you want to mount.name:game-demo# An array of keys from the ConfigMap to create as filesitems:- key:"game.properties"path:"game.properties"- key:"user-interface.properties"path:"user-interface.properties"
Un ConfigMap no diferencia entre las propiedades de una linea individual y
un fichero con múltiples lineas y valores.
Lo importante es como los Pods y otros objetos consumen estos valores.
Para este ejemplo, definimos un Volumen y lo montamos dentro del contenedor
demo como /config creando dos ficheros,
/config/game.properties y /config/user-interface.properties,
aunque haya cuatro claves en el ConfigMap. Esto es debido a que enla definición
del Pod se especifica el array items en la sección volumes.
Si quieres omitir el array items entero, cada clave del ConfigMap se convierte en
un fichero con el mismo nombre que la clave, y tienes 4 ficheros.
Usando ConfigMaps
Los ConfigMaps pueden montarse como volúmenes. También pueden ser utilizados por otras
partes del sistema, sin ser expuestos directamente al Pod. Por ejemplo,
los ConfigMaps pueden contener información para que otros elementos del sistema utilicen
para su configuración.
Nota:
La manera más común de usar los Configmaps es para configurar
los contenedores que están corriendo en un Pod en el mismo Namespace.
También se pueden usar por separado.
Por ejemplo,
quizá encuentres AddOns
u Operadores que
ajustan su comportamiento en base a un ConfigMap.
Crear un ConfigMap o usar uno que exista. Múltiples Pods pueden utilizar el mismo ConfigMap.
Modifica la configuración del Pod para añadir el volumen en .spec.volumes[]. Pon cualquier nombre al Volumen, y tienes un campo .spec.volumes[].configMap.name configurado con referencia al objeto ConfigMap.
Añade un .spec.containers[].volumeMounts[] a cada contenedor que necesite el ConfigMap. Especifica .spec.containers[].volumeMounts[].readOnly = true y .spec.containers[].volumeMounts[].mountPath en un directorio sin uso donde quieras que aparezca el ConfigMap.
Modifica la imagen o el comando utilizado para que el programa busque los ficheros en el directorio. Cada clave del ConfigMap data se convierte en un un fichero en el mountPath.
En este ejemplo, el Pod monta un ConfigMap como un volumen:
Cada ConfigMap que quieras utilizar debe estar referenciado en .spec.volumes.
Si hay múltiples contenedores en el Pod, cada contenedor tiene su propio
bloque volumeMounts, pero solo un .spec.volumes es necesario por cada ConfigMap.
ConfigMaps montados son actualizados automáticamente
Cuando un ConfigMap está siendo utilizado en un volumen y es actualizado, las claves son actualizadas también.
El kubelet comprueba si el ConfigMap montado está actualizado cada periodo de sincronización.
Sin embargo, el kubelet utiliza su caché local para obtener el valor actual del ConfigMap.
El tipo de caché es configurable usando el campo ConfigMapAndSecretChangeDetectionStrategy en el
KubeletConfiguration struct.
Un ConfigMap puede ser propagado por vista (default), ttl-based, o simplemente redirigiendo
todas las consultas directamente a la API.
Como resultado, el retraso total desde el momento que el ConfigMap es actualizado hasta el momento
que las nuevas claves son proyectadas en el Pod puede ser tan largo como la sincronización del Pod
el retraso de propagación de la caché, donde la propagación de la caché depende del tipo de
caché elegido (es igual al retraso de propagación, ttl de la caché, o cero correspondientemente).
FEATURE STATE:Kubernetes v1.18 [alpha]
La característica alpha de kubernetes Immutable Secrets and ConfigMaps provee una opción para configurar
Secrets individuales y ConfigMaps como inmutables. Para los Clústeres que usan ConfigMaps como extensión
(al menos decenas o cientos de un único ConfigMap montado en Pods), previene cambios en sus
datos con las siguientes ventajas:
protección de actualizaciones accidentales (o no deseadas) que pueden causar caídas de aplicaciones
mejora el rendimiento del Clúster significativamente reduciendo la carga del kube-apiserver,
cerrando las vistas para el ConfigMap marcado como inmutable.
Para usar esta característica, habilita el ImmutableEmphemeralVolumesfeature gate y configura
el campo del Secret o ConfigMap immutable como true. Por ejemplo:
Nota: Una vez que un ConfigMap o un Secret es marcado como inmutable, no es posible revertir el cambio
ni cambiar el contenido del campo data. Solo se puede eliminar y recrear el ConfigMap.
Los Pods existentes mantiene un punto de montaje del ConfigMap eliminado - es recomendable
recrear los Pods.
Leer The Twelve-Factor App para entender el motivo de separar
el código de la configuración.
3.7.2 - Sobrecarga de Pod
FEATURE STATE:Kubernetes v1.16 [alpha]
Cuando se está ejecutando un Pod en un nodo, el Pod por sí mismo utiliza una cantidad de recursos del sistema. Estos recursos son adicionales a los recursos necesarios para hacer funcionar el/los contenedor(es) dentro del Pod.
La Sobrecarga de Pod es una característica para contabilizar los recursos consumidos por la infraestructura de Pods que están por encima de los valores de Requests y Limits del/los contenedor(es).
Sobrecarga de Pod
En Kubernetes, la sobrecarga de Pod se configura en el tiempo de admisión con respecto a la sobrecarga asociada con el RuntimeClass del Pod.
Cuando se habilita la opción de sobrecarga de Pod, se considera tanto la propia sobrecarga como la suma de solicitudes de recursos del contenedor al programar el Pod. Del mismo modo, Kubelet incluirá la sobrecarga de Pod cuando se dimensione el cgroup del Pod, y cuando se realice la clasificación de la expulsión de Pods.
Configuración
Debe asegurarse de que el Feature GatePodOverhead esté activado (su valor está desactivado de manera predeterminada) en todo el clúster. Esto significa:
en cualquier servidor de API personalizado que necesite Feature Gates.
Nota: Los usuarios que pueden escribir recursos del tipo RuntimeClass podrían impactar y poner en riesgo el rendimiento de la carga de trabajo en todo el clúster. Por ello, se puede limitar el acceso a esta característica usando los controles de acceso de Kubernetes.
Para obtener más detalles vea la documentación sobre autorización.
3.7.3 - Administrando los recursos de los contenedores
Cuando especificas un Pod, opcionalmente puedes especificar
los recursos que necesita un Contenedor.
Los recursos que normalmente se definen son CPU y memoria (RAM); pero hay otros.
Cuando especificas el recurso request para Contenedores en un Pod,
el Scheduler de Kubernetes usa esta información para decidir en qué nodo colocar el Pod.
Cuando especificas el recurso limit para un Contenedor, Kubelet impone estos límites, así que el contenedor no
puede utilizar más recursos que el límite que le definimos. Kubelet también reserva al menos la cantidad
especificada en request para el contenedor.
Peticiones y límites
Si el nodo donde está corriendo un pod tiene suficientes recursos disponibles, es posible
(y válido) que el contenedor utilice más recursos de los especificados en request.
Sin embargo, un contenedor no está autorizado a utilizar más de lo especificado en limit.
Por ejemplo, si configuras una petición de memory de 256 MiB para un contenedor, y ese contenedor está
en un Pod colocado en un nodo con 8GiB de memoria y no hay otros Pod, entonces el contenedor puede intentar usar
más RAM.
Si configuras un límite de memory de 4GiB para el contenedor, kubelet)
(y
motor de ejecución del contenedor) impone el límite.
El Runtime evita que el contenedor use más recursos de los configurados en el límite. Por ejemplo:
cuando un proceso en el contenedor intenta consumir más cantidad de memoria de la permitida,
el Kernel del sistema termina el proceso que intentó la utilización de la memoria, con un error de out of memory (OOM).
Los límites se pueden implementar de forma reactiva (el sistema interviene cuando ve la violación)
o por imposición (el sistema previene al contenedor de exceder el límite). Diferentes Runtimes pueden tener distintas
implementaciones a las mismas restricciones.
Nota: Si un contenedor especifica su propio límite de memoria, pero no especifica la petición de memoria, Kubernetes
automáticamente asigna una petición de memoria igual a la del límite. De igual manera, si un contenedor especifica su propio límite de CPU, pero no especifica una petición de CPU, Kubernetes automáticamente asigna una petición de CPU igual a la especificada en el límite.
Tipos de recursos
CPU y memoria son cada uno un tipo de recurso. Un tipo de recurso tiene una unidad base.
CPU representa procesos de computación y es especificada en unidades de Kubernetes CPUs.
Memoria es especificada en unidades de bytes.
Si estás usando Kubernetes v1.14 o posterior, puedes especificar recursos huge page.
Huge pages son una característica de Linux específica donde el kernel del nodo asigna bloques
de memoria que son más grandes que el tamaño de paginación por defecto.
Por ejemplo, en un sistema donde el tamaño de paginación por defecto es de 4KiB, podrías
especificar un límite, hugepages-2Mi: 80Mi. Si el contenedor intenta asignar
más de 40 2MiB huge pages (un total de 80 MiB), la asignación fallará.
Nota: No se pueden sobreasignar recursos hugepages-*.
A diferencia de los recursos de memoria y cpu.
CPU y memoria son colectivamente conocidos como recursos de computación, o simplemente como
recursos. Los recursos de computación son cantidades medibles que pueden ser solicitadas, asignadas
y consumidas. Son distintas a los Recursos API. Los recursos API , como Pods y
Services son objetos que pueden ser leídos y modificados
a través de la API de Kubernetes.
Peticiones y límites de recursos de Pods y Contenedores
Cada contenedor de un Pod puede especificar uno o más de los siguientes:
Aunque las peticiones y límites pueden ser especificadas solo en contenedores individuales, es conveniente hablar
sobre los recursos de peticiones y límites del Pod. Un limite/petición
de recursos de un Pod para un tipo de recurso particular es la suma de
peticiones/límites de cada tipo para cada contenedor del Pod.
Unidades de recursos en Kubernetes
Significado de CPU
Límites y peticiones para recursos de CPU son medidos en unidades de cpu.
Una cpu, en Kubernetes, es equivalente a 1 vCPU/Core para proveedores de cloud y 1 hyperthread en procesadores bare-metal Intel.
Las peticiones fraccionadas están permitidas. Un contenedor con spec.containers[].resources.requests.cpu de 0.5 tiene garantizada la mitad, tanto
CPU como otro que requiere 1 CPU. La expresión 0.1 es equivalente a la expresión 100m, que puede ser leída como "cien millicpus". Algunas personas dicen
"cienmilicores", y se entiende que quiere decir lo mismo. Una solicitud con un punto decimal, como 0.1, es convertido a 100m por la API, y no se permite
una precisión mayor que 1m. Por esta razón, la forma 100m es la preferente.
CPU es siempre solicitada como una cantidad absoluta, nunca como una cantidad relativa;
0.1 es la misma cantidad de cpu que un core-simple, dual-core, o máquina de 48-core.
Significado de memoria
Los límites y peticiones de memoria son medidos en bytes. Puedes expresar la memoria como
un número entero o como un número decimal usando alguno de estos sufijos:
E, P, T, G, M, K. También puedes usar los equivalentes en potencia de dos: Ei, Pi, Ti, Gi,
Mi, Ki. Por ejemplo, los siguientes valores representan lo mismo:
128974848, 129e6, 129M, 123Mi
Aquí un ejemplo.
El siguiente Pod tiene dos contenedores. Cada contenedor tiene una petición de 0.25 cpu
y 64MiB (226 bytes) de memoria. Cada contenedor tiene un límite de 0.5 cpu
y 128MiB de memoria. Puedes decirle al Pod que solicite 0.5 cpu y 128MiB de memoria
y un límite de 1 cpu y 256MiB de memoria.
Cómo son programados los Pods con solicitudes de recursos
Cuando creas un Pod, el planificador de Kubernetes determina el nodo para correr dicho Pod.
Cada nodo tiene una capacidad máxima para cada tipo de recurso:
la cantidad de CPU y memoria que dispone para los Pods. El planificador de Kubernetes se asegura de que,
para cada tipo de recurso, la suma de los recursos solicitados de los contenedores programados sea menor a la capacidad del nodo. Cabe mencionar que aunque la memoria actual o CPU
en uso de los nodos sea muy baja, el planificador todavía rechaza programar un Pod en un nodo si
la comprobación de capacidad falla. Esto protege contra escasez de recursos en un nodo
cuando el uso de recursos posterior crece, por ejemplo, durante un pico diario de
solicitud de recursos.
El spec.containers[].resources.requests.cpu es convertido a su valor interno,
el cuál es fraccional, y multiplicado por 1024. El mayor valor de este número o
2 es usado por el valor de
--cpu-shares
en el comando docker run.
El spec.containers[].resources.limits.cpu se convierte a su valor en milicore y
multiplicado por 100. El resultado es el tiempo total de CPU que un contenedor puede usar
cada 100ms. Un contenedor no puede usar más tiempo de CPU que del solicitado durante este intervalo.
Nota: El período por defecto es de 100ms. La resolución mínima de cuota mínima es 1ms.
El spec.containers[].resources.limits.memory se convierte a entero, y
se usa como valor de
--memory
del comando docker run.
Si el contenedor excede su límite de memoria, este quizá se detenga. Si es reiniciable,
el kubelet lo reiniciará, así como cualquier otro error.
Si un Contenedor excede su petición de memoria, es probable que ese Pod sea
desalojado en cualquier momento que el nodo se quede sin memoria.
Un Contenedor puede o no tener permitido exceder el límite de CPU por
algunos períodos de tiempo. Sin embargo, esto no lo destruirá por uso excesivo de CPU.
Para conocer cuando un Contenedor no puede ser programado o será destruido debido a
límite de recursos, revisa la sección de Troubleshooting.
Monitorización del uso de recursos de computación y memoria.
El uso de recursos de un Pod es reportado como parte del estado del Pod.
Los nodos tienen almacenamiento local efímero, respaldado por
dispositivos de escritura agregados o, a veces, por RAM.
"Efímero" significa que no se garantiza la durabilidad a largo plazo.
.
Los Pods usan el almacenamiento local efímero para añadir espacio, caché, y para logs.
Kubelet puede proveer espacio añadido a los Pods usando almacenamiento local efímero para
montar emptyDirvolumes en los contenedores.
Kubelet también usa este tipo de almacenamiento para guardar
logs de contenedores a nivel de nodo,
imágenes de contenedores, y la capa de escritura de los contenedores.
Precaución: Si un nodo falla, los datos en el almacenamiento efímero se pueden perder.
Tus aplicaciones no pueden esperar ningun SLA (IOPS de disco, por ejemplo)
del almacenamiento local efímero.
Como característica beta, Kubernetes te deja probar, reservar y limitar la cantidad
de almacenamiento local efímero que un Pod puede consumir.
Configuraciones para almacenamiento local efímero
Kubernetes soporta 2 maneras de configurar el almacenamiento local efímero en un nodo:
En esta configuración, colocas todos los tipos de datos (emptyDir volúmenes, capa de escritura,
imágenes de contenedores, logs) en un solo sistema de ficheros.
La manera más efectiva de configurar Kubelet es dedicando este sistema de archivos para los datos de Kubernetes (kubelet).
Kubelet escribe logs en ficheros dentro del directorio de logs (por defecto /var/log
); y tiene un directorio base para otros datos almacenados localmente
(/var/lib/kubelet por defecto).
Por lo general, /var/lib/kubelet y /var/log están en el sistema de archivos de root,
y Kubelet es diseñado con ese objetivo en mente.
Tu nodo puede tener tantos otros sistema de archivos, no usados por Kubernetes,
como quieras.
Tienes un sistema de archivos en el nodo que estás usando para datos efímeros que
provienen de los Pods corriendo: logs, y volúmenes emptyDir.
Puedes usar este sistema de archivos para otros datos (por ejemplo: logs del sistema no relacionados
con Kubernetes); estos pueden ser incluso del sistema de archivos root.
Kubelet también escribe
logs de contenedores a nivel de nodo
en el primer sistema de archivos, y trata estos de manera similar al almacenamiento efímero.
También usas un sistema de archivos distinto, respaldado por un dispositivo de almacenamiento lógico diferente.
En esta configuración, el directorio donde le dices a Kubelet que coloque
las capas de imágenes de los contenedores y capas de escritura es este segundo sistema de archivos.
El primer sistema de archivos no guarda ninguna capa de imágenes o de escritura.
Tu nodo puede tener tantos sistemas de archivos, no usados por Kubernetes, como quieras.
Kubelet puede medir la cantidad de almacenamiento local que se está usando. Esto es posible por:
el LocalStorageCapacityIsolationfeature gate
está habilitado (esta caracterísitca está habilitada por defecto), y
has configurado el nodo usando una de las configuraciones soportadas
para almacenamiento local efímero..
Si tienes una configuración diferente, entonces Kubelet no aplica límites de recursos
para almacenamiento local efímero.
Nota: Kubelet rastrea tmpfs volúmenes emptyDir como uso de memoria de contenedor, en lugar de
almacenamiento local efímero.
Configurando solicitudes y límites para almacenamiento local efímero
Puedes usar ephemeral-storage para manejar almacenamiento local efímero. Cada contenedor de un Pod puede especificar
uno o más de los siguientes:
Los límites y solicitudes para almacenamiento-efímero son medidos en bytes. Puedes expresar el almacenamiento
como un numero entero o flotante usando los siguientes sufijos:
E, P, T, G, M, K. También puedes usar las siguientes equivalencias: Ei, Pi, Ti, Gi,
Mi, Ki. Por ejemplo, los siguientes representan el mismo valor:
128974848, 129e6, 129M, 123Mi
En el siguiente ejemplo, el Pod tiene dos contenedores. Cada contenedor tiene una petición de 2GiB de almacenamiento local efímero. Cada
contenedor tiene un límite de 4GiB de almacenamiento local efímero. Sin embargo, el Pod tiene una petición de 4GiB de almacenamiento efímero
, y un límite de 8GiB de almacenamiento local efímero.
Como son programados los Pods con solicitudes de almacenamiento efímero
Cuando creas un Pod, el planificador de Kubernetes selecciona un nodo para el Pod donde sera creado.
Cada nodo tiene una cantidad máxima de almacenamiento local efímero que puede proveer a los Pods. Para
más información, mira Node Allocatable.
El planificador se asegura de que el total de los recursos solicitados para los contenedores sea menor que la capacidad del nodo.
Manejo del consumo de almacenamiento efímero
Si Kubelet está manejando el almacenamiento efímero local como un recurso, entonces
Kubelet mide el uso de almacenamiento en:
Si un Pod está usando más almacenamiento efímero que el permitido, Kubelet
establece una señal de desalojo que desencadena el desalojo del Pod.
Para aislamiento a nivel de contenedor, si una capa de escritura del contenedor y
logs excede el límite de uso del almacenamiento, Kubelet marca el Pod para desalojo.
Para aislamiento a nivel de Pod, Kubelet calcula un límite de almacenamiento
general para el Pod sumando los límites de los contenedores de ese Pod.
En este caso, si la suma del uso de almacenamiento local efímero para todos los contenedores
y los volúmenes emptyDir de los Pods excede el límite de almacenamiento general del
Pod, Kubelet marca el Pod para desalojo.
Precaución:
Si Kubelet no está midiendo el almacenamiento local efímero, entonces el Pod
que excede este límite de almacenamiento, no será desalojado para liberar
el límite del recurso de almacenamiento.
Sin embargo, si el espacio del sistema de archivos para la capa de escritura del contenedor,
logs a nivel de nodo o volúmenes emptyDir decae, el
taints del nodo lanza la desalojo para
cualquier Pod que no tolere dicho taint.
Kubelet realiza frecuentemente, verificaciones programadas que revisan cada
volumen emptyDir, directorio de logs del contenedor, y capa de escritura
del contenedor.
El escáner mide cuanto espacio está en uso.
Nota:
En este modo, Kubelet no rastrea descriptores de archivos abiertos
para archivos eliminados.
Si tú (o un contenedor) creas un archivo dentro de un volumen emptyDir,
y algo mas abre ese archivo, y tú lo borras mientras este está abierto,
entonces el inodo para este archivo borrado se mantiene hasta que cierras
el archivo, pero Kubelet no cataloga este espacio como en uso.
FEATURE STATE:Kubernetes v1.15 [alpha]
Las cuotas de proyecto están definidas a nivel de sistema operativo
para el manejo de uso de almacenamiento en uso de sistema de archivos.
Con Kubernetes, puedes habilitar las cuotas de proyecto para el uso
de la monitorización del almacenamiento. Asegúrate que el respaldo del
Sistema de archivos de los volúmenes emptyDir , en el nodo, provee soporte de
cuotas de proyecto.
Por ejemplo, XFS y ext4fs ofrecen cuotas de proyecto.
Nota: Las cuotas de proyecto te permiten monitorear el uso del almacenamiento; no
fuerzan los límites.
Kubernetes usa IDs de proyecto empezando por 1048576. Los IDs en uso
son registrados en /etc/projects y /etc/projid. Si los IDs de proyecto
en este rango son usados para otros propósitos en el sistema, esos IDs
de proyecto deben ser registrados en /etc/projects y /etc/projid para
que Kubernetes no los use.
Las cuotas son más rápidas y más precisas que el escáner de directorios.
Cuando un directorio es asignado a un proyecto, todos los ficheros creados
bajo un directorio son creados en ese proyecto, y el kernel simplemente
tiene que mantener rastreados cuántos bloques están en uso por ficheros
en ese proyecto. Si un fichero es creado y borrado, pero tiene un fichero abierto,
continúa consumiendo espacio. El seguimiento de cuotas registra ese espacio
con precisión mientras que los escaneos de directorios pasan por alto
el almacenamiento utilizado por los archivos eliminados
Si quieres usar cuotas de proyecto, debes:
Habilitar el LocalStorageCapacityIsolationFSQuotaMonitoring=truefeature gate
en la configuración del kubelet.
Asegúrese de que el sistema de archivos raíz (o el sistema de archivos en tiempo de ejecución opcional)
tiene las cuotas de proyectos habilitadas. Todos los sistemas de archivos XFS admiten cuotas de proyectos.
Para los sistemas de archivos ext4, debe habilitar la función de seguimiento de cuotas del proyecto
mientras el sistema de archivos no está montado.
# For ext4, with /dev/block-device not mounted
sudo tune2fs -O project -Q prjquota /dev/block-device
Asegúrese de que el sistema de archivos raíz (o el sistema de archivos de tiempo de ejecución opcional) esté
montado con cuotas de proyecto habilitadas. Tanto para XFS como para ext4fs, la opción de montaje
se llama prjquota.
Recursos extendidos
Los recursos extendidos son nombres de recursos calificados fuera del
dominio kubernetes.io. Permiten que los operadores de clústers publiciten y los usuarios
consuman los recursos no integrados de Kubernetes.
Hay dos pasos necesarios para utilizar los recursos extendidos. Primero, el operador del clúster
debe anunciar un Recurso Extendido. En segundo lugar, los usuarios deben solicitar
el Recurso Extendido en los Pods.
Manejando recursos extendidos
Recursos extendido a nivel de nodo
Los recursos extendidos a nivel de nodo están vinculados a los nodos
Device plugin managed resources
Mira Plugins de
Dispositivos
para percibir como los plugins de dispositivos manejan los recursos
en cada nodo.
Otros recursos
Para anunciar un nuevo recurso extendido a nivel de nodo, el operador del clúster puede
enviar una solicitud HTTP PATCH al servidor API para especificar la cantidad
disponible en el status.capacity para un nodo en el clúster. Después de esta
operación, el status.capacity del nodo incluirá un nuevo recurso. El campo
status.allocatable se actualiza automáticamente con el nuevo recurso
de forma asíncrona por el kubelet. Tenga en cuenta que debido a que el planificador
utiliza el valor de status.allocatable del nodo cuando evalúa la aptitud del Pod, puede haber un breve
retraso entre parchear la capacidad del nodo con un nuevo recurso y el primer Pod
que solicita el recurso en ese nodo.
Ejemplo:
Aquí hay un ejemplo que muestra cómo usar curl para formar una solicitud HTTP que
anuncia cinco recursos "example.com/foo" en el nodo k8s-node-1 cuyo nodo master
es k8s-master.
Nota: En la solicitud anterior, ~ 1 es la codificación del carácter/
en la ruta del parche. El valor de la ruta de operación en JSON-Patch se interpreta como un
puntero JSON. Para obtener más detalles, consulte
IETF RFC 6901, sección 3.
Recursos extendidos a nivel de Clúster
Los recursos extendidos a nivel de clúster no están vinculados a los nodos. Suelen estar gestionados
por extensores del scheduler, que manejan el consumo de recursos y la cuota de recursos.
La siguiente configuración para una política del scheduler indica que el
recurso extendido a nivel de clúster "example.com/foo" es mantenido
por el extensor del scheduler.
El scheduler envía un Pod al extensor del scheduler solo si la solicitud del Pod "example.com/foo".
El campo ignoredByScheduler especifica que el schduler no compruba el recurso
"example.com/foo" en su predicado PodFitsResources.
Los usuarios pueden consumir recursos extendidos en las especificaciones del Pod, como la CPU y la memoria.
El planificador se encarga de la contabilidad de recursos para que no más de
la cantidad disponible sea asignada simultáneamente a los Pods.
El servidor de API restringe las cantidades de recursos extendidos a números enteros.
Ejemplos de cantidades validas son 3, 3000m y 3Ki. Ejemplos de
cantidades no válidas son 0.5 y 1500m.
Nota: Los recursos extendidos reemplazan los Recursos Integrales Opacos.
Los usuarios pueden usar cualquier otro prefijo de dominio que kubernetes.io
tenga reservado.
Para consumir un recurso extendido en un Pod, incluye un nombre de recurso
como clave en spec.containers[].resources.limits en las especificaciones del contenedor.
Nota: Los Recursos Extendidos no pueden ser sobreescritos, así que solicitudes y límites
deben ser iguales si ambos están presentes en las especificaciones de un contenedor.
Un pod se programa solo si se satisfacen todas las solicitudes de recursos, incluidas
CPU, memoria y cualquier recurso extendido. El Pod permanece en estado PENDING
siempre que no se pueda satisfacer la solicitud de recursos.
Ejemplo:
El siguiente Pod solicita 2CPUs y 1 "example.com/foo" (un recurso extendido).
Mis Pods están en estado pendiente con un mensaje de failedScheduling
Si el planificador no puede encontrar ningún nodo donde pueda colocar un Pod, el Pod permanece
no programado hasta que se pueda encontrar un lugar. Se produce un evento cada vez que
el planificador no encuentra un lugar para el Pod, como este:
kubectl describe pod frontend | grep -A 3 Events
Events:
FirstSeen LastSeen Count From Subobject PathReason Message
36s 5s 6 {scheduler } FailedScheduling Failed for reason PodExceedsFreeCPU and possibly others
En el ejemplo anterior, el Pod llamado "frontend" no se puede programar debido a
recursos de CPU insuficientes en el nodo. Mensajes de error similares también pueden sugerir
fallo debido a memoria insuficiente (PodExceedsFreeMemory). En general, si un Pod
está pendiente con un mensaje de este tipo, hay varias cosas para probar:
Añadir más nodos al clúster.
Terminar Pods innecesarios para hacer hueco a los Pods en estado pendiente.
Compruebe que el Pod no sea más grande que todos los nodos. Por ejemplo, si todos los
los nodos tienen una capacidad de cpu: 1, entonces un Pod con una solicitud de cpu: 1.1
nunca se programará.
Puedes comprobar las capacidades del nodo y cantidad utilizada con el comando
kubectl describe nodes. Por ejemplo:
EN la salida anterior, puedes ver si una solicitud de Pod mayor que 1120m
CPUs o 6.23Gi de memoria, no cabrán en el nodo.
Echando un vistazo a la sección Pods, puedes ver qué Pods están ocupando espacio
en el nodo.
La cantidad de recursos disponibles para los pods es menor que la capacidad del nodo, porque
los demonios del sistema utilizan una parte de los recursos disponibles. El campo allocatableNodeStatus
indica la cantidad de recursos que están disponibles para los Pods. Para más información, mira
Node Allocatable Resources.
La característica resource quota se puede configurar
para limitar la cantidad total de recursos que se pueden consumir. Si se usa en conjunto
con espacios de nombres, puede evitar que un equipo acapare todos los recursos.
Mi contenedor está terminado
Es posible que su contenedor se cancele porque carece de recursos. Para verificar
si un contenedor está siendo eliminado porque está alcanzando un límite de recursos, ejecute
kubectl describe pod en el Pod de interés:
kubectl describe pod simmemleak-hra99
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
Labels: name=simmemleak
Status: Running
Reason:
Message:
IP: 10.244.2.75
Replication Controllers: simmemleak (1/1 replicas created)
Containers:
simmemleak:
Image: saadali/simmemleak
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2015 12:54:41 -0700
Last Termination State: Terminated
Exit Code: 1
Started: Fri, 07 Jul 2015 12:54:30 -0700
Finished: Fri, 07 Jul 2015 12:54:33 -0700
Ready: False
Restart Count: 5
Conditions:
Type Status
Ready False
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {scheduler } scheduled Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD pulled Pod container image "k8s.gcr.io/pause:0.8.0" already present on machine
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD created Created with docker id 6a41280f516d
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD started Started with docker id 6a41280f516d
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} spec.containers{simmemleak} created Created with docker id 87348f12526a
En el ejemplo anterior, Restart Count: 5 indica que el contenedor simmemleak
del Pod se reinició cinco veces.
Puedes ejecutar kubectl get pod con la opción -o go-template=... para extraer el estado
previos de los Contenedores terminados:
kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-hra99
Los objetos de tipo Secret en Kubernetes te permiten almacenar y administrar información confidencial, como
contraseñas, tokens OAuth y llaves ssh. Poniendo esta información en un Secret
es más seguro y más flexible que ponerlo en la definición de un Pod o en un container image. Ver Secrets design document para más información.
Introducción a Secrets
Un Secret es un objeto que contiene una pequeña cantidad de datos confidenciales como contraseñas, un token, o una llave. Tal información podría ser puesta en la especificación de un Pod o en una imagen; poniendolo en un objeto de tipo Secret permite mayor control sobre como se usa, y reduce el riesgo de exposicición accidental.
Los usuarios pueden crear Secrets, y el sistema también puede crearlos.
Para usar un Secret, un Pod debe hacer referencia a este. Un Secret puede ser usado con un Pod de dos formas: como archivos en un volume montado en uno o más de sus contenedores, o utilizados por el kubelet al extraer imágenes del pod.
Secrets incorporados
Las Cuentas de Servicio Crean y Adjuntan Secrets con las Credenciales de la API
Kubernetes crea automaticamente Secrets que contienen credenciales para acceder a la API y modifica automáticamente sus pods para usar este tipo de Secret.
La creación y el uso automático de las credenciales de la API, pueden desabilitarse o anularse si se desea. Sin embargo, si todo lo que necesita hacer es acceder de forma segura al apiserver, este es el flujo de trabajo recomendado.
Ver la documentación de Service Account para más información sobre cómo funcionan las Cuentas de Servicio.
Creando tu propio Secret
Creando un Secret Usando kubectl create Secret
Pongamos como ejemplo el caso de una grupo de pods que necesitan acceder a una base de datos. El nombre y contraseña que los pods deberían usar están en los archivos:
./username.txt y ./password.txt en tu máquina local.
# Crear archivos necesarios para el resto del ejemplo.echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt
El comando kubectl create secret
empaqueta esos archivos en un Secret y crea el objeto en el Apiserver.
Si la contraseña que está utilizando tiene caracteres especiales como por ejemplo $, \, *, o !, es posible que sean interpretados por tu intérprete de comandos y es necesario escapar cada carácter utilizando \ o introduciéndolos entre comillas simples '.
Por ejemplo, si tú password actual es S!B\*d$zDsb, deberías ejecutar el comando de esta manera:
Nota:kubectl get y kubectl describe evita mostrar el contenido de un Secret por defecto.
Esto es para proteger el Secret de ser expuesto accidentalmente a un espectador, o de ser almacenado en un registro de terminal.
Puedes crear también un Secret primero en un archivo, en formato json o en yaml, y luego crear ese objeto. El
Secret contiene dos mapas:
data y stringData. El campo de data es usado para almacenar datos arbitrarios, codificado usando base64. El campo stringData se proporciona para su conveniencia, y le permite proporcionar datos secretos como cadenas no codificadas.
Por ejemplo, para almacenar dos cadenas en un Secret usando el campo data, conviértalos a base64 de la siguiente manera:
Para ciertos escenarios, es posible que desee utilizar el campo de stringData field en su lugar.
Este campo le permite poner una cadena codificada que no sea base64 directamente en el Secret,
y la cadena será codificada para ti cuando el Secret es creado o actualizado.
Un ejemplo práctico de esto podría ser donde está implementando una aplicación
que usa un Secret para almacenar un archivo de configuración, y desea completar partes de ese archivo de configuración durante su proceso de implementación.
Si su aplicación usa el siguiente archivo de configuración:
Donde YWRtaW5pc3RyYXRvcg== decodifica a administrator.
Las llaves de data y stringData deben consistir en caracteres alfanuméricos,
'-', '_' or '.'.
Nota de codificación: Los valores serializados JSON y YAML de los datos secretos estan codificadas como cadenas base64. Las nuevas lineas no son válidas dentro de esa cadena y debe ser omitido. Al usar base64 en Darwin/macOS, los usuarios deben evitar el uso de la opción -b para dividir líneas largas. Por lo contratio los usuarios de Linux deben añadir la opción -w 0 a los comandos base64 o al pipeline base64 | tr -d '\n' si la opción -w no esta disponible.
Creaando un Secret a partir de Generador
Kubectl soporta managing objects using Kustomize
desde 1.14. Con esta nueva característica,
puedes tambien crear un Secret a partir de un generador y luego aplicarlo para crear el objeto en el Apiserver. Los generadores deben ser especificados en un kustomization.yaml dentro de un directorio.
Por ejemplo, para generar un Secret a partir de los archivos ./username.txt y ./password.txt
# Crear un fichero llamado kustomization.yaml con SecretGenerator
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: db-user-pass
files:
- username.txt
- password.txt
EOF
Aplica el directorio kustomization para crear el objeto Secret.
$ kubectl apply -k .
secret/db-user-pass-96mffmfh4k created
Puedes verificar que el secret fue creado de la siguiente manera:
$ kubectl get secrets
NAME TYPE DATA AGE
db-user-pass-96mffmfh4k Opaque 2 51s
$ kubectl describe secrets/db-user-pass-96mffmfh4k
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data====
password.txt: 12 bytes
username.txt: 5 bytes
Por ejemplo, para generar un Secret a partir de literales username=admin y password=secret,
puedes especificar el generador del Secret en kustomization.yaml como:
# Crea un fichero kustomization.yaml con SecretGenerator
cat <<EOF >./kustomization.yaml
secretGenerator:
- name: db-user-pass
literals:
- username=admin
- password=secret
EOF
Aplica el directorio kustomization para crear el objeto Secret.
kubectl apply -k .
secret/db-user-pass-dddghtt9b5 created
Nota: El nombre generado del Secret tiene un sufijo agregado al hashing de los contenidos. Esto asegura que se genera un nuevo Secret cada vez que el contenido es modificado.
Decodificando un Secret
Los Secrets se pueden recuperar a través del comando kubectl get secret . Por ejemplo, para recuperar el Secret creado en la sección anterior:
Los Secrets se pueden montar como volúmenes de datos o ser expuestos como
variables de ambiente
para ser usados por un contenedor en un pod. También pueden ser utilizados por otras partes del sistema,
sin estar directamente expuesto en el pod. Por ejemplo, pueden tener credenciales que otras partes del sistema usan para interactuar con sistemas externos en su nombre.
Usando Secrets como Archivos de un Pod
Para consumir un Secret en un volumen en un Pod:
Crear un Secret o usar uno existente. Múltiples pods pueden referenciar el mismo Secret.
Modifique la definición del Pod para agregar un volumen debajo de .spec.volumes[]. Asigne un nombre al volumen y tenga un campo .spec.volumes[].secret.secretName igual al nombre del objeto del Secret.
Agrega un .spec.containers[].volumeMounts[] a cada contenedor que necesite un Secret. Especifica .spec.containers[].volumeMounts[].readOnly = true y .spec.containers[].volumeMounts[].mountPath a un nombre de directorio no utilizado donde desea que aparezca los Secrets.
Modifique la imagen y/o linea de comando para que el programa busque archivos en ese directorio. Cada llave en el data map del los Secrets se convierte en el nombre del archivo bajo mountPath.
Este es un ejemplo de un pod que monta un Secret en un volumen:
Cada Secret que desea usar debe mencionarse en .spec.volumes.
Si hay múltiples contenedores en un Pod, entonces cada contenedor necesita su propio bloque volumeMounts , pero solo un .spec.volumes se necesita por Secret.
Puede empaquetar muchos archivos en un Secret, o usar muchos Secrets, lo que sea conveniente.
Proyección de llaves Secret a rutas específicas
También podemos controlar las rutas dentro del volumen donde se proyectan las llaves Secrets.
Puede usar el campo .spec.volumes[].secret.items para cambiar la ruta de destino de cada clave:
El Secret username se almacena bajo el archivo /etc/foo/my-group/my-username en lugar de /etc/foo/username.
El Secret password no se proyecta
Si se utiliza .spec.volumes[].secret.items , solo se proyectan las llaves específicadas en los items.
Para consumir todas las llaves del Secret, Todas deben ser enumeradas en el campo items.
Todas las llaves enumeradas deben existir en el Secret correspondiente. De lo contrario, el volumen no se crea.
Permisos de archivos Secrets
Tambien puede especificar el modo de permiso de los archivos de bits que tendrá una parte de un Secret.
Si no especifica ninguno, 0644 es usado por defecto. Puede especificar un modo predeterminado para todo el volumen del Secret y sobreescribir por llave si es necesario.
Por ejemplo, puede especificar un modo predeterminado como este:
Entonces, el Secret será montado en /etc/foo y todos los archivos creados por el
montaje del volumen del Secret tendrán permiso 0400.
Tenga en cuenta que la especificación JSON no soporta la notación octal, entonces use el valor 256 para
permisos 0400. Si usa yaml en lugar de json para el pod, puede usar notación octal para especificar permisos de una manera más natural.
También puede usar el mapeo, como en el ejemplo anterior, y especificar diferentes permisos para diferentes archivos como:
En este caso, el archivo resultante en /etc/foo/my-group/my-username tendrá
un valor de permiso 0777. Debido a las limitaciones de JSON, debe especificar el modo en notación decimal.
Tenga en cuenta que este valor de permiso puede mostrarse en notación decimal si lo lee después.
Consumir Valores Secrets de Volúmenes
Dentro del contenedor que monta un volumen del Secret, las llaves del Secret aparece como archivos y los valores del Secret son decodificados en base-64 y almacenados dentro de estos archivos.
Este es el resultado de comandos ejecutados dentro del contenedor del ejemplo anterior:
ls /etc/foo/
username
password
cat /etc/foo/username
admin
cat /etc/foo/password
1f2d1e2e67df
El programa en un contenedor es responsable de leer los Secrets de los archivos.
Los Secrets Montados se actualizan automáticamente
Cuando se actualiza un Secret que ya se está consumiendo en un volumen, las claves proyectadas también se actualizan eventualmente.
Kubelet está verificando si el Secret montado esta actualizado en cada sincronización periódica.
Sin embargo, está usando su caché local para obtener el valor actual del Secret.
El tipo de caché es configurable usando el (campo ConfigMapAndSecretChangeDetectionStrategy en
KubeletConfiguration struct).
Puede ser propagado por el reloj (default), ttl-based, o simplemente redirigiendo
todas las solicitudes a kube-apiserver directamente.
Como resultado, el retraso total desde el momento en que se actualiza el Secret hasta el momento en que se proyectan las nuevas claves en el Pod puede ser tan largo como el periodo de sincronización de kubelet + retraso de
propagación de caché, donde el retraso de propagación de caché depende del tipo de caché elegido.
(Es igual a mirar el retraso de propagación, ttl of cache, o cero correspondientemente).
Nota: Un contenedor que usa un Secret como
subPath el montaje del volumen no recibirá actualizaciones de Secret.
Crea un Secret o usa uno existente. Múltiples pods pueden hacer referencia a un mismo Secret.
Modifique la definición de su Pod en cada contenedor que desee consumir el valor de una llave Secret para agregar una variable de entorno para cada llave Secret que deseas consumir. La variable de entorno que consume la llave Secret debe completar el nombre y la llave del Secret en env[].valueFrom.secretKeyRef.
Modifique su imagen y/o linea de comandos para que el programa busque valores en las variables de entorno especificadas.
Esto es un ejemplo de un pod que usa Secrets de variables de entorno:
Consumiendo Valores Secrets a partir de Variables de Entorno
Dentro de un contenedor que consume un Secret en una variable de entorno, las claves Secrets aparecen como variables de entorno normal que contienen valores decodificados de base-64 de los datos del Secret.
Este es el resultado de comandos ejecutados dentro del contenedor del ejemplo anterior.
echo$SECRET_USERNAME
admin
echo$SECRET_PASSWORD
1f2d1e2e67df
Usando imagePullSecrets
Una imagePullSecret es una forma de pasar a kubelet un Secret que contiene las credenciales para un registro de imagenes de Docker (u otro) para que pueda obtener una imagen privada en nombre de su pod.
Especificar manualmente una imagePullSecret
El uso de imagePullSecrets se desccriben en la documentación de las imágenes images documentation
Organización de imagePullSecrets para que se Adjunte Automáticamente
Puede crear manualmente un imagePullSecret, y hacer referencia a él desde un serviceAccount. Cualquier pod creado con ese serviceAccount
o ese valor predeterminado para usar serviceAccount, obtendrá su campo imagePullSecret
establecido en el service account.
Ver Agregar ImagePullSecrets a una cuenta de servicio
para una explicación detallada de ese proceso.
Montaje Automatico de Secrets Creados Manualmente
Secrets creados Manualmente, (por ejemplo uno que contiene un token para acceder a una cuenta github) se puede conectar automáticamente a los pods según su cuenta de servicio. Vea Inyección de infromación en pods usando un a PodPreset para una explicación detallada de este proceso.
Detalles
Restricciones
Las fuentes del volumen del Secret se validan para garantizar que la referencia del objeto especificado apunte a un objeto de tipo Secret. Por lo tanto, se debe crear un Secret antes de que cualquier pod dependa de él.
Los objetos API Secret residen en namespace.
Solo pueden ser referenciados por pods en el mismo namespace.
Los Secrets individuales estan limitados a 1MiB de tamaño. Esto es para desalentar la creación de Secrets muy grandes que agotarían la memoria del apiserver y de kubelet.
Sin embargo la creación de muchos Secrets más pequeños también podría agotar la memoria. Límites más completos en el uso de memoria debido a Secret es una característica planificada.
Kubelet solo admite el uso de Secret para Pods que obtiene del API server. Esto incluye cualquier pods creado usando kubectl, o indirectamente a través de un contralador de replicación.
No incluye pods creados a través de los kubelets
--manifest-url flag, its --config flag, o su REST API (estas no son formas comunes de crear pods.)
Los Secrets deben crearse antes de que se consuman en pod como variables de entono a menos que estén marcados como optional. Referencias a Secrets que no existen evitarán que el pod inicie.
Las referencias a través de secretKeyRef a claves que no existen en un Secret con nombre evitarán que el pod se inicie.
Los Secrets que se utilizan para poblar variables de entorno a través de envFrom que tienen claves que se consideran nombres de variables de entorno no validos, tendran esas claves omitidas. El Pod se permitira reiniciar. Habrá un evento cuyo motivo es InvalidVariableNames y el mensaje contendrá la lista de claves no validas que se omitieron. El ejemplo muestra un pod que se refiere al default/mysecret que contiene 2 claves no validas, 1 badkey y 2 alsobad.
kubectl get events
LASTSEEN FIRSTSEEN COUNT NAME KIND SUBOBJECT TYPE REASON
0s 0s 1 dapi-test-pod Pod Warning InvalidEnvironmentVariableNames kubelet, 127.0.0.1 Keys [1badkey, 2alsobad] from the EnvFrom secret default/mysecret were skipped since they are considered invalid environment variable names.
Interacción del Secret y Pod de por vida
Cuando se crea un Pod a través de la API, no se verifica que exista un recreto referenciado.
Una vez que se programa el Pod, kubelet intentará obtener el valor del Secret.
Si el Secret no se puede recuperar será por que no existe o por una falla
temporal de conexión al servidor API, kubelet volverá a intentarlo periodicamente.
Enviará un evento sobre el pod explicando las razones por la que aún no se inició.
Una vez que el Secret es encontrado, kubelet creará y montará el volumen que lo contiene.
Ninguno de los contenedorees del pod se iniciará hasta que se monten todos los volúmes del pod.
Casos de uso
Caso de Uso: Pod con llaves ssh
Cree un fichero kustomization.yaml con SecretGenerator conteniendo algunas llaves ssh:
Precaución: Piense detenidamente antes de enviar tus propias llaves ssh: otros usuarios del cluster pueden tener acceso al Secret. Utilice una cuenta de servicio a la que desee que estén accesibles todos los usuarios con los que comparte el cluster de Kubernetes, y pueda revocarlas si se ven comprometidas.
Ahora podemos crear un pod que haga referencia al Secret con la llave ssh key y lo consuma en un volumen:
El contenedor es libre de usar los datos del Secret para establecer conexión ssh.
Caso de uso: Pods con credenciales prod / test
Este ejemplo ilustra un pod que consume un Secret que contiene credenciales de prod y otro pod que consume un Secret con credenciales de entorno de prueba.
Crear un fichero kustomization.yaml con SecretGenerator
Caracteres especiales como $, \*, y ! requieren ser escapados.
Si el password que estas usando tiene caracteres especiales, necesitas escaparlos usando el caracter \\ . Por ejemplo, si tu password actual es S!B\*d$zDsb, deberías ejecutar el comando de esta forma:
observe cómo las especificaciones para los dos pods difieren solo en un campo; esto facilita la creación de pods con diferentes capacidades de una plantilla de configuración de pod común.
Deberías simplificar aún más la especificación del pod base utilizando dos Cuentas de Servicio:
uno llamado, prod-user con el prod-db-secret, y otro llamado,
test-user con el test-db-secret. Luego, la especificación del pod se puede acortar a, por ejemplo:
Para hacer que los datos esten 'ocultos' (es decir, en un file dónde el nombre comienza con un caracter de punto), simplemente haga que esa clave comience con un punto. Por ejemplo, cuando el siguiente Secret es montado en un volumen:
El secret-volume contendrá un solo archivo, llamado .secret-file, y
el dotfile-test-container tendrá este fichero presente en el path
/etc/secret-volume/.secret-file.
Nota: Los archivos que comiences con caracterers de punto estan ocultos de la salida de ls -l;
tu debes usar ls -la para verlos al enumerar los contenidos del directorio.
Caso de uso: Secret visible para un contenedor en un pod
Considere un programa que necesita manejar solicitudes HTTP, hacer una lógicca empresarial compleja y luego firmar algunos mensajes con un HMAC. Debido a que tiene una lógica de aplicación compleja, puede haber una vulnerabilidad de lectura remota de archivos inadvertida en el servidor, lo que podría exponer la clave privada a un atacante.
Esto podría dividirse en dos procesos en dos contenedores: un contenedor de frontend que maneja la interacción del usuario y la lógica empresarial. pero que no puede ver la clave privada; y un contenedor de firmante que puede ver la clave privada, y responde a solicitudes de firma simples del frontend (ejemplo, a través de redes de localhost).
Con este enfoque particionado, un atacante ahora tiene que engañar a un servidor de aplicaciones para que haga algo bastante arbitrario, lo que puede ser más difícil que hacer que lea un archivo.
Mejores prácticas
Clientes que usan la API de Secrets
Al implementar aplicaciones que interactuan con los API Secrets, el acceso debe limitarse utilizando authorization policies como RBAC.
Los Secrets a menudo contienen valores que abarcan un espectro de importancia, muchos de los cuales pueden causar escalamientos dentro de Kubernetes (ejememplo, tokens de cuentas de servicio) y a sistemas externos. Incluso si una aplicación individual puede razonar sobre el poder de los Secrets con los que espera interactuar, otras aplicaciones dentro dle mismo namespace pueden invalidar esos supuestos.
Por esas razones las solicitudes de watch y list dentro de un espacio de nombres son extremadamente poderosos y deben evitarse, dado que listar Secrets permiten a los clientes inspecionar los valores de todos los Secrets que estan en el namespace. La capacidad para watch and list todos los Secrets en un cluster deben reservarse solo para los componentes de nivel de sistema más privilegiados.
Las aplicaciones que necesitan acceder a la API de Secrets deben realizar solicitudes de get de los Secrets que necesitan. Esto permite a los administradores restringir el acceso a todos los Secrets mientras white-listing access to individual instances que necesita la aplicación.
Para un mejor rendimiento sobre un bucle get, los clientes pueden diseñar recursos que hacen referencia a un Secret y luego un Secret watch el recurso, al volver a solicitar el Secret cuando cambie la referencia. Además,, un "bulk watch" API
para que los clientes puedan watch recursos individuales, y probablemente estará disponible en futuras versiones de Kubernetes.
Propiedades de seguridad
Protecciones
Debido a que los objetos Secret se pueden crear independientemente de los Pods que los usan, hay menos riesgo de que el Secret expuesto durante el flujo de trabajo de la creación, visualización, y edición de pods. El sistema también puede tomar precausiones con los objetosSecret, tal como eviar escribirlos en el disco siempre que sea posible.
Un Secret solo se envía a un nodo si un pod en ese nodo lo requiere. Kubelet almacena el Secret en un tmpfs para que el Secret no se escriba en el almacenamiento de disco. Una vez que se elimina el pod que depende del Secret, kubelet eliminará su copia local de los datos de Secrets.
Puede haber Secrets para varios Pods en el mismo nodo. Sin embargo, solo los Secrets que solicita un Pod son potencialmente visibles dentro de sus contenedores. Por lo tanto, un Pod no tiene acceso a los Secrets de otro Pod.
Puede haver varios contenedores en un Pod. Sin embargo, cada contenedor en un pod tiene que solicitar el volumen del Secret en su
volumeMounts para que sea visible dentro del contenedor. Esto se puede usar para construir particiones de seguridad útiles en el Pod level](#use-case-secret-visible-to-one-container-in-a-pod).
En la mayoría de las distribuciones Kubernetes-project-maintained, la comunicación entre usuario a el apiserver, y del apiserver a kubelets, ista protegido por SSL/TLS.
Los Secrets estan protegidos cuando se transmiten por estos canales.
FEATURE STATE:Kubernetes v1.13 [beta]
Puedes habilitar encryption at rest
para datos secretos, para que los Secrets no se almacenen en claro en etcd.
Riesgos
En el servidor API, los datos de los Secrets se almacenan en etcd; por lo tanto:
Los adminsitradores deben habilitar el cifrado en reposo para los datos del cluster (requiere v1.13 o posterior)
Los administradores deben limitar el acceso a etcd a los usuarios administradores
Los administradores pueden querer borrar/destruir discos usados por etcd cuando ya no estén en uso
Si ejecuta etcd en un clúster, los administradores deben asegurarse de usar SSL/TSL para la comunicación entre pares etcd.
Si configura el Secret a través de un archivo de (JSON o YAML) que tiene los datos del Secret codificados como base64, compartir este archivo o registrarlo en un repositorio de origen significa que el Secret está comprometido. La codificación Base64 no es un método de cifrado y se considera igual que un texto plano.
Las aplicaciones aún necesitan proteger el valor del Secret después de leerlo del volumen, como no registrarlo accidentalmente o transmitirlo a una parte no confiable.
Un usuario que puede crear un pod que usa un Secret también puede ver el valor del Secret. Incluso si una política del apiserver no permite que ese usuario lea el objeto Secret, el usuario puede ejecutar el pod que expone el Secret.
Actualmente, cualquier persona con root en cualquier nodo puede leer cualquier secret del apiserver, haciéndose pasar por el kubelet. Es una característica planificada enviar Secrets a los nodos que realmente lo requieran, para restringir el impacto de una explosión de root en un single node.
Siguientes pasos
3.7.5 - Organizar el acceso a los clústeres utilizando archivos kubeconfig
Utilice los archivos kubeconfig para organizar la información acerca de los clústeres, los
usuarios, los Namespaces y los mecanismos de autenticación. La herramienta de
línea de comandos kubectl utiliza los archivos kubeconfig para hallar la información que
necesita para escoger un clúster y comunicarse con el servidor API de un clúster.
Nota: Un archivo utilizado para configurar el acceso a los clústeres se denomina
archivo kubeconfig. Esta es una forma genérica de referirse a los archivos de
configuración. Esto no significa que exista un archivo llamado kubeconfig.
Por defecto, kubectl busca un archivo llamado config en el directorio $HOME/.kube.
Puedes especificar otros archivos kubeconfig mediante la configuración de la variable
de entorno KUBECONFIG o mediante la configuracion del flag
--kubeconfig.
Compatibilidad con múltiples clústeres, usuarios y mecanismos de autenticación
Suponga que tiene diversos clústeres y que sus usuarios y componentes se autentican
de diversas maneras. Por ejemplo:
Un kubelet en ejecución se podría autenticar usando certificados.
Un usuario se podría autenticar utilizando tokens.
Los administradores podrían tener un conjunto de certificados que sean suministrados a los usuarios individualmente.
Con los archivos kubeconfig puedes organizar tus clústeres, usuarios y Namespaces.
También puedes definir diferentes contextos para realizar de forma rápida y
fácil cambios entre clústeres y Namespaces.
Contexto
Un elemento context en un archivo kubeconfig se utiliza para agrupar los parámetros de
acceso bajo un nombre apropiado. Cada contexto tiene tres parámetros: clúster, Namespace
y usuario.
Por defecto, la herramienta de línea de comandos kubectl utiliza los parámetros del
contexto actual para comunicarse con el clúster.
Para seleccionar el contexto actual:
kubectl config use-context
Variable de entorno KUBECONFIG
La variable de entorno KUBECONFIG contiene una lista de archivos kubeconfig.
En el caso de Linux y Mac, la lista está delimitada por dos puntos. Si se trata
de Windows, la lista está delimitada por punto y coma. La variable de entorno
KUBECONFIG no es indispensable. Si la variable de entorno KUBECONFIG no existe,
kubectl utiliza el archivo kubeconfig por defecto $HOME/.kube/config.
Si la variable de entorno KUBECONFIG existe, kubectl utiliza una
configuración eficiente que es el resultado de la fusión de los archivos
listados en la variable de entorno KUBECONFIG.
Fusionando archivos kubeconfig
Para poder ver su configuración, escriba el siguiente comando:
kubectl config view
Como se ha descrito anteriormente, la respuesta de este comando podría resultar a partir de un solo
archivo kubeconfig, o podría ser el resultado de la fusión de varios archivos kubeconfig.
A continuación se muestran las reglas que usa kubectl cuando fusiona archivos kubeconfig:
Si el flag --kubeconfig está activado, usa solamente el archivo especificado. Sin fusionar.
Sólo se permite una instancia con este flag.
En caso contrario, si la variable de entorno KUBECONFIG está activada, sera usada
como un listado de los archivos a ser fusionados.
Fusionar los archivos listados en la variable de entorno KUBECONFIG de acuerdo
con estas reglas:
Ignorar nombres de archivo vacíos.
Producir errores para archivos con contenido que no pueden ser deserializados.
El primer archivo que establezca un valor particular o una clave se impone.
Nunca cambie el valor o la clave.
Ejemplo: Conserva el contexto del primer archivo para configurar el contexto actual.
Ejemplo: Si dos archivos especifican un red-user, utilice sólo los valores del primer archivo.
Incluso desechar el segundo archivo aunque tenga registros que no tengan conflictos.
En caso contrario, utilice el archivo kubeconfig predeterminado $HOME/.kube/config, sin fusionar.
Determinar el contexto a utilizar con base en el primer acierto en esta secuencia:
Si es que existe, utilice el flag ---contexto de la línea de comandos.
Utilice el contexto actual procedente de los archivos kubeconfig fusionados.
En este punto se permite un contexto vacío.
Determinar el clúster y el usuario. En este caso, puede o no haber un contexto.
Determine el clúster y el usuario con base en el primer acierto que se ejecute dos veces en
esta secuencia: una para el usuario y otra para el clúster:
Si es que existen, utilice el flag --user o --cluster de la línea de comandos.
Si el contexto no está vacío, tome el usuario o clúster del contexto.
En este caso el usuario y el clúster pueden estar vacíos.
Determinar la información del clúster a utilizar. En este caso, puede o no haber información del clúster.
Se construye cada pieza de la información del clúster con base en esta secuencia, el primer acierto se impone:
Si es que existen, use el flag --server, --certificate-authority, --insecure-skip-tls-verify en la línea de comandos.
Si existen atributos de información de clúster procedentes de los archivos kubeconfig fusionados, utilícelos.
Falla si no existe la ubicación del servidor.
Determinar la información del usuario a utilizar. Cree información de usuario utilizando las mismas reglas que
la información de clúster, con la excepción de permitir sólo un mecanismo de autenticación por usuario:
Si es que existen, utilice el flag --client-certificate, --client-key, --username, --password, --token de la línea de comandos.
Utilice los campos user de los archivos kubeconfig fusionados.
Falla si hay dos mecanismos de autenticación contradictorios.
Si todavía falta información, utilice los valores predeterminados y solicite
información de autenticación.
Referencias de archivos
Las referencias, así también como, las rutas de un archivo kubeconfig son relativas a la ubicación del archivo kubeconfig.
Las referencias de un archivo en la línea de comandos son relativas al directorio actual de trabajo.
Dentro de $HOME/.kube/config, las rutas relativas se almacenan de manera relativa a la ubicación del archivo kubeconfig , al igual que las rutas absolutas
se almacenan absolutamente.
Esta descripción general define un modelo para la seguridad de Kubernetes en el contexto de Seguridad en Cloud Native.
Advertencia: Este modelo de seguridad en el contenedor brinda sugerencias, no es una prueba de políticas de seguridad de la información.
Las 4C de Seguridad en Cloud Native
Puede pensar en seguridad por capas. Las 4C de la seguridad en Cloud Native son la nube (Cloud),
Clústeres, Contenedores y Código.
Nota: Este enfoque en capas aumenta la defensa en profundidad
de la seguridad, es considerada una buena práctica en seguridad para el software de sistemas.
Cada capa del modelo de seguridad Cloud Native es basada en la siguiente capa más externa.
La capa de código se beneficia de una base sólida (nube, clúster, contenedor) de capas seguras.
No podemos garantizar la seguridad aplicando solo seguridad a nivel del código, y usar estándares de seguridad deficientes en las otras capas.
Nube (Cloud)
En muchos sentidos, la nube (o los servidores o el centro de datos corporativo) es la
base de computador confiable
de un clúster de Kubernetes. Si la capa de la nube es vulnerable (o
configurado de alguna manera vulnerable), por consecuencia no hay garantía de que los componentes construidos
encima de la base sean seguros. Cada proveedor de la nube tiene recomendaciones de seguridad
para ejecutar las cargas de trabajo de forma segura en sus entornos.
Seguridad del proveedor de la nube
Si está ejecutando un clúster de Kubernetes en su propio hardware o en un proveedor de nube diferente,
consulte la documentación para conocer las mejores prácticas de seguridad.
A continuación, algunos enlaces a la documentación de seguridad de los proveedores de nube más populares:
Sugerencias para proteger su infraestructura en un clúster de Kubernetes:
Infrastructure security
Área de Interés para la Infraestructura de Kubernetes
Recomendación
Acceso de red al Plano de Control
Todo acceso público al plano de control del Kubernetes en Internet no está permitido y es controlado por listas de control de acceso a la red estrictas a un conjunto de direcciones IP necesarias para administrar el clúster.
Acceso a la red de los Nodos
Los nodos deben ser configurados para solo aceptar conexiones (por medio de listas de control de acceso a la red) desde el plano de control en los puertos especificados y aceptar conexiones para servicios en Kubernetes del tipo NodePort y LoadBalancer. Si es posible, estos nodos no deben exponerse públicamente en Internet.
Acceso a la API de Kubernetes del proveedor de la nube
Cada proveedor de la nube debe dar un conjunto de permisos al plano de control y nodos del Kubernetes. Es mejor otorgar al clúster el permiso de acceso al proveedor de nube siguiendo el principio de mínimo privilegio para los recursos que necesite administrar. La documentación del Kops ofrece información sobre las políticas y roles de IAM.
Acceso a etcd
El acceso a etcd (banco de datos de Kubernetes) debe ser limitado apenas al plano de control. Dependiendo de su configuración, debería intentar usar etcd sobre TLS. Puede encontrar mas información en la documentación de etcd.
Encriptación etcd
Siempre que sea posible, es una buena práctica encriptar todas las unidades de almacenamiento. Etcd mantiene el estado de todo el clúster (incluidos los Secretos), por lo que su disco debe estar encriptado.
Clúster
Existen dos áreas de preocupación para proteger Kubernetes:
Protección de las configuraciones de los componentes del clúster.
Protección de las aplicaciones que se ejecutan en el clúster.
Componentes del Clúster
Si desea proteger su clúster de accesos accidentales o maliciosos y adoptar
buenas prácticas de seguridad, a continuación sigue estos consejos sobre
como proteger el clúster.
Componentes del clúster (su aplicación)
Dependiendo de la superficie de ataque de su aplicación, es posible que desee concentrarse en
temas de seguridad específicos. Por ejemplo: si está ejecutando un servicio (Servicio A) que es crítico
en una cadena de otros recursos y otra carga de trabajo separada (Servicio B) que es
vulnerable a un ataque de sobrecarga de recursos, el riesgo de comprometer el Servicio A
es alto si no limita las funciones del Servicio B. La siguiente tabla enumera
áreas de atención de seguridad y recomendaciones para proteger las cargas de trabajo que se ejecutan en Kubernetes:
La seguridad de los contenedores está fuera del alcance de la guía. Aquí hay recomendaciones generales y
enlaces para explorar este tema:
Área de Interés para Contenedores
Recomendación
Escáneres de vulnerabilidad de contenedores y seguridad de dependencia del sistema operativo
Como parte del paso de la creación de la imagen, se debe utilizar un escáner de contenedores para detectar vulnerabilidades.
Firma de Imágenes y Aplicación
Firma de imágenes de contenedores para mantener un sistema confiable para el contenido de sus contenedores.
Prohibir Usuarios Privilegiados
Al crear contenedores, consulte la documentación para crear usuarios dentro de los contenedores con el menor privilegio necesario para cumplir con el propósito del contenedor en el sistema operativo.
Utilice el contenedor de tiempo de ejecución con el aislamiento más fuerte
El código de la aplicación es una de las principales superficies de ataque sobre las que tenemos más control.
Aunque la protección del código de la aplicación está fuera del tema de seguridad de Kubernetes, aquí algunas
recomendaciones para proteger el código de su aplicación:
Seguridad del código
Code security
Áreas de Atención para el Código
Recomendación
Acceso solo a través de TLS
Si su código necesita comunicarse a través de TCP, ejecute un handshake TLS con el cliente anticipadamente. Con la excepción de algunos casos, encripte todo lo que está en tránsito. Yendo un paso más allá, es una buena idea cifrar el tráfico de red entre los servicios. Esto se puede hacer a través del proceso de autenticación mutua o mTLS, que realiza una verificación bilateral de la comunicación a través de los certificados en los servicios.
Limitación de rangos de puertos de comunicación
Esta recomendación puede ser un poco evidente, pero siempre que sea posible, solo debe exponer los puertos de su servicio que son absolutamente esenciales para la comunicación o la recopilación de métricas.
Seguridad en dependencia de terceros
Es una buena práctica comprobar periódicamente las bibliotecas de terceros de su aplicación en busca de vulnerabilidades de seguridad. Cada lenguaje de programación tiene una herramienta para realizar esta verificación de forma automática.
Análisis de código estático
La mayoría de los lenguajes proporcionan una forma de analizar el código en busca de prácticas de codificación potencialmente inseguras. Siempre que sea posible, debe automatizar los escaneos utilizando herramientas que puedan escanear las bases del código en busca de errores de seguridad comunes. Algunas de las herramientas se pueden encontrar en OWASP Source Code Analysis Tools.
Ataques de sondeo dinámico
Existen algunas herramientas automatizadas que puede ejecutar en su servicio para explorar algunos de los ataques más conocidos. Esto incluye la inyección de SQL, CSRF y XSS. Una de las herramientas de análisis dinámico más populares es la OWASP Zed Attack proxy.
Siguientes pasos
Obtenga más información sobre los temas de seguridad de Kubernetes:
Políticas configurables que se aplican a grupos de recursos.
La sección de Políticas describe las diferentes políticas configurables que se aplican a grupos de recursos:
3.9.1 - Rangos de límites (Limit Ranges)
Aplica límites de recursos a un Namespace para restringir y garantizar la asignación y consumo de recursos informáticos.
Contexto
Por defecto, los contenedores se ejecutan sin restricciones sobre los recursos informáticos disponibles en un clúster de Kubernetes.
Si el Nodo dispone de los recursos informáticos, un Pod o sus Contenedores tienen permitido consumir por encima de la cuota solicitada si no superan el límite establecido en su especificación.
Existe la preocupación de que un Pod o Contenedor pueda monopolizar todos los recursos disponibles.
Utilidad
Aplicando restricciones de asignación de recursos, los administradores de clústeres se aseguran del cumplimiento del consumo de recursos por espacio de nombre (Namespace).
El controlador de admisión LimitRanger aplicará valores predeterminados y límites, para todos los Pods o Contenedores que no establezcan requisitos de recursos informáticos. Y realizará un seguimiento del uso para garantizar que no excedan el mínimo, el máximo, y la proporción de ningún LimitRange definido en el Namespace.
Si al crear o actualizar un recurso del ejemplo (Pods, Contenedores, Solicitudes de Volúmenes Persistentes) se viola una restricción al LimitRange, la solicitud al servidor API fallará con un código de estado HTTP "403 FORBIDDEN" y un mensaje que explica la restricción que se ha violado.
En caso de que en se active un LimitRange para recursos de cómputos como cpu y memory, los usuarios deberán especificar los requisitos y/o límites de recursos a dichos valores. De lo contrario, el sistema puede rechazar la creación del Pod.
Las validaciones de LimitRange ocurren solo en la etapa de Admisión de Pod, no en Pods que ya se han iniciado (Running Pods).
Algunos ejemplos de políticas que se pueden crear utilizando rangos de límites son:
En un clúster de 2 nodos con una capacidad de 8 GiB de RAM y 16 núcleos, podría restringirse los Pods en un Namespace a requerir 100m de CPU con un límite máximo de 500m para CPU y requerir 200Mi de memoria con un límite máximo de 600Mi de memoria.
Definir el valor por defecto de límite y requisitos de CPU a 150m y el valor por defecto de requisito de memoria a 300MiContenedores que se iniciaron sin requisitos de CPU y memoria en sus especificaciones.
En el caso de que los límites totales del Namespace sean menores que la suma de los límites de los Pods,
puede haber contienda por los recursos. En este caso, los contenedores o pods no seran creados.
Ni la contención ni los cambios en un LimitRange afectarán a los recursos ya creados.
3.11.2 - Extensiones de computación, almacenamiento y redes
4 - Guías de iniciación
4.1 - Fedora
5 - Tareas
Esta sección de la documentación de Kubernetes contiene páginas que
muestran cómo acometer tareas individuales. Cada página de tarea muestra cómo
realizar una única cosa, típicamente proporcionando una pequeña secuencia de comandos.
Interfaz Web de Usuario (Tablero de Control)
Despliega y accede al interfaz web de usuario del Tablero de Control para ayudarte en la gestión y monitorización de las aplicaciones en contenedores de tu clúster de Kubenertes.
Usar la línea de comandos con kubectl
Instala y configura la herramienta de línea de comandos kubectl para gestionar de forma directa tus clústers de Kubernetes.
Configurar Pods y Contenedores
Realiza tareas comunes de configuración para tus Pods y Contenedores.
Ejecutar Aplicaciones
Realiza tareas comunes de gestión de aplicaciones, como actualizaciones de lanzamiento, inyectar información en los pods, y auto-escalado horizontal de pods.
Ejecutar Jobs
Ejecuta Jobs usando procesado paralelo.
Acceder a las Aplicaciones de un Clúster
Configura el balanceo de carga, re-envío de puertos, o configura el cortafuegos o las configuraciones de DNS para acceder a las aplicaciones en un clúster.
Monitorización, Trazas, y Depuración
Configura la monitorización y las trazas para identificar problemas en un clúster o depurar una aplicación en un contenedor.
Acceder a la API de Kubernetes
Aprende varios métodos para acceder directamente a la API de Kubernetes.
Usar TLS
Configura tu aplicación para que confíe y use el Certificado de Autoridad (CA) raíz de tu clúster.
Administrar un Clúster
Aprende tareas comunes de administración de un clúster.
Administrar la Federación
Configura componentes en una federación de clústers.
Gestionar Aplicaciones con Estado
Realiza tareas comunes de gestión de aplicaciones con estado, incluyendo escalado, borrado y depuración de StatefulSets.
Daemons del Clúster
Realiza tareas comunes de gestión de un DaemonSet, como llevar a cabo una actualización de lanzamiento.
Gestionar GPUs
Configura y planifica GPUs de NVIDIA para hacerlas disponibles como recursos a los nodos de un clúster.
Gestionar HugePages
Configura y planifica HugePages como un recurso planificado en un clúster.
Configurar las herramientas de Kubernetes en su computadora.
kubectl
Usa la herramienta de línea de comandos de Kubernetes, kubectl, para desplegar y gestionar aplicaciones en Kubernetes. Usando kubectl, puedes inspeccionar recursos del clúster; crear, eliminar, y actualizar componentes; explorar tu nuevo clúster y arrancar aplicaciones.
Ver Instalar y Configurar kubectl para más información sobre cómo descargar y instalar kubectl y configurarlo para acceder su clúster.
De forma similar a kind, minikube es una herramienta que le permite usar Kubernetes en su máquina local. minikube le permite ejecutar un único nodo en su computadora personal (PC de Windows, macOS y Linux) para que se pueda probar Kubernetes, o para su trabajo de desarrollo.
Se puede seguir la guía oficial de minikube si su enfoque esta instalando la herramienta.
Usa la herramienta de línea de comandos de Kubernetes, kubectl, para desplegar y gestionar aplicaciones en Kubernetes. Usando kubectl, puedes inspeccionar recursos del clúster; crear, eliminar, y actualizar componentes; explorar tu nuevo clúster; y arrancar aplicaciones de ejemplo. Para ver la lista completa de operaciones de kubectl, se puede ver el resumen de kubectl.
Antes de empezar
Debes usar una versión de kubectl que esté a menos de una versión menor de diferencia con tu clúster. Por ejemplo, un cliente v1.2 debería funcionar con un máster v1.1, v1.2, y v1.3. Usar la última versión de kubectl ayuda a evitar problemas inesperados.
Para descargar una versión específica, remplaza el comando $(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt) con la versión específica.
Por ejemplo, para descarga la versión v1.20.15 en Linux, teclea:
Si usas Ubuntu o alguna de las otras distribuciones de Linux que soportan el gestor de paquetes snap, kubectl está disponible como una aplicación snap.
snap install kubectl --classic
kubectl version --client
Para descargar una versión específica, remplaza el comando $(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt) con la versión específica.
Por ejemplo, para descargar la versión v1.20.15 en macOS, teclea:
Si tienes Docker Desktop instalado, es posible que tengas que modificar tu PATH al PATH añadido por Docker Desktop o eliminar la versión de kubectl proporcionada por Docker Desktop.
Instalar con Powershell desde PSGallery
Si estás en Windows y utilizas el gestor de paquetes Powershell Gallery, puedes instalar y actualizar kubectl con Powershell.
Ejecuta los comandos de instalación (asegurándote de especificar una DownloadLocation):
Para asegurar que la versión utilizada sea la más actual puedes probar:
kubectl version --client
Comprobar la configuración kubectl
Para que kubectl pueda encontrar y acceder a un clúster de Kubernetes, necesita un fichero kubeconfig, que se crea de forma automática cuando creas un clúster usando kube-up.sh o despliegas de forma satisfactoria un clúster de Minikube. Revisa las guías para comenzar para más información acerca de crear clústers. Si necesitas acceso a un clúster que no has creado, ver el documento de Compartir Acceso a un Clúster.
Por defecto, la configuración de kubectl se encuentra en ~/.kube/config.
Comprueba que kubectl está correctamente configurado obteniendo el estado del clúster:
kubectl cluster-info
Si ves una respuesta en forma de URL, kubectl está correctamente configurado para acceder a tu clúster.
Si ves un mensaje similar al siguiente, kubectl no está correctamente configurado o no es capaz de conectar con un clúster de Kubernetes.
The connection to the server <server-name:port> was refused - did you specify the right host or port?
Por ejemplo, si intentas ejecutar un clúster de Kubernetes en tu portátil (localmente), necesitarás una herramienta como minikube que esté instalada primero y entonces volver a ejecutar los comandos indicados arriba.
Si kubectl cluster-info devuelve la respuesta en forma de url, pero no puedes acceder a tu clúster, para comprobar si está configurado adecuadamente, usa:
kubectl cluster-info dump
kubectl configuraciones opcionales
Habilitar el auto-completado en el intérprete de comandos
kubectl provee de soporte para auto-completado para Bash y Zsh, ¡que te puede ahorrar mucho uso del teclado!
Abajo están los procedimientos para configurar el auto-completado para Bash (incluyendo la diferencia entre Linux y macOS) y Zsh.
La secuencia de comandos de completado de kubectl para Bash puede ser generado con el comando kubectl completion bash. Corriendo la secuencia de comandos de completado en tu intérprete de comandos habilita el auto-completado de kubectl.
Sin embargo, la secuencia de comandos de completado depende de bash-completion*, lo que significa que tienes que instalar primero este programa (puedes probar si ya tienes bash-completion instalado ejecutando type _init_completion).
Instalar bash-completion
bash-completion es ofrecido por muchos gestores de paquetes (ver aquí). Puedes instalarlo con apt-get install bash-completion o yum install bash-completion, etc.
Los comandos de arriba crean /usr/share/bash-completion/bash_completion, que es la secuencia de comandos principal de bash-completion. Dependiendo de tu gestor de paquetes, tienes que correr manualmente este archivo en tu ~/.bashrc.
Para averiguarlo, recarga tu intérprete de comandos y ejecuta type _init_completion. Si el comando tiene éxito, ya has terminado; si no, añade lo siguiente a tu ~/.bashrc:
source /usr/share/bash-completion/bash_completion
recarga tu intérprete de comandos y verifica que bash-completion está correctamente instalado tecleando type _init_completion.
Habilitar el auto-completado de kubectl
Debes asegurarte que la secuencia de comandos de completado de kubectl corre en todas tus sesiones de tu intérprete de comandos. Hay dos formas en que puedes hacer esto:
Corre la secuencia de comandos de completado en tu ~/.bashrc:
Si tienes un alias para kubectl, puedes extender los comandos de shell para funcionar con ese alias:
echo'alias k=kubectl' >>~/.bashrc
echo'complete -F __start_kubectl k' >>~/.bashrc
Nota: bash-completion corre todas las secuencias de comandos de completado en /etc/bash_completion.d.
Ambas estrategias son equivalentes. Tras recargar tu intérprete de comandos, el auto-completado de kubectl debería estar funcionando.
Introducción
La secuencia de comandos de completado de kubectl para Bash puede generarse con el comando kubectl completion bash. Corriendo la secuencia de comandos de completado en tu intérprete de comandos habilita el auto-completado de kubectl.
Sin embargo, la secuencia de comandos de completado depende de bash-completion*, lo que significa que tienes que instalar primero este programa (puedes probar si ya tienes bash-completion instalado ejecutando type _init_completion).
Advertencia: macOS incluye Bash 3.2 por defecto. La secuencia de comandos de completado de kubectl requiere Bash 4.1+ y no funciona con Bash 3.2. Una posible alternativa es instalar una nueva versión de Bash en macOS (ver instrucciones aquí). Las instrucciones de abajo sólo funcionan si estás usando Bash 4.1+.
Actualizar bash
Las instrucciones asumen que usa Bash 4.1+. Puedes comprobar tu versión de bash con:
echo$BASH_VERSION
Si no es 4.1+, puede actualizar bash con Homebrew:
brew install bash
Recarga tu intérprete de comandos y verifica que estás usando la versión deseada:
echo$BASH_VERSION$SHELL
Usualmente, Homebrew lo instala en /usr/local/bin/bash.
Instalar bash-completion
Puedes instalar bash-completion con Homebrew:
brew install bash-completion@2
Nota: El @2 simboliza bash-completion 2, que es requerido por la secuencia de comandos de completado de kubectl (no funciona con bash-completion 1). Luego, bash-completion 2 requiere Bash 4.1+, eso es por lo que necesitabas actualizar Bash.
Como se indicaba en la salida de brew install (sección "Caveats"), añade las siguientes líneas a tu ~/.bashrc o ~/.bash_profile:
Recarga tu intérprete de comandos y verifica que bash-completion está correctamente instalado tecleando type _init_completion.
Habilitar el auto-completado de kubectl
Debes asegurarte que la secuencia de comandos de completado de kubectl corre en todas tus sesiones de tu intérprete de comenados. Hay múltiples formas en que puedes hacer esto:
Corre la secuencia de comandos de completado en tu ~/.bashrc:
Si has instalado kubectl con Homebrew (como se explica aquí), entonces la secuencia de comandos de completado se instaló automáticamente en /usr/local/etc/bash_completion.d/kubectl. En este caso, no tienes que hacer nada.
Nota: bash-completion (si se instaló con Homebrew) corre todas las secuencias de comandos de completado en el directorio que se ha puesto en la variable de entorno BASH_COMPLETION_COMPAT_DIR.
Todas las estrategias son equivalentes. Tras recargar tu intérprete de comandos, el auto-completado de kubectl debería funcionar.
La secuencia de comandos de completado de kubectl para Zsh puede ser generada con el comando kubectl completion zsh. Corriendo la secuencia de comandos de completado en tu intérprete de comandos habilita el auto-completado de kubectl.
Para hacerlo en todas tus sesiones de tu intérprete de comandos, añade lo siguiente a tu ~/.zshrc:
source <(kubectl completion zsh)
Si tienes alias para kubectl, puedes extender el completado de intérprete de comandos para funcionar con ese alias.
echo'alias k=kubectl' >>~/.zshrc
echo'complete -F __start_kubectl k' >>~/.zshrc
Tras recargar tu intérprete de comandos, el auto-completado de kubectl debería funcionar.
Si obtienes un error como complete:13: command not found: compdef, entonces añade lo siguiente al principio de tu ~/.zshrc:
Leer ´la documentación de kubectl reference](/docs/reference/kubectl/kubectl/)
5.2 - Administrar un clúster
5.2.1 - Administrar un clúster con kubeadm
5.2.2 - Administrar recursos de memoria, CPU y API
5.2.3 - Instalar un proveedor de políticas de red
5.3 - Configurar pods y contenedores
5.3.1 - Configura un Pod para Usar un Volume como Almacenamiento
En esta página se muestra cómo configurar un Pod para usar un Volume (volumen) como almacenamiento.
El sistema de ficheros de un Contenedor existe mientras el Contenedor exista. Por tanto, cuando un Contenedor es destruido o reiniciado, los cambios realizados en el sistema de ficheros se pierden. Para un almacenamiento más consistente que sea independiente del ciclo de vida del Contenedor, puedes usar un Volume. Esta característica es especialmente importante para aplicaciones que deben mantener un estado, como motores de almacenamiento clave-valor (por ejemplo Redis) y bases de datos.
Antes de empezar
Debes tener un cluster Kubernetes a tu dispocición, y la herramienta de línea de comandos kubectl debe estar configurada. Si no tienes un cluster, puedes crear uno utilizando Minikube,
o puedes utilizar una de las siguientes herramientas en línea:
Para comprobar la versión, introduzca kubectl version.
Configura un Volume para un Pod
En este ejercicio crearás un Pod que ejecuta un único Contenedor. Este Pod tiene un Volume de tipo emptyDir (directorio vacío) que existe durante todo el ciclo de vida del Pod, incluso cuando el Contenedor es destruido y reiniciado. Aquí está el fichero de configuración del Pod:
Verifica que el Contenedor del Pod se está ejecutando y después observa los cambios en el Pod
kubectl get pod redis --watch
La salida debería ser similar a:
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
En otro terminal, abre una sesión interactiva dentro del Contenedor que se está ejecutando:
kubectl exec -it redis -- /bin/bash
En el terminal, ve a /data/redis y crea un fichero:
root@redis:/data# cd /data/redis/
root@redis:/data/redis# echo Hello > test-file
En el terminal, lista los procesos en ejecución:
root@redis:/data/redis# apt-get update
root@redis:/data/redis# apt-get install procps
root@redis:/data/redis# ps aux
La salida debería ser similar a:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
redis 1 0.1 0.1 333083828 ? Ssl 00:46 0:00 redis-server *:6379
root 12 0.0 0.0 202283020 ? Ss 00:47 0:00 /bin/bash
root 15 0.0 0.0 175002072 ? R+ 00:48 0:00 ps aux
En el terminal, mata el proceso de Redis:
root@redis:/data/redis# kill <pid>
donde <pid> es el ID de proceso (PID) de Redis.
En el terminal original, observa los cambios en el Pod de Redis. Eventualmente verás algo como lo siguiente:
NAME READY STATUS RESTARTS AGE
redis 1/1 Running 0 13s
redis 0/1 Completed 0 6m
redis 1/1 Running 1 6m
En este punto, el Contenedor ha sido destruido y reiniciado. Esto es debido a que el Pod de Redis tiene una
restartPolicy (política de reinicio)
de Always (siempre).
Abre un terminal en el Contenedor reiniciado:
kubectl exec -it redis -- /bin/bash
En el terminal, ve a /data/redis y verifica que test-file todavía existe:
root@redis:/data/redis# cd /data/redis/
root@redis:/data/redis# ls
test-file
Elimina el Pod que has creado para este ejercicio:
Además del almacenamiento local proporcionado por emptyDir, Kubernetes soporta diferentes tipos de soluciones de almacenamiento por red, incluyendo los discos gestionados de los diferentes proveedores cloud, como por ejemplo los Persistent Disks en Google Cloud Platform o el Elastic Block Storage de Amazon Web Services. Este tipo de soluciones para volúmenes son las preferidas para el almacenamiento de datos críticos. Kubernetes se encarga de todos los detalles, tal como montar y desmontar los dispositivos en los nodos del clúster. Revisa Volumes para obtener más información.
5.4 - Administrar Objetos en Kubernetes
Interactuando con el API de Kubernetes aplicando paradigmas declarativo e imperativo.
5.4.1 - Administración declarativa de Objetos en Kubernetes usando archivos de Configuración
Objetos en Kubernetes pueden ser creados, actualizados y eliminados utilizando
archivos de configuración almacenados en un directorio. Usando el comando
kubectl apply podrá crearlos o actualizarlos de manera recursiva según sea necesario.
Este método retiene cualquier escritura realizada contra objetos activos en el
sistema sin unirlos de regreso a los archivos de configuración. kubectl diff le
permite visualizar de manera previa los cambios que apply realizará.
Debes tener un cluster Kubernetes a tu dispocición, y la herramienta de línea de comandos kubectl debe estar configurada. Si no tienes un cluster, puedes crear uno utilizando Minikube,
o puedes utilizar una de las siguientes herramientas en línea:
La configuración de objetos declarativa requiere una comprensión firme de la
definición y configuración de objetos de Kubernetes. Si aún no lo ha hecho, lea
y complete los siguientes documentos:
A continuación la definición de términos usados en este documento:
archivo de configuración de objeto / archivo de configuración: Un archivo en el
que se define la configuración de un objeto de Kubernetes. Este tema muestra como
utilizar archivos de configuración con kubectl apply. Los archivos de configuración
por lo general se almacenan en un sistema de control de versiones, como Git.
configuración activa de objeto / configuración activa: Los valores de configuración
activos de un objeto, según estén siendo observados por el Clúster. Esta configuración
se almacena en el sistema de almacenamiento de Kubernetes, usualmente etcd.
escritor de configuración declarativo / escritor declarativo: Una persona o
componente de software que actualiza a un objeto activo. Los escritores activos a
los que se refiere este tema aplican cambios a los archivos de configuración de objetos
y ejecutan kubectl apply para aplicarlos.
Como crear objetos
Utilice kubectl apply para crear todos los objetos definidos en los archivos
de configuración existentes en un directorio específico, con excepción de aquellos que
ya existen:
kubectl apply -f <directorio>/
Esto definirá la anotación kubectl.kubernetes.io/last-applied-configuration: '{...}'
en cada objeto. Esta anotación contiene el contenido del archivo de configuración
utilizado para la creación del objeto.
Nota: Agregue la opción -R para procesar un directorio de manera recursiva.
El siguiente es un ejemplo de archivo de configuración para un objeto:
diff utiliza server-side dry-run,
que debe estar habilitado en el kube-apiserver.
Dado que diff ejecuta una solicitud de apply en el servidor en modo de simulacro (dry-run),
requiere obtener permisos de PATCH, CREATE, y UPDATE.
Vea Autorización Dry-Run
para más detalles.
Despliegue la configuración activa usando kubectl get:
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
La salida le mostrará que la anotación kubectl.kubernetes.io/last-applied-configuration
fue escrita a la configuración activa, y es consistente con los contenidos del archivo
de configuración:
kind:Deploymentmetadata:annotations:# ...# Esta es la representación JSON de simple_deployment.yaml# Fue escrita por kubectl apply cuando el objeto fue creadokubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}# ...spec:# ...minReadySeconds:5selector:matchLabels:# ...app:nginxtemplate:metadata:# ...labels:app:nginxspec:containers:- image:nginx:1.14.2# ...name:nginxports:- containerPort:80# ...# ...# ...# ...
Como actualizar objetos
También puede usar kubectl apply para actualizar los objetos definidos en un directorio,
aún cuando esos objetos ya existan en la configuración activa. Con este enfoque logrará
lo siguiente:
Definir los campos que aparecerán en la configuración activa.
Eliminar aquellos campos eliminados en el archivo de configuración, de la configuración activa.
Nota: Con el propósito de ilustrar, el comando anterior se refiere a un único archivo
de configuración en vez de un directorio.
Despliegue la configuración activa usando kubectl get:
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
La salida le mostrará que la anotación kubectl.kubernetes.io/last-applied-configuration
fue escrita a la configuración activa, y es consistente con los contenidos del archivo
de configuración:
kind:Deploymentmetadata:annotations:# ...# Esta es la representación JSON de simple_deployment.yaml# Fue escrita por kubectl apply cuando el objeto fue creadokubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}# ...spec:# ...minReadySeconds:5selector:matchLabels:# ...app:nginxtemplate:metadata:# ...labels:app:nginxspec:containers:- image:nginx:1.14.2# ...name:nginxports:- containerPort:80# ...# ...# ...# ...
De manera directa, actualice el campo replicas en la configuración activa usando kubectl scale.
En este caso no se usa kubectl apply:
Despliegue la configuración activa usando kubectl get:
kubectl get deployment nginx-deployment -o yaml
La salida le muestra que el campo replicas ha sido definido en 2, y que la
anotación last-applied-configuration no contiene el campo replicas:
apiVersion:apps/v1kind:Deploymentmetadata:annotations:# ...# note que la anotación no contiene replicas# debido a que el objeto no fue actualizado usando applykubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}# ...spec:replicas:2# definido por scale# ...minReadySeconds:5selector:matchLabels:# ...app:nginxtemplate:metadata:# ...labels:app:nginxspec:containers:- image:nginx:1.14.2# ...name:nginxports:- containerPort:80# ...
Actualice el archivo de configuración simple_deployment.yaml para cambiar el campo image
de nginx:1.14.2 a nginx:1.16.1, y elimine el campo minReadySeconds:
apiVersion:apps/v1kind:Deploymentmetadata:name:nginx-deploymentspec:selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.16.1# actualice el valor de imageports:- containerPort:80
Aplique los cambios realizados al archivo de configuración:
Despliegue la configuración activa usando kubectl get:
kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml
La salida le mostrará los siguientes cambios hechos a la configuración activa:
El campo replicas retiene el valor de 2 definido por kubectl scale.
Esto es posible ya que el campo fue omitido en el archivo de configuración.
El campo image ha sido actualizado de nginx:1.16.1 a nginx:1.14.2.
La anotación last-applied-configuration ha sido actualizada con la nueva imagen.
El campo minReadySeconds ha sido despejado.
La anotación last-applied-configuration ya no contiene el campo minReadySeconds
apiVersion:apps/v1kind:Deploymentmetadata:annotations:# ...# La anotación contiene la imagen acutalizada a nginx 1.11.9,# pero no contiene la actualización de las replicas a 2kubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}# ...spec:replicas:2# Definido por `kubectl scale`. Ignorado por `kubectl apply`.# minReadySeconds fue despejado por `kubectl apply`# ...selector:matchLabels:# ...app:nginxtemplate:metadata:# ...labels:app:nginxspec:containers:- image:nginx:1.16.1# Definido `kubectl apply`# ...name:nginxports:- containerPort:80# ...# ...# ...# ...
Advertencia: No se puede combinar kubectl apply con comandos de configuración imperativa de objetos
como create y replace. Esto se debe a que create
y replace no retienen la anotación kubectl.kubernetes.io/last-applied-configuration
que kubectl apply utiliza para calcular los cambios por realizar.
Como eliminar objetos
Hay dos opciones diferentes para eliminar objetos gestionados por kubectl apply.
Manera recomendada: kubectl delete -f <archivo>
La manera recomendada de eliminar objetos de manera manual es utilizando el comando
imperativo, ya que es más explícito en relación a lo que será eliminado, y es
menos probable que resulte en algo siendo eliminado sin la intención del usuario.
kubectl delete -f <archivo>
Manera alternativa: kubectl apply -f <directorio/> --prune -l etiqueta=deseada
Únicamente utilice esta opción si está seguro de saber lo que está haciendo.
Advertencia:kubectl apply --prune se encuentra aún en alpha, y cambios incompatibles con versiones previas
podrían ser introducidos en lanzamientos futuros.
Advertencia: Sea cuidadoso(a) al usar este comando, para evitar eliminar objetos
no intencionalmente.
Como una alternativa a kubectl delete, puede usar kubectl apply para identificar objetos a ser
eliminados, luego de que sus archivos de configuración han sido eliminados del directorio. El commando apply con --prune
consulta a la API del servidor por todos los objetos que coincidan con un grupo de etiquetas, e intenta relacionar
la configuración obtenida de los objetos activos contra los objetos según sus archivos de configuración.
Si un objeto coincide con la consulta, y no tiene un archivo de configuración en el directorio, pero si
tiene una anotación last-applied-configuration, entonces será eliminado.
Advertencia:apply con --prune debería de ser ejecutado únicamente en contra del directorio
raíz que contiene los archivos de configuración. Ejecutarlo en contra de sub-directorios
podría causar que objetos sean eliminados no intencionalmente, si son retornados en la
consulta por selección de etiqueta usando -l <etiquetas> y no existen en el subdirectorio.
Como visualizar un objeto
Puede usar kubectl get con -o yaml para ver la configuración de objetos activos:
kubectl get -f <archivo|url> -o yaml
Como son las diferencias calculadas y unidas por apply
Precaución: Un patch (parche) es una operación de actualización con alcance a campos específicos
de un objeto, y no al objeto completo. Esto permite actualizar únicamente grupos de campos
específicos en un objeto sin tener que leer el objeto primero.
Cuando kubectl apply actualiza la configuración activa para un objeto, lo hace enviando
una solicitud de patch al servidor de API. El patch define actualizaciones para campos
específicos en la configuración del objeto activo. El comando kubectl apply calcula esta solicitud
de patch usando el archivo de configuración, la configuración activa, y la anotación last-applied-configuration
almacenada en la configuración activa.
Calculando la unión de un patch
El comando kubectl apply escribe los contenidos de la configuración a la anotación
kubectl.kubernetes.io/last-applied-configuration. Esto es usado para identificar aquellos campos
que han sido eliminados de la configuración y deben ser limpiados. Los siguientes pasos
son usados para calcular que campos deben ser eliminados o definidos:
Calculo de campos por eliminar. Estos son los campos presentes en last-applied-configuration pero ausentes en el archivo de configuración.
Calculo de campos por agregar o definir. Estos son los campos presentes en el archivo de configuración, con valores inconsistentes con la configuración activa.
A continuación un ejemplo. Suponga que este es el archivo de configuración para un objeto de tipo Deployment:
apiVersion:apps/v1kind:Deploymentmetadata:name:nginx-deploymentspec:selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.16.1# actualice el valor de imageports:- containerPort:80
También, suponga que esta es la configuración activa para ese mismo objeto de tipo Deployment:
apiVersion:apps/v1kind:Deploymentmetadata:annotations:# ...# tome nota de que la anotación no contiene un valor para replicas# dado que no fue actualizado usando el comando applykubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}# ...spec:replicas:2# definidas por scale# ...minReadySeconds:5selector:matchLabels:# ...app:nginxtemplate:metadata:# ...labels:app:nginxspec:containers:- image:nginx:1.14.2# ...name:nginxports:- containerPort:80# ...
Estos son los cálculos de unión que serían realizados por kubectl apply:
Calcular los campos por eliminar, leyendo los valores de last-applied-configuration
y comparándolos con los valores en el archivo de configuración.
Limpiar los campos definidos en null de manera explícita en el archivo de configuración
sin tomar en cuenta si se encuentran presentes en la anotación last-applied-configuration.
En este ejemplo, minReadySeconds aparece en la anotación
last-applied-configuration pero no aparece en el archivo de configuración.
Acción: Limpiar minReadySeconds de la configuración activa.
Calcular los campos por ser definidos, al leer los valores del fichero de configuración
y compararlos con los valores en la configuración activa. En este ejemplo, el valor image
en el archivo de configuración, no coincide con el valor en la configuración activa.
Acción: Definir el campo image en la configuración activa.
Definir el valor de la anotación last-applied-configuration para que sea consistente
con el archivo de configuración.
Unir los resultados de 1, 2 y 3, en una única solicitud de patch para enviar al servidor de API.
Esta es la configuración activa como resultado de esta unión:
apiVersion:apps/v1kind:Deploymentmetadata:annotations:# ...# La anotación contiene la imágen actualizada a nginx 1.11.9,# pero no contiene la actualización a 2 replicaskubectl.kubernetes.io/last-applied-configuration:| {"apiVersion":"apps/v1","kind":"Deployment",
"metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
"spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
"spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
"ports":[{"containerPort":80}]}]}}}}# ...spec:selector:matchLabels:# ...app:nginxreplicas:2# Definido por `kubectl scale`. Ignorado por `kubectl apply`.# minReadySeconds eliminado por `kubectl apply`# ...template:metadata:# ...labels:app:nginxspec:containers:- image:nginx:1.16.1# Definido por `kubectl apply`# ...name:nginxports:- containerPort:80# ...# ...# ...# ...
Como se unen los diferentes tipos de campos
La manera en la que los campos en un archivo de configuración son unidos con la
configuración activa depende del tipo de campo. Existen varios tipos de campos:
primitivo: Campos de cadena de texto (string), enteros (integer), o lógicos (boolean).
Por ejemplo, image y replicas son campos de tipo primitivo. Acción: Reemplazarlos.
mapa, también llamados objeto: Campo de tipo mapa o un tipo
complejo que contiene sub-campos. Por ejemplo, labels,
annotations,spec y metadata son todos mapas. Acción: Unir los elementos o sub-campos.
lista: Campos que contienen una lista de elementos que pueden ser de tipo primitivo o mapa.
Como ejemplos, containers, ports, y args son listas. Acción: Varía.
Cuando kubectl apply actualiza un campo de tipo mapa o lista, típicamente no reemplaza
el campo completo, sino actualiza los sub-elementos individuales.
Por ejemplo, cuando se hace una unión del campo spec en un Deployment, el spec
completo no es reemplazado, por el contrario, únicamente los sub-campos de spec como
replica son comparados y unidos.
Uniendo cambios en campos primitivos
Campos primitivos son limpiados o reemplazados.
Nota:- determina que "no aplica" debido a que el valor no es utilizado.
Campo en el archivo de configuración
Campo en la configuración activa
Campo en last-applied-configuration
Acción
Si
Si
-
Define el valor en el archivo de configuración como activo.
Si
No
-
Define el valor a la configuración local.
No
-
Si
Elimina de la configuración activa.
No
-
No
No hacer nada. Mantiene el valor activo.
Uniendo cambios en campos de un mapa
Los campos que conjuntamente representan un mapa, son unidos al comparar cada uno de los subcampos o elementos del mapa:
Nota:- determina que "no aplica" debido a que el valor no es utilizado.
Propiedad en archivo de configuración
Propiedad en configuración activa
Campo en last-applied-configuration
Acción
Si
Si
-
Comparar valores de sub-propiedades.
Si
No
-
Usar configuración local.
No
-
Si
Eliminar de la configuración activa.
No
-
No
No hacer nada. Mantener el valor activo.
Uniendo cambios en campos de tipo lista
El unir cambios en una lista utiliza una de tres posibles estrategias:
Reemplazar la lista si todos sus elementos son primitivos.
Unir elementos individuales en líneas de elementos complejos.
Unir una lista de elementos primitivos.
Se define la estrategia elegida con base en cada campo.
Reemplazar una lista si todos sus elementos son primitivos
Trata la lista como si fuese un campo primitivo. Reemplaza o elimina la lista completa.
Esto preserva el orden de los elementos.
Ejemplo: Usando kubectl apply para actualizar el campo args de un Contenedor en un Pod.
Esto define el valor de args en la configuración activa, al valor en el archivo de configuración.
Cualquier elemento de args que haya sido previamente agregado a la configuración activa se perderá.
El orden de los elementos definidos en args en el archivo de configuración, serán conservados
en la configuración activa.
# valor en last-applied-configurationargs:["a","b"]# valores en archivo de configuraciónargs:["a","c"]# configuración activaargs:["a","b","d"]# resultado posterior a la uniónargs:["a","c"]
Explicación: La unión utilizó los valores del archivo de configuración para definir los nuevos valores de la lista.
Unir elementos individuales en una lista de elementos complejos
Trata la lista como un mapa, y trata cada campo específico de cada elemento como una llave.
Agrega, elimina o actualiza elementos individuales. Esta operación no conserva el orden.
Esta estrategia de unión utiliza una etiqueta especial en cada campo llamada patchMergeKey. La etiqueta
patchMergeKey es definida para cada campo en el código fuente de Kubernetes:
types.go
Al unir una lista de mapas, el campo especificado en patchMergeKey para el elemento dado
se utiliza como un mapa de llaves para ese elemento.
Ejemplo: Utilice kubectl apply para actualizar el campo containers de un PodSpec.
Esto une la lista como si fuese un mapa donde cada elemento utiliza name por llave.
# valor en last-applied-configurationcontainers:- name:nginximage:nginx:1.16- name: nginx-helper-a # llave:nginx-helper-a; será eliminado en resultadoimage:helper:1.3- name: nginx-helper-b # llave:nginx-helper-b; será conservadoimage:helper:1.3# valor en archivo de configuracióncontainers:- name:nginximage:nginx:1.16- name:nginx-helper-bimage:helper:1.3- name: nginx-helper-c # llavel:nginx-helper-c; será agregado en el resultadoimage:helper:1.3# configuración activacontainers:- name:nginximage:nginx:1.16- name:nginx-helper-aimage:helper:1.3- name:nginx-helper-bimage:helper:1.3args:["run"]# Campo será conservado- name: nginx-helper-d # llave:nginx-helper-d; será conservadoimage:helper:1.3# resultado posterior a la unióncontainers:- name:nginximage:nginx:1.16# Elemento nginx-helper-a fue eliminado- name:nginx-helper-bimage:helper:1.3args:["run"]# Campo fue conservado- name:nginx-helper-c# Elemento fue agregadoimage:helper:1.3- name:nginx-helper-d# Elemento fue ignoradoimage:helper:1.3
Explicación:
El contenedor llamado "nginx-helper-a" fué eliminado al no aparecer ningún
contenedor llamado "nginx-helper-a" en el archivo de configuración.
El contenedor llamado "nginx-helper-b" mantiene los cambios existentes en args
en la configuración activa. kubectl apply pudo identificar que
el contenedor "nginx-helper-b" en la configuración activa es el mismo
"nginx-helper-b" que aparece en el archivo de configuración, aún teniendo diferentes
valores en los campos (no existe args en el archivo de configuración). Esto sucede
debido a que el valor del campo patchMergeKey (name) es idéntico en ambos.
El contenedor llamado "nginx-helper-c" fue agregado ya que no existe ningún contenedor
con ese nombre en la configuración activa, pero si existe uno con ese nombre
en el archivo de configuración.
El contendor llamado "nginx-helper-d" fue conservado debido a que no aparece
ningún elemento con ese nombre en last-applied-configuration.
Unir una lista de elementos primitivos
A partir de Kubernetes 1.5, el unir listas de elementos primitivos no es soportado.
Nota: La etiqueta patchStrategy en types.go es la que
determina cual de las estrategias aplica para cualquier campo en particular.
Para campos de tipo lista, el campo será reemplazado cuando no exista una especificación de patchStrategy.
Valores de campo por defecto
El Servidor de API define algunos campos a sus valores por defecto si no son especificados
al momento de crear un objeto.
Aquí puede ver un archivo de configuración para un Deployment. Este archivo no especifica
el campo strategy:
Despliegue la configuración activa usando kubectl get:
kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml
La salida muestra que el servidor de API definió varios campos con los valores por defecto
en la configuración activa. Estos campos no fueron especificados en el archivo de
configuración.
apiVersion:apps/v1kind:Deployment# ...spec:selector:matchLabels:app:nginxminReadySeconds:5replicas:1# valor por defecto definido por apiserverstrategy:rollingUpdate:# valor por defecto definido por apiserver - derivado de strategy.typemaxSurge:1maxUnavailable:1type:RollingUpdate# valor por defecto definido por apiservertemplate:metadata:creationTimestamp:nulllabels:app:nginxspec:containers:- image:nginx:1.14.2imagePullPolicy:IfNotPresent# valor por defecto definido por apiservername:nginxports:- containerPort:80protocol:TCP# valor por defecto definido por apiserverresources:{}# valor por defecto definido por apiserverterminationMessagePath:/dev/termination-log# valor por defecto definido por apiserverdnsPolicy:ClústerFirst# valor por defecto definido por apiserverrestartPolicy:Always# valor por defecto definido por apiserversecurityContext:{}# valor por defecto definido por apiserverterminationGracePeriodSeconds:30# valor por defecto definido por apiserver# ...
En una solicitud de patch, los campos definidos a valores por defecto no son redefinidos a excepción
de cuando hayan sido limpiados de manera explícita como parte de la solicitud de patch. Esto puede
causar comportamientos no esperados para campos cuyo valor por defecto es basado en los valores
de otros campos. Cuando el otro campo ha cambiado, el valor por defecto de ellos no será actualizado
de no ser que sean limpiados de manera explícita.
Por esta razón, se recomienda que algunos campos que reciben un valor por defecto del
servidor sean definidos de manera explícita en los archivos de configuración, aun cuando
el valor definido sea idéntico al valor por defecto. Esto facilita la identificación
de valores conflictivos que podrían no ser revertidos a valores por defecto por parte
del servidor.
Ejemplo:
# last-applied-configurationspec:template:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.14.2ports:- containerPort:80# archivo de configuraciónspec:strategy:type:Recreate# valor actualizadotemplate:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.14.2ports:- containerPort:80# configuración activaspec:strategy:type:RollingUpdate# valor por defectorollingUpdate:# valor por defecto derivado del campo typemaxSurge :1maxUnavailable:1template:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.14.2ports:- containerPort:80# resultado posterior a la unión - ERROR!spec:strategy:type: Recreate # valor actualizado:incompatible con RollingUpdaterollingUpdate: # valor por defecto:incompatible con "type: Recreate"maxSurge :1maxUnavailable:1template:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.14.2ports:- containerPort:80
Explicación:
El usuario crea un Deployment sin definir strategy.type.
El servidor define strategy.type a su valor por defecto de RollingUpdate y
agrega los valores por defecto a strategy.rollingUpdate.
El usuario cambia strategy.type a Recreate. Los valores de strategy.rollingUpdate
se mantienen en su configuración por defecto, sin embargo el servidor espera que se limpien.
Si los valores de strategy.rollingUpdate hubiesen sido definidos inicialmente en el archivo
de configuración, hubiese sido más claro que requerían ser eliminados.
Apply fallará debido a que strategy.rollingUpdate no fue eliminado. El campo strategy.rollingupdate
no puede estar definido, si el valor de strategy.type es Recreate.
Recomendación: Estos campos deberían de ser definidos de manera explícita en el archivo de configuración:
Etiquetas de Selectors y PodTemplate en cargas de trabajo como Deployment, StatefulSet, Job, DaemonSet,
ReplicaSet, y ReplicationController
Estrategia de rollout para un Deployment
Como limpiar campos definidos a valores por defecto por el servidor, o definidos por otros escritores
Campos que no aparecen en el archivo de configuración pueden ser limpiados si se define su valor
a null y luego se aplica el archivo de configuración.
Para los campos definidos a valores por defecto por el servidor, esto provoca que se reestablezca
a sus valores por defecto.
Como cambiar al propietario de un campo entre un archivo de configuración y un escritor imperativo
Estos son los únicos métodos que debe usar para cambiar un campo individual de un objeto:
Usando kubectl apply.
Escribiendo de manera directa a la configuración activa sin modificar el archivo de configuración:
por ejemplo, usando kubectl scale.
Cambiando al propietario de un campo de un escritor imperativo a un archivo de configuración
Añada el campo al archivo de configuración, y no realice nuevas actualizaciones a la configuración
activa que no sucedan por medio de kubectl apply.
Cambiando al propietario de un archivo de configuración a un escritor imperativo
A partir de Kubernetes 1.5, el cambiar un campo que ha sido definido por medio de un
archivo de configuración para que sea modificado por un escritor imperativo requiere
pasos manuales:
Eliminar el campo del archivo de configuración.
Eliminar el campo de la anotación kubectl.kubernetes.io/last-applied-configuration en el objeto activo.
Cambiando los métodos de gestión
Los objetos en Kubernetes deberían de ser gestionados utilizando únicamente un método
a la vez. El alternar de un método a otro es posible, pero es un proceso manual.
Nota: Esta bien el usar eliminación imperativa junto a gestión declarativa.
Migrando de gestión imperativa con comandos a configuración declarativa de objetos
El migrar de gestión imperativa utilizando comandos a la gestión declarativa de objetos
requiere varios pasos manuales:
Exporte el objeto activo a un archivo local de configuración:
kubectl get <tipo>/<nombre> -o yaml > <tipo>_<nombre>.yaml
Elimine de manera manual el campo status del archivo de configuración.
Nota: Este paso es opcional, ya que kubectl apply no actualiza el campo status
aunque este presente en el archivo de configuración.
Defina la anotación kubectl.kubernetes.io/last-applied-configuration en el objeto:
Modifique el proceso para usar kubectl apply para gestionar el objeto de manera exclusiva.
Definiendo los selectores para el controlador y las etiquetas de PodTemplate
Advertencia: Se desaconseja encarecidamente actualizar los selectores en controladores.
La forma recomendada es definir una etiqueta única e inmutable para PodTemplate usada
únicamente por el selector del controlador sin tener ningún otro significado semántico.
5.6.1 - Corre una aplicación stateless usando un Deployment
Ésta página enseña como correr una aplicación stateless usando un deployment de Kubernetes.
Objetivos
Crear un deployment de nginx.
Usar kubectl para obtener información acerca del deployment.
Actualizar el deployment.
Antes de empezar
Debes tener un cluster Kubernetes a tu dispocición, y la herramienta de línea de comandos kubectl debe estar configurada. Si no tienes un cluster, puedes crear uno utilizando Minikube,
o puedes utilizar una de las siguientes herramientas en línea:
Su versión de Kubernetes debe ser como mínimo v1.9.
Para comprobar la versión, introduzca kubectl version.
Creando y explorando un nginx deployment
Puedes correr una aplicación creando un deployment de Kubernetes, y puedes describir el deployment en un fichero YAML. Por ejemplo, el siguiente fichero YAML describe un deployment que corre la imágen Docker nginx:1.7.9:
apiVersion:apps/v1# Usa apps/v1beta2 para versiones anteriores a 1.9.0kind:Deploymentmetadata:name:nginx-deploymentspec:selector:matchLabels:app:nginxreplicas:2# indica al controlador que ejecute 2 podstemplate:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.7.9ports:- containerPort:80
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 30 Aug 2016 18:11:37 -0700
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=1
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.7.9
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1771418926 (2/2 replicas created)
No events.
Lista los pods creados por el deployment:
kubectl get pods -l app=nginx
El resultado es similar a esto:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1771418926-7o5ns 1/1 Running 0 16h
nginx-deployment-1771418926-r18az 1/1 Running 0 16h
Muestra información acerca del pod:
kubectl describe pod <pod-name>
donde <pod-name> es el nombre de uno de los pods.
Actualizando el deployment
Puedes actualizar el deployment aplicando un nuevo fichero YAML. El siguiente fichero YAML
especifica que el deployment debería ser actualizado para usar nginx 1.8.
apiVersion:apps/v1# Usa apps/v1beta2 para versiones anteriores a 1.9.0kind:Deploymentmetadata:name:nginx-deploymentspec:selector:matchLabels:app:nginxreplicas:2template:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.8# Actualiza la versión de nginx de 1.7.9 a 1.8ports:- containerPort:80
Comprueba como el deployment crea nuevos pods con la nueva imagen mientras va eliminando los pods con la especificación antigua:
kubectl get pods -l app=nginx
Escalando la aplicación aumentado el número de replicas
Puedes aumentar el número de pods en tu deployment aplicando un nuevo fichero YAML.
El siguiente fichero YAML especifica un total de 4 replicas, lo que significa que el deployment debería tener cuatro pods:
apiVersion:apps/v1# Usa apps/v1beta2 para versiones anteriores a 1.9.0kind:Deploymentmetadata:name:nginx-deploymentspec:selector:matchLabels:app:nginxreplicas:4# Actualiza el número de réplicas de 2 a 4template:metadata:labels:app:nginxspec:containers:- name:nginximage:nginx:1.8ports:- containerPort:80
NAME READY STATUS RESTARTS AGE
nginx-deployment-148880595-4zdqq 1/1 Running 0 25s
nginx-deployment-148880595-6zgi1 1/1 Running 0 25s
nginx-deployment-148880595-fxcez 1/1 Running 0 2m
nginx-deployment-148880595-rwovn 1/1 Running 0 2m
Eliminando un deployment
Elimina el deployment por el nombre:
kubectl delete deployment nginx-deployment
ReplicationControllers
La manera preferida de crear una aplicación con múltiples instancias es usando un Deployment, el cual usa un ReplicaSet. Antes de que Deployment y ReplicaSet fueran introducidos en Kubernetes, aplicaciones con múltiples instancias eran configuradas usando un
ReplicationController.
5.6.2 - Especificando un presupuesto de disrupción para tu aplicación
Ésta pagina enseña como limitar el numero de disrupciones concurrentes que afectan a tu aplicación definiendo presupuestos de disrupción de pods, Pod Disruption Budgets (PDB) en inglés. Estos presupuestos definen el mínimo número de pods que deben estar ejecutándose en todo momento para asegurar la disponibilidad de la aplicación durante operaciones de mantenimiento efectuadas sobre los nodos por los administradores del cluster.
Antes de empezar
Tener permisos de administrador sobre la aplicación que esta corriendo en Kubernetes y requiere alta disponibilidad
Deberías confirmar con el propietario del cluster o proveedor de servicio que respetan Presupuestos de Disrupción para Pods.
Protegiendo una aplicación con un PodDisruptionBudget
Identifica la aplicación que quieres proteger con un PodDisruptionBudget (PDB).
Revisa como afectan las disrupciones a tú aplicación.
Crea un PDB usando un archivo YAML.
Crea el objecto PDB desde el archivo YAML.
Identifica la applicación que quieres proteger
El caso más común es proteger aplicaciones que usan uno de los controladores incorporados
en Kubernetes:
Deployment
Replicationcontrolador
ReplicaSet
StatefulSet
En este caso, toma nota del .spec.selector que utiliza el controlador; el mismo se utilizará en el spec.selector del PDB.
También puedes utilizar PDBs para proteger pods que no estan gestionados por uno de los controladores listados arriba, o agrupaciones arbitrarias de pods, con algunas restricciones descritas en Controladores Arbitrarios y Selectors.
Revisa como afectan las disrupciones a tú aplicación
Decide cuántas instancias de tu aplicación pueden estar fuera de servicio al mismo
tiempo debido a disrupciones voluntarias de corto plazo.
Frontend stateless:
Objetivo: evitar reducir capacidad para servir por mas de 10%.
Solución: usar un PDB que especifica minAvailable 90%.
Aplicación Stateful con una sola instancia:
Objetivo: no terminar esta aplicación sin primero confirmar conmigo.
Posible Solución 1: No usar un PDB y tolerar inactividad ocasional.
Posible Solución 2: Crea un PDB con maxUnavailable=0. Entiende que el operador del cluster debe consultar contigo antes de terminar tu aplicación. Cuando el operador te contacte, prepara tu aplicación para downtime y elimina el PDB para indicar que estas preparado para la disrupción. Crea el PDB de nuevo al terminar la disrupción.
Aplicación Stateful con múltiples instancias como Consul, ZooKeeper, etcd, Redis o MySQL:
Objetivo: no reducir el numero de instancias por debajo del quorum, de lo contrario, las escrituras fallarían.
Posible Solución 1: fijar maxUnavailable a 1 (funciona con diferentes escalas de aplicación).
Posible Solución 2: fijar minAvailable al tamaño del quorum (e.g. 3 cuando hay un total de 5 instancias). (Permite mas disrupciones a la vez.).
Trabajos por lote reiniciables:
Objetivo: El trabajo debe completarse en caso de una interrupción voluntaria.
Posible solución: No cree un PDB. El controlador de Jobs creará un pod de reemplazo.
Especificando un PodDisruptionBudget
Un PodDisruptionBudget tiene tres atributos:
Un label selector .spec.selector para especificar el grupo de
pods donde aplicar el presupuesto. Este campo es requerido.
.spec.minAvailable que es una descripción del número de pods del grupo que deben estar disponibles después del desalojo, incluso en ausencia del pod desalojado. minAvailable puede ser un número absoluto o un porcentaje.
.spec.maxUnavailable (disponible en Kubernetes 1.7 y superior) que es una descripción
del numero de pods del grupo que pueden estar indisponibles despues del desalojo. Puede ser un número absoluto o un porcentaje.
Nota: Para las versiones 1.8 y anteriores: al crear un PodDisruptionBudget
utilizando la herramienta de línea de comandos kubectl, el campo minAvailable es 1 por defecto si no se especifica minAvailable ni maxUnavailable.
Puedes especificar únicamente un valor para maxUnavailable y minAvailable por PodDisruptionBudget.
maxUnavailable solo se puede usar para controlar el desalojo de pods
que tienen un controlador asociado manejándolos. En los ejemplos a continuación, "réplicas deseadas"
hace referencia al valor 'scale' del controlador que gestiona el grupo de pods seleccionados por el
PodDisruptionBudget.
Ejemplo 1: Con un minAvailable de 5, se permiten los desalojos siempre que dejen
5 o más pods disponibles entre las seleccionadas por el selector del PodDisruptionBudget.
Ejemplo 2: Con un minAvailable del 30%, se permiten los desalojos mientras que al menos 30% de la cantidad de réplicas se mantengan disponibles.
Ejemplo 3: Con un maxUnavailable de 5, se permiten desalojos siempre que haya como máximo 5
réplicas indisponibles entre el número total de réplicas deseadas.
Ejemplo 4: Con un maxUnavailable de 30%, se permiten los desalojos siempre y cuando no más del 30%
de las réplicas esten indisponibles.
En el uso típico, se usaría un solo presupuesto para una colección de pods administrados por
un controlador, por ejemplo, los pods en un solo ReplicaSet o StatefulSet.
Nota: Un presupuesto de disrupción no garantiza que el número/porcentaje de pods especificado
siempre estarán disponibles. Por ejemplo, un nodo que alberga un
pod del grupo puede fallar cuando el grupo está en el tamaño mínimo
especificados en el presupuesto, lo que hace que el número de pods disponibles este por debajo del tamaño especificado. El presupuesto solo puede proteger contra
desalojos voluntarios, pero no todas las causas de indisponibilidad.
Un maxUnavailable de 0% (o 0) o un minAvailable de 100% (o igual al
número de réplicas) puede prevenir que los nodos sean purgados completamente.
Esto está permitido según la semántica de PodDisruptionBudget.
Puedes encontrar ejemplos de presupuestos de disrupción de pods definidas a continuación. Los ejemplos aplican al grupo de pods que tienen la etiqueta app: zookeeper.
Por ejemplo, si el objeto anterior zk-pdb selecciona los pods de un StatefulSet de tamaño 3, ambas
especificaciones tienen el mismo significado exacto. Se recomienda el uso de maxUnavailable ya que
responde automáticamente a los cambios en el número de réplicas del controlador correspondiente.
Crea el objeto PDB
Puedes crear el objeto PDB con el comando kubectl apply -f mypdb.yaml.
No puedes actualizar objetos PDB. Deben ser eliminados y recreados.
Comprueba el estado del PDB
Utiliza kubectl para comprobar que se ha creado tu PDB.
Suponiendo que en realidad no tengas pods que coincidan con app: zookeeper en su namespace,
entonces verás algo como esto:
kubectl get poddisruptionbudgets
NAME MIN-AVAILABLE ALLOWED-DISRUPTIONS AGE
zk-pdb 2 0 7s
Si hay pods que coinciden (por ejemplo, 3), entonces debes ver algo similar a esto:
kubectl get poddisruptionbudgets
NAME MIN-AVAILABLE ALLOWED-DISRUPTIONS AGE
zk-pdb 2 1 7s
El valor distinto a cero de ALLOWED-DISRUPTIONS significa que el controlador de disrupción ha visto los pods, contó los pods coincidentes, y actualizó el estado del PDB.
Puedes obtener más información sobre el estado de un PDB con este comando:
Por último, los PodDisruptionBudgets también se pueden consultar con kubectl utilizando el nombre corto pdb:
kubectl get pdb
NAME MIN-AVAILABLE ALLOWED-DISRUPTIONS AGE
zk-pdb 20 7s
Controladores y selectors arbitrarios
Puedes omitir esta sección si solo utilizas PDBs con los controladores integrados de aplicaciones (Deployment, Replicationcontrolador, ReplicaSet y StatefulSet), con el selector de PDB coincidiendo con el selector del controlador.
Puedes utilizar un PDB con pods controlados por otro tipo de controlador, por un
"Operator", o pods individuales, pero con las siguientes restricciones:
solo puedes usar .spec.minAvailable, no .spec.maxUnavailable.
solo puedes usar un número entero en .spec.minAvailable, no un porcentaje.
Puedes usar un selector que selecciona un subconjunto o superconjunto de los pods que pertenecen a un controlador incorporado. Sin embargo, cuando hay varios PDB en un namespace, debes tener cuidado de no
crear PDBs cuyos selectores se superponen.
5.7 - Gestionar y ejecutar daemons
5.8 - Gestionar y ejecutar trabajos
5.9 - Acceder al clúster y las aplicaciones
5.10 - Monitorización, Logs y Debugging
5.10.1 - Auditoría
La auditoría de Kubernetes proporciona un conjunto de registros cronológicos referentes a la seguridad
que documentan la secuencia de actividades que tanto los usuarios individuales, como
los administradores y otros componentes del sistema ha realizado en el sistema.
Así, permite al administrador del clúster responder a las siguientes cuestiones:
¿qué ha pasado?
¿cuándo ha pasado?
¿quién lo ha iniciado?
¿sobre qué ha pasado?
¿dónde se ha observado?
¿desde dónde se ha iniciado?
¿hacia dónde iba?
El componente Kube-apiserver lleva a cabo la auditoría. Cada petición en cada fase
de su ejecución genera un evento, que se pre-procesa según un cierto reglamento y
se escribe en un backend. Este reglamento determina lo que se audita
y los backends persisten los registros. Las implementaciones actuales de backend
incluyen los archivos de logs y los webhooks.
Cada petición puede grabarse junto con una "etapa" asociada. Las etapas conocidas son:
RequestReceived - La etapa para aquellos eventos generados tan pronto como
el responsable de la auditoría recibe la petición, pero antes de que sea delegada al
siguiente responsable en la cadena.
ResponseStarted - Una vez que las cabeceras de la respuesta se han enviado,
pero antes de que el cuerpo de la respuesta se envíe. Esta etapa sólo se genera
en peticiones de larga duración (ej. watch).
ResponseComplete - El cuerpo de la respuesta se ha completado y no se enviarán más bytes.
Panic - Eventos que se generan cuando ocurre una situación de pánico.
Nota: La característica de registro de auditoría incrementa el consumo de memoria del servidor API
porque requiere de contexto adicional para lo que se audita en cada petición.
De forma adicional, el consumo de memoria depende de la configuración misma del registro.
Reglamento de Auditoría
El reglamento de auditoría define las reglas acerca de los eventos que deberían registrarse y
los datos que deberían incluir. La estructura del objeto de reglas de auditoría se define
en el audit.k8s.io grupo de API. Cuando se procesa un evento, se compara
con la lista de reglas en orden. La primera regla coincidente establece el "nivel de auditoría"
del evento. Los niveles de auditoría conocidos son:
None - no se registra eventos que disparan esta regla.
Metadata - se registra los metadatos de la petición (usuario que la realiza, marca de fecha y hora, recurso,
verbo, etc.), pero no la petición ni el cuerpo de la respuesta.
Request - se registra los metadatos del evento y el cuerpo de la petición, pero no el cuerpo de la respuesta.
Esto no aplica para las peticiones que no son de recurso.
RequestResponse - se registra los metadatos del evento, y los cuerpos de la petición y la respuesta.
Esto no aplica para las peticiones que no son de recurso.
Es posible indicar un archivo al definir el reglamento en el kube-apiserver
usando el parámetro --audit-policy-file. Si dicho parámetros se omite, no se registra ningún evento.
Nótese que el campo rulesdebe proporcionarse en el archivo del reglamento de auditoría.
Un reglamento sin (0) reglas se considera ilegal.
Abajo se presenta un ejemplo de un archivo de reglamento de auditoría:
apiVersion:audit.k8s.io/v1# Esto es obligatorio.kind:Policy# No generar eventos de auditoría para las peticiones en la etapa RequestReceived.omitStages:- "RequestReceived"rules:# Registrar los cambios del pod al nivel RequestResponse- level:RequestResponseresources:- group:""# Los recursos "pods" no hacen coincidir las peticiones a cualquier sub-recurso de pods,# lo que es consistente con la regla RBAC.resources:["pods"]# Registrar "pods/log", "pods/status" al nivel Metadata- level:Metadataresources:- group:""resources:["pods/log","pods/status"]# No registrar peticiones al configmap denominado "controller-leader"- level:Noneresources:- group:""resources:["configmaps"]resourceNames:["controller-leader"]# No registrar peticiones de observación hechas por "system:kube-proxy" sobre puntos de acceso o servicios- level:Noneusers:["system:kube-proxy"]verbs:["watch"]resources:- group:""# Grupo API baseresources:["endpoints","services"]# No registrar peticiones autenticadas a ciertas rutas URL que no son recursos.- level:NoneuserGroups:["system:authenticated"]nonResourceURLs:- "/api*"# Coincidencia por comodín.- "/version"# Registrar el cuerpo de la petición de los cambios de configmap en kube-system.- level:Requestresources:- group:""# Grupo API baseresources:["configmaps"]# Esta regla sólo aplica a los recursos en el Namespace "kube-system".# La cadena vacía "" se puede usar para seleccionar los recursos sin Namespace.namespaces:["kube-system"]# Registrar los cambios de configmap y secret en todos los otros Namespaces al nivel Metadata.- level:Metadataresources:- group:""# Grupo API baseresources:["secrets","configmaps"]# Registrar todos los recursos en core y extensions al nivel Request.- level:Requestresources:- group:""# Grupo API base- group:"extensions"# La versión del grupo NO debería incluirse.# Regla para "cazar" todos las demás peticiones al nivel Metadata.- level:Metadata# Las peticiones de larga duración, como los watches, que caen bajo esta regla no# generan un evento de auditoría en RequestReceived.omitStages:- "RequestReceived"
Puedes usar un archivo mínimo de reglamento de auditoría para registrar todas las peticiones al nivel Metadata de la siguiente forma:
# Log all requests at the Metadata level.apiVersion:audit.k8s.io/v1kind:Policyrules:- level:Metadata
El perfil de auditoría utilizado por GCE debería servir como referencia para
que los administradores construyeran sus propios perfiles de auditoría.
Backends de auditoría
Los backends de auditoría persisten los eventos de auditoría en un almacenamiento externo.
El Kube-apiserver por defecto proporciona tres backends:
Backend de logs, que escribe los eventos en disco
Backend de webhook, que envía los eventos a una API externa
Backend dinámico, que configura backends de webhook a través de objetos de la API AuditSink.
En todos los casos, la estructura de los eventos de auditoría se define por la API del grupo
audit.k8s.io. La versión actual de la API es
v1.
Nota:
En el caso de parches, el cuerpo de la petición es una matriz JSON con operaciones de parcheado, en vez
de un objeto JSON que incluya el objeto de la API de Kubernetes apropiado. Por ejemplo,
el siguiente cuerpo de mensaje es una petición de parcheado válida para
/apis/batch/v1/namespaces/some-namespace/jobs/some-job-name.
El backend de logs escribe los eventos de auditoría a un archivo en formato JSON.
Puedes configurar el backend de logs de auditoría usando el siguiente
parámetro de kube-apiserver flags:
--audit-log-path especifica la ruta al archivo de log que el backend utiliza para
escribir los eventos de auditoría. Si no se especifica, se deshabilita el backend de logs. - significa salida estándar
--audit-log-maxage define el máximo número de días a retener los archivos de log
--audit-log-maxbackup define el máximo número de archivos de log a retener
--audit-log-maxsize define el tamaño máximo en megabytes del archivo de logs antes de ser rotado
Backend de Webhook
El backend de Webhook envía eventos de auditoría a una API remota, que se supone es la misma API
que expone el kube-apiserver. Puedes configurar el backend de webhook de auditoría usando
los siguientes parámetros de kube-apiserver:
--audit-webhook-config-file especifica la ruta a un archivo con configuración del webhook.
La configuración del webhook es, de hecho, un archivo kubeconfig.
--audit-webhook-initial-backoff especifica la cantidad de tiempo a esperar tras una petición fallida
antes de volver a intentarla. Los reintentos posteriores se ejecutan con retraso exponencial.
El archivo de configuración del webhook usa el formato kubeconfig para especificar la dirección remota
del servicio y las credenciales para conectarse al mismo.
En la versión 1.13, los backends de webhook pueden configurarse dinámicamente.
Procesamiento por lotes
Tanto el backend de logs como el de webhook permiten procesamiento por lotes. Si usamos el webhook como ejemplo,
aquí se muestra la lista de parámetros disponibles. Para aplicar el mismo parámetro al backend de logs,
simplemente sustituye webhook por log en el nombre del parámetro. Por defecto,
el procesimiento por lotes está habilitado en webhook y deshabilitado en log. De forma similar,
por defecto la regulación (throttling) está habilitada en webhook y deshabilitada en log.
--audit-webhook-mode define la estrategia de memoria intermedia (búfer), que puede ser una de las siguientes:
batch - almacenar eventos y procesarlos de forma asíncrona en lotes. Esta es la estrategia por defecto.
blocking - bloquear todas las respuestas del servidor API al procesar cada evento de forma individual.
blocking-strict - igual que blocking, pero si ocurre un error durante el registro de la audtoría en la etapa RequestReceived, la petición completa al apiserver fallará.
Los siguientes parámetros se usan únicamente en el modo batch:
--audit-webhook-batch-buffer-size define el número de eventos a almacenar de forma intermedia antes de procesar por lotes.
Si el ritmo de eventos entrantes desborda la memoria intermedia, dichos eventos se descartan.
--audit-webhook-batch-max-size define el número máximo de eventos en un único proceso por lotes.
--audit-webhook-batch-max-wait define la cantidad máxima de tiempo a esperar de forma incondicional antes de procesar los eventos de la cola.
--audit-webhook-batch-throttle-qps define el promedio máximo de procesos por lote generados por segundo.
--audit-webhook-batch-throttle-burst define el número máximo de procesos por lote generados al mismo tiempo si el QPS permitido no fue usado en su totalidad anteriormente.
Ajuste de parámetros
Los parámetros deberían ajustarse a la carga del apiserver.
Por ejemplo, si kube-apiserver recibe 100 peticiones por segundo, y para cada petición se audita
las etapas ResponseStarted y ResponseComplete, deberías esperar unos ~200
eventos de auditoría generados por segundo. Asumiendo que hay hasta 100 eventos en un lote,
deberías establecer el nivel de regulación (throttling) por lo menos a 2 QPS. Además, asumiendo
que el backend puede tardar hasta 5 segundos en escribir eventos, deberías configurar el tamaño de la memoria intermedia para almacenar hasta 5 segundos de eventos, esto es,
10 lotes, o sea, 1000 eventos.
En la mayoría de los casos, sin embargo, los valores por defecto de los parámetros
deberían ser suficientes y no deberías preocuparte de ajustarlos manualmente.
Puedes echar un vistazo a la siguientes métricas de Prometheus que expone kube-apiserver
y también los logs para monitorizar el estado del subsistema de auditoría:
apiserver_audit_event_total métrica que contiene el número total de eventos de auditoría exportados.
apiserver_audit_error_total métrica que contiene el número total de eventos descartados debido a un error durante su exportación.
Truncado
Tanto el backend de logs como el de webhook permiten truncado. Como ejemplo, aquí se indica la
lista de parámetros disponible para el backend de logs:
audit-log-truncate-enabled indica si el truncado de eventos y por lotes está habilitado.
audit-log-truncate-max-batch-size indica el tamaño máximo en bytes del lote enviado al backend correspondiente.
audit-log-truncate-max-event-size indica el tamaño máximo en bytes del evento de auditoría enviado al backend correspondiente.
Por defecto, el truncado está deshabilitado tanto en webhook como en log; un administrador del clúster debe configurar bien el parámetro audit-log-truncate-enabled o audit-webhook-truncate-enabled para habilitar esta característica.
Backend dinámico
FEATURE STATE:Kubernetes v1.13 [alpha]
En la versión 1.13 de Kubernetes, puedes configurar de forma dinámica los backends de auditoría usando objetos de la API AuditSink.
Para habilitar la auditoría dinámica, debes configurar los siguientes parámetros de apiserver:
--audit-dynamic-configuration: el interruptor principal. Cuando esta característica sea GA, el único parámetro necesario.
--feature-gates=DynamicAuditing=true: en evaluación en alpha y beta.
--runtime-config=auditregistration.k8s.io/v1alpha1=true: habilitar la API.
Cuando se habilita, un objeto AuditSink se provisiona de la siguiente forma:
Para una definición completa de la API, ver AuditSink. Múltiples objetos existirán como soluciones independientes.
Aquellos backends estáticos que se configuran con parámetros en tiempo de ejecución no se ven impactados por esta característica.
Sin embargo, estos backends dinámicos comparten las opciones de truncado del webhook estático, de forma que si dichas opciones se configura con parámetros en tiempo de ejecución, entonces se aplican a todos los backends dinámicos.
Reglamento
El reglamento de AuditSink es diferente del de la auditoría en tiempo de ejecución. Esto es debido a que el objeto de la API sirve para casos de uso diferentes. El reglamento continuará
evolucionando para dar cabida a más casos de uso.
El campo level establece el nivel de auditoría indicado a todas las peticiones. El campo stages es actualmente una lista de las etapas que se permite registrar.
Seguridad
Los administradores deberían tener en cuenta que permitir el acceso en modo escritura de esta característica otorga el modo de acceso de lectura
a toda la información del clúster. Así, el acceso debería gestionarse como un privilegio de nivel cluster-admin.
Rendimiento
Actualmente, esta característica tiene implicaciones en el apiserver en forma de incrementos en el uso de la CPU y la memoria.
Aunque debería ser nominal cuando se trata de un número pequeño de destinos, se realizarán pruebas adicionales de rendimiento para entender su impacto real antes de que esta API pase a beta.
Configuración multi-clúster
Si estás extendiendo la API de Kubernetes mediante la capa de agregación, puedes también
configurar el registro de auditoría para el apiserver agregado. Para ello, pasa las opciones
de configuración en el mismo formato que se describe arriba al apiserver agregado
y configura el mecanismo de ingestión de logs para que recolecte los logs de auditoría.
Cada uno de los apiservers puede tener configuraciones de auditoría diferentes con
diferentes reglamentos de auditoría.
Ejemplos de recolectores de Logs
Uso de fluentd para recolectar y distribuir eventos de auditoría a partir de un archivo de logs
Fluentd es un recolector de datos de libre distribución que proporciona una capa unificada de registros.
En este ejemplo, usaremos fluentd para separar los eventos de auditoría por nombres de espacio:
Instala fluentd, fluent-plugin-forest y fluent-plugin-rewrite-tag-filter en el nodo donde corre kube-apiserver
Nota: Fluent-plugin-forest y fluent-plugin-rewrite-tag-filter son plugins de fluentd. Puedes obtener detalles de la instalación de estos plugins en el documento [fluentd plugin-management][fluentd_plugin_management_doc].
Crea un archivo de configuración para fluentd:
cat <<'EOF' > /etc/fluentd/config
# fluentd conf runs in the same host with kube-apiserver
<source>
@type tail
# audit log path of kube-apiserver
path /var/log/kube-audit
pos_file /var/log/audit.pos
format json
time_key time
time_format %Y-%m-%dT%H:%M:%S.%N%z
tag audit
</source>
<filter audit>
#https://github.com/fluent/fluent-plugin-rewrite-tag-filter/issues/13
@type record_transformer
enable_ruby
<record>
namespace ${record["objectRef"].nil? ? "none":(record["objectRef"]["namespace"].nil? ? "none":record["objectRef"]["namespace"])}
</record>
</filter>
<match audit>
# route audit according to namespace element in context
@type rewrite_tag_filter
<rule>
key namespace
pattern /^(.+)/
tag ${tag}.$1
</rule>
</match>
<filter audit.**>
@type record_transformer
remove_keys namespace
</filter>
<match audit.**>
@type forest
subtype file
remove_prefix audit
<template>
time_slice_format %Y%m%d%H
compress gz
path /var/log/audit-${tag}.*.log
format json
include_time_key true
</template>
</match>
EOF
Arranca fluentd:
fluentd -c /etc/fluentd/config -vv
Arranca el componente kube-apiserver con las siguientes opciones:
Comprueba las auditorías de los distintos espacios de nombres en /var/log/audit-*.log
Uso de logstash para recolectar y distribuir eventos de auditoría desde un backend de webhook
Logstash es una herramienta de libre distribución de procesamiento de datos en servidor.
En este ejemplo, vamos a usar logstash para recolectar eventos de auditoría a partir de un backend de webhook,
y grabar los eventos de usuarios diferentes en archivos distintos.
cat <<EOF > /etc/logstash/config
input{
http{
#TODO, figure out a way to use kubeconfig file to authenticate to logstash
#https://www.elastic.co/guide/en/logstash/current/plugins-inputs-http.html#plugins-inputs-http-ssl
port=>8888
}
}
filter{
split{
# Webhook audit backend sends several events together with EventList
# split each event here.
field=>[items]
# We only need event subelement, remove others.
remove_field=>[headers, metadata, apiVersion, "@timestamp", kind, "@version", host]
}
mutate{
rename => {items=>event}
}
}
output{
file{
# Audit events from different users will be saved into different files.
path=>"/var/log/kube-audit-%{[event][user][username]}/audit"
}
}
EOF
Comprueba las auditorías en los directorios /var/log/kube-audit-*/audit de los nodos de logstash
Nótese que además del plugin para salida en archivos, logstash ofrece una variedad de salidas adicionales
que permiten a los usuarios enviar la información donde necesiten. Por ejemplo, se puede enviar los eventos de auditoría
al plugin de elasticsearch que soporta búsquedas avanzadas y analíticas.
5.10.2 - Depurar Contenedores de Inicialización
Esta página muestra cómo investigar problemas relacionados con la ejecución
de los contenedores de inicialización (init containers). Las líneas de comando del ejemplo de abajo
se refieren al Pod como <pod-name> y a los Init Containers como <init-container-1> e
<init-container-2> respectivamente.
Antes de empezar
Debes tener un cluster Kubernetes a tu dispocición, y la herramienta de línea de comandos kubectl debe estar configurada. Si no tienes un cluster, puedes crear uno utilizando Minikube,
o puedes utilizar una de las siguientes herramientas en línea:
También puedes acceder al estado del Init Container de forma programática mediante
la lectura del campo status.initContainerStatuses dentro del Pod Spec:
kubectl get pod nginx --template '{{.status.initContainerStatuses}}'
Este comando devolverá la misma información que arriba en formato JSON.
Acceder a los logs de los Init Containers
Indica el nombre del Init Container así como el nombre del Pod para
acceder a sus logs.
kubectl logs <pod-name> -c <init-container-2>
Los Init Containers que ejecutan secuencias de línea de comandos muestran los comandos
conforme se van ejecutando. Por ejemplo, puedes hacer lo siguiente en Bash
indicando set -x al principio de la secuencia.
Comprender el estado de un Pod
Un estado de un Pod que comienza con Init: especifica el estado de la ejecución de
un Init Container. La tabla a continuación muestra algunos valores de estado de ejemplo
que puedes encontrar al depurar Init Containers.
Estado
Significado
Init:N/M
El Pod tiene M Init Containers, y por el momento se han completado N.
Init:Error
Ha fallado la ejecución de un Init Container.
Init:CrashLoopBackOff
Un Init Container ha fallado de forma repetida.
Pending
El Pod todavía no ha comenzado a ejecutar sus Init Containers.
PodInitializing o Running
El Pod ya ha terminado de ejecutar sus Init Containers.
5.10.3 - Escribiendo Logs con Elasticsearch y Kibana
Este artículo describe cómo configurar un clúster para la ingesta de logs en
Elasticsearch y su posterior visualización
con Kibana, a modo de alternativa a
Stackdriver Logging cuando se utiliza la plataforma GCE.
Nota: No se puede desplegar de forma automática Elasticsearch o Kibana en un clúster alojado en Google Kubernetes Engine. Hay que desplegarlos de forma manual.
Para utilizar Elasticsearch y Kibana para escritura de logs del clúster, deberías configurar
la siguiente variable de entorno que se muestra a continuación como parte de la creación
del clúster con kube-up.sh:
KUBE_LOGGING_DESTINATION=elasticsearch
También deberías asegurar que KUBE_ENABLE_NODE_LOGGING=true (que es el valor por defecto en la plataforma GCE).
Así, cuando crees un clúster, un mensaje te indicará que la recolección de logs de los daemons de Fluentd
que corren en cada nodo enviará dichos logs a Elasticsearch:
cluster/kube-up.sh
...
Project: kubernetes-satnam
Zone: us-central1-b
... calling kube-up
Project: kubernetes-satnam
Zone: us-central1-b
+++ Staging server tars to Google Storage: gs://kubernetes-staging-e6d0e81793/devel
+++ kubernetes-server-linux-amd64.tar.gz uploaded (sha1 = 6987c098277871b6d69623141276924ab687f89d)
+++ kubernetes-salt.tar.gz uploaded (sha1 = bdfc83ed6b60fa9e3bff9004b542cfc643464cd0)
Looking for already existing resources
Starting master and configuring firewalls
Created [https://www.googleapis.com/compute/v1/projects/kubernetes-satnam/zones/us-central1-b/disks/kubernetes-master-pd].
NAME ZONE SIZE_GB TYPE STATUS
kubernetes-master-pd us-central1-b 20 pd-ssd READY
Created [https://www.googleapis.com/compute/v1/projects/kubernetes-satnam/regions/us-central1/addresses/kubernetes-master-ip].
+++ Logging using Fluentd to elasticsearch
Tanto los pods por nodo de Fluentd, como los pods de Elasticsearch, y los pods de Kibana
deberían ejecutarse en el namespace de kube-system inmediatamente después
de que el clúster esté disponible.
Los pods de fluentd-elasticsearch recogen los logs de cada nodo y los envían a los
pods de elasticsearch-logging, que son parte de un servicio llamado elasticsearch-logging.
Estos pods de Elasticsearch almacenan los logs y los exponen via una API REST.
El pod de kibana-logging proporciona una UI via web donde leer los logs almacenados en
Elasticsearch, y es parte de un servicio denominado kibana-logging.
Los servicios de Elasticsearch y Kibana ambos están en el namespace kube-system
y no se exponen de forma directa mediante una IP accesible públicamente. Para poder acceder a dichos logs,
sigue las instrucciones acerca de cómo Acceder a servicios corriendo en un clúster.
Si tratas de acceder al servicio de elasticsearch-logging desde tu navegador,
verás una página de estado que se parece a la siguiente:
A partir de ese momento, puedes introducir consultas de Elasticsearch directamente en el navegador, si lo necesitas.
Echa un vistazo a la documentación de Elasticsearch
para más detalles acerca de cómo hacerlo.
De forma alternativa, puedes ver los logs de tu clúster en Kibana (de nuevo usando las
instrucciones para acceder a un servicio corriendo en un clúster).
La primera vez que visitas la URL de Kibana se te presentará una página que te pedirá
que configures una vista de los logs. Selecciona la opción de valores de serie temporal
y luego @timestamp. En la página siguiente selecciona la pestaña de Discover
y entonces deberías ver todos los logs. Puedes establecer el intervalo de actualización
en 5 segundos para refrescar los logs de forma regular.
Aquí se muestra una vista típica de logs desde el visor de Kibana:
Siguientes pasos
¡Kibana te permite todo tipo de potentes opciones para explorar tus logs! Puedes encontrar
algunas ideas para profundizar en el tema en la documentación de Kibana.
Nota: Por defecto, Stackdriver recolecta toda la salida estándar de tus contenedores, así
como el flujo de la salida de error. Para recolectar cualquier log tu aplicación escribe en un archivo (por ejemplo),
ver la estrategia de sidecar
en el resumen de escritura de logs en Kubernetes.
Despliegue
Para ingerir logs, debes desplegar el agente de Stackdriver Logging en cada uno de los nodos de tu clúster.
Dicho agente configura una instancia de fluentd, donde la configuración se guarda en un ConfigMap
y las instancias se gestionan a través de un DaemonSet de Kubernetes. El despliegue actual del
ConfigMap y el DaemonSet dentro de tu clúster depende de tu configuración individual del clúster.
Desplegar en un nuevo clúster
Google Kubernetes Engine
Stackdriver es la solución por defecto de escritura de logs para aquellos clústeres desplegados en Google Kubernetes Engine.
Stackdriver Logging se despliega por defecto en cada clúster a no ser que se le indique de forma explícita no hacerlo.
Otras plataformas
Para desplegar Stackdriver Logging en un nuevo clúster que estés creando con
kube-up.sh, haz lo siguiente:
Configura la variable de entorno KUBE_LOGGING_DESTINATION con el valor gcp.
Si no estás trabajando en GCE, incluye beta.kubernetes.io/fluentd-ds-ready=true
en la variable KUBE_NODE_LABELS.
Una vez que tu clúster ha arrancado, cada nodo debería ejecutar un agente de Stackdriver Logging.
Los DaemonSet y ConfigMap se configuran como extras. Si no estás usando kube-up.sh,
considera la posibilidad de arrancar un clúster sin una solución pre-determinada de escritura de logs
y entonces desplegar los agentes de Stackdriver Logging una vez el clúster esté ejecutándose.
Advertencia: El proceso de Stackdriver Logging reporta problemas conocidos en plataformas distintas
a Google Kubernetes Engine. Úsalo bajo tu propio riesgo.
Desplegar a un clúster existente
Aplica una etiqueta en cada nodo, si no estaba presente ya.
El despliegue del agente de Stackdriver Logging utiliza etiquetas de nodo para
determinar en qué nodos debería desplegarse. Estas etiquetas fueron introducidas
para distinguir entre nodos de Kubernetes de la versión 1.6 o superior.
Si el clúster se creó con Stackdriver Logging configurado y el nodo tiene la
versión 1.5.X o inferior, ejecutará fluentd como un pod estático. Puesto que un nodo
no puede tener más de una instancia de fluentd, aplica únicamente las etiquetas
a los nodos que no tienen un pod de fluentd ya desplegado. Puedes confirmar si tu nodo
ha sido etiquetado correctamente ejecutando kubectl describe de la siguiente manera:
Asegúrate que la salida contiene la etiqueta beta.kubernetes.io/fluentd-ds-ready=true.
Si no está presente, puedes añadirla usando el comando kubectl label como se indica:
Nota: Si un nodo falla y tiene que volver a crearse, deberás volver a definir
la etiqueta al nuevo nodo. Para facilitar esta tarea, puedes utilizar el
parámetro de línea de comandos del Kubelet para aplicar dichas etiquetas
cada vez que se arranque un nodo.
Despliega un ConfigMap con la configuración del agente de escritura de logs ejecutando el siguiente comando:
Este comando crea el ConfigMap en el espacio de nombres default. Puedes descargar el archivo
manualmente y cambiarlo antes de crear el objeto ConfigMap.
Despliega el agente DaemonSet de escritura de logs ejecutando el siguiente comando:
Puedes descargar y editar este archivo antes de usarlo igualmente.
Verificar el despliegue de tu agente de escritura de logs
Tras el despliegue del DaemonSet de StackDriver, puedes comprobar el estado de
cada uno de los despliegues de los agentes ejecutando el siguiente comando:
kubectl get ds --all-namespaces
Si tienes 3 nodos en el clúster, la salida debería ser similar a esta:
NAMESPACE NAME DESIRED CURRENT READY NODE-SELECTOR AGE
...
default fluentd-gcp-v2.0 3 3 3 beta.kubernetes.io/fluentd-ds-ready=true 5m
...
Para comprender cómo funciona Stackdriver, considera la siguiente especificación
de un generador de logs sintéticos counter-pod.yaml:
apiVersion:v1kind:Podmetadata:name:counterspec:containers:- name:countimage:busyboxargs:[/bin/sh, -c,'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
Esta especificación de pod tiene un contenedor que ejecuta una secuencia de comandos bash
que escribe el valor de un contador y la fecha y hora cada segundo, de forma indefinida.
Vamos a crear este pod en el espacio de nombres por defecto.
NAME READY STATUS RESTARTS AGE
counter 1/1 Running 0 5m
Durante un período de tiempo corto puedes observar que el estado del pod es 'Pending', debido a que el kubelet
tiene primero que descargar la imagen del contenedor. Cuando el estado del pod cambia a Running
puedes usar el comando kubectl logs para ver la salida de este pod contador.
kubectl logs counter
0: Mon Jan 1 00:00:00 UTC 2001
1: Mon Jan 1 00:00:01 UTC 2001
2: Mon Jan 1 00:00:02 UTC 2001
...
Como se describe en el resumen de escritura de logs, este comando visualiza las entradas de logs
del archivo de logs del contenedor. Si se termina el contenedor y Kubernetes lo reinicia,
todavía puedes acceder a los logs de la ejecución previa del contenedor. Sin embargo,
si el pod se desaloja del nodo, los archivos de log se pierden. Vamos a demostrar este
comportamiento mediante el borrado del contenedor que ejecuta nuestro contador:
Tras un tiempo, puedes acceder a los logs del pod contador otra vez:
kubectl logs counter
0: Mon Jan 1 00:01:00 UTC 2001
1: Mon Jan 1 00:01:01 UTC 2001
2: Mon Jan 1 00:01:02 UTC 2001
...
Como era de esperar, únicamente se visualizan las líneas de log recientes. Sin embargo,
para una aplicación real seguramente prefieras acceder a los logs de todos los contenedores,
especialmente cuando te haga falta depurar problemas. Aquí es donde haber habilitado
Stackdriver Logging puede ayudarte.
Ver logs
El agente de Stackdriver Logging asocia metadatos a cada entrada de log, para que puedas usarlos posteriormente
en consultas para seleccionar sólo los mensajes que te interesan: por ejemplo,
los mensajes de un pod en particular.
Los metadatos más importantes son el tipo de recurso y el nombre del log.
El tipo de recurso de un log de contenedor tiene el valor container, que se muestra como
GKE Containers en la UI (incluso si el clúster de Kubernetes no está en Google Kubernetes Engine).
El nombre de log es el nombre del contenedor, de forma que si tienes un pod con
dos contenedores, denominados container_1 y container_2 en la especificación, sus logs
tendrán los nombres container_1 y container_2 respectivamente.
Los componentes del sistema tienen el valor compute como tipo de recursos, que se muestra como
GCE VM Instance en la UI. Los nombres de log para los componentes del sistema son fijos.
Para un nodo de Google Kubernetes Engine, cada entrada de log de cada componente de sistema tiene uno de los siguientes nombres:
Uno de los posibles modos de ver los logs es usando el comando de línea de interfaz
gcloud logging
del SDK de Google Cloud.
Este comando usa la sintaxis de filtrado de StackDriver Logging
para consultar logs específicos. Por ejemplo, puedes ejecutar el siguiente comando:
...
"2: Mon Jan 1 00:01:02 UTC 2001\n"
"1: Mon Jan 1 00:01:01 UTC 2001\n"
"0: Mon Jan 1 00:01:00 UTC 2001\n"
...
"2: Mon Jan 1 00:00:02 UTC 2001\n"
"1: Mon Jan 1 00:00:01 UTC 2001\n"
"0: Mon Jan 1 00:00:00 UTC 2001\n"
Como puedes observar, muestra los mensajes del contenedor contador tanto de la
primera como de la segunda ejecución, a pesar de que el kubelet ya había eliminado los logs del primer contenedor.
Exportar logs
Puedes exportar los logs al Google Cloud Storage
o a BigQuery para llevar a cabo un análisis más profundo.
Stackdriver Logging ofrece el concepto de destinos, donde puedes especificar el destino de
las entradas de logs. Más información disponible en la página de exportación de logs de StackDriver.
Configurar los agentes de Stackdriver Logging
En ocasiones la instalación por defecto de Stackdriver Logging puede que no se ajuste a tus necesidades, por ejemplo:
Puede que quieras añadir más recursos porque el rendimiento por defecto no encaja con tus necesidades.
Puede que quieras añadir un parseo adicional para extraer más metadatos de tus mensajes de log,
como la severidad o referencias al código fuente.
Puede que quieras enviar los logs no sólo a Stackdriver o sólo enviarlos a Stackdriver parcialmente.
En cualquiera de estos casos, necesitas poder cambiar los parámetros del DaemonSet y el ConfigMap.
Prerequisitos
Si estás usando GKE y Stackdriver Logging está habilitado en tu clúster, no puedes
cambiar su configuración, porque ya está gestionada por GKE.
Sin embargo, puedes deshabilitar la integración por defecto y desplegar la tuya propia.
Nota: Tendrás que mantener y dar soporte tú mismo a la nueva configuración desplegada:
actualizar la imagen y la configuración, ajustar los recuros y todo eso.
Para deshabilitar la integración por defecto, usa el siguiente comando:
Puedes encontrar notas acerca de cómo instalar los agentes de Stackdriver Logging
en un clúster ya ejecutándose en la sección de despliegue.
Cambiar los parámetros del DaemonSet
Cuando tienes un DaemonSet de Stackdriver Logging en tu clúster, puedes simplemente
modificar el campo template en su especificación, y el controlador del daemonset actualizará los pods por ti. Por ejemplo,
asumamos que acabas de instalar el Stackdriver Logging como se describe arriba. Ahora quieres cambiar
el límite de memoria que se le asigna a fluentd para poder procesar más logs de forma segura.
Obtén la especificación del DaemonSet que corre en tu clúster:
kubectl get ds fluentd-gcp-v2.0 --namespace kube-system -o yaml > fluentd-gcp-ds.yaml
A continuación, edita los requisitos del recurso en el spec y actualiza el objeto DaemonSet
en el apiserver usando el siguiente comando:
kubectl replace -f fluentd-gcp-ds.yaml
Tras un tiempo, los pods de agente de Stackdriver Logging se reiniciarán con la nueva configuración.
Cambiar los parámetros de fluentd
La configuración de Fluentd se almacena en un objeto ConfigMap. Realmente se trata de un conjunto
de archivos de configuración que se combinan conjuntamente. Puedes aprender acerca de
la configuración de fluentd en el sitio oficial.
Imagina que quieres añadir una nueva lógica de parseo a la configuración actual, de forma que fluentd pueda entender
el formato de logs por defecto de Python. Un filtro apropiado de fluentd para conseguirlo sería:
<filter reform.**>
type parser
format /^(?<severity>\w):(?<logger_name>\w):(?<log>.*)/
reserve_data true
suppress_parse_error_log true
key_name log
</filter>
Ahora tienes que añadirlo a la configuración actual y que los agentes de Stackdriver Logging la usen.
Para ello, obtén la versión actual del ConfigMap de Stackdriver Logging de tu clúster
ejecutando el siguiente comando:
kubectl get cm fluentd-gcp-config --namespace kube-system -o yaml > fluentd-gcp-configmap.yaml
Luego, como valor de la clave containers.input.conf, inserta un nuevo filtro justo después
de la sección source.
Nota: El orden es importante.
Actualizar el ConfigMap en el apiserver es más complicado que actualizar el DaemonSet.
Es mejor considerar que un ConfigMap es inmutable. Así, para poder actualizar la configuración, deberías
crear un nuevo ConfigMap con otro nombre y cambiar el DaemonSet para que apunte al nuevo
siguiendo la guía de arriba.
Añadir plugins de fluentd
Fluentd está desarrollado en Ruby y permite extender sus capacidades mediante el uso de
plugins. Si quieres usar un plugin que no está incluido en
la imagen por defecto del contenedor de Stackdriver Logging, debes construir tu propia imagen.
Imagina que quieres añadir un destino Kafka para aquellos mensajes de un contenedor en particular
para poder procesarlos posteriormente. Puedes reusar los fuentes de imagen de contenedor
con algunos pequeños cambios:
Cambia el archivo Makefile para que apunte a tu repositorio de contenedores, ej. PREFIX=gcr.io/<your-project-id>.
Añade tu dependencia al archivo Gemfile, por ejemplo gem 'fluent-plugin-kafka'.
Luego, ejecuta make build push desde ese directorio. Cuando el DaemonSet haya tomado los cambios de la nueva imagen,
podrás usar el plugin que has indicado en la configuración de fluentd.
5.10.5 - Pipeline de métricas de recursos
Desde Kubernetes 1.8, las métricas de uso de recursos, tales como el uso de CPU y memoria del contenedor,
están disponibles en Kubernetes a través de la API de métricas. Estas métricas son accedidas directamente
por el usuario, por ejemplo usando el comando kubectl top, o usadas por un controlador en el cluster,
por ejemplo el Horizontal Pod Autoscaler, para la toma de decisiones.
La API de Métricas
A través de la API de métricas, Metrics API en inglés, puedes obtener la cantidad de recursos usados
actualmente por cada nodo o pod. Esta API no almacena los valores de las métricas,
así que no es posible, por ejemplo, obtener la cantidad de recursos que fueron usados por
un nodo hace 10 minutos.
La API de métricas está completamente integrada en la API de Kubernetes:
se expone a través del mismo endpoint que las otras APIs de Kubernetes bajo el path /apis/metrics.k8s.io/
ofrece las mismas garantías de seguridad, escalabilidad y confiabilidad
La API está definida en el repositorio k8s.io/metrics. Puedes encontrar
más información sobre la API ahí.
Nota: La API requiere que el servidor de métricas esté desplegado en el clúster. En otro caso no estará
disponible.
Servidor de Métricas
El Servidor de Métricas es un agregador
de datos de uso de recursos de todo el clúster.
A partir de Kubernetes 1.8, el servidor de métricas se despliega por defecto como un objeto de
tipo Deployment en clústeres
creados con el script kube-up.sh. Si usas otro mecanismo de configuración de Kubernetes, puedes desplegarlo
usando los yamls de despliegue
proporcionados. Está soportado a partir de Kubernetes 1.7 (más detalles al final).
El servidor reune métricas de la Summary API, que es expuesta por el Kubelet en cada nodo.
El servidor de métricas se añadió a la API de Kubernetes utilizando el
Kubernetes aggregator introducido en Kubernetes 1.7.
Puedes aprender más acerca del servidor de métricas en el documento de diseño.
5.11 - Extender la API de Kubernetes
5.11.1 - Usar recursos personalizados
5.12 - Gestionar certificados TLS
5.13 - Federación
5.13.1 - Administrar la federación de clústeres
5.14 - Catálogo de servicios
6 - Tutoriales
Esta sección de la documentación de Kubernetes contiene tutoriales.
Un tutorial muestra cómo lograr una meta que es más grande que una sola
tarea. Típicamente un tutorial tiene varias secciones y cada
una de ellas contiene un procedimiento.
Antes de recorrer cada tutorial, recomendamos añadir un marcador a
Glosario de términos para poder consultarlo fácilmente.
Esenciales
Kubernetes Basics se trata de un tutorial interactivo en profundidad para entender Kubernetes y probar algunas funciones básicas.
Si quieres escribir un tutorial, revisa utilizando templates para obtener información sobre el tipo de página y la plantilla de los tutotriales.
6.1 - Hello Minikube
Este tutorial muestra como ejecutar una aplicación Node.js Hola Mundo en Kubernetes utilizando
Minikube y Katacoda.
Katacoda provee un ambiente de Kubernetes desde el navegador.
Nota: También se puede seguir este tutorial si se ha instalado Minikube localmente.
Objetivos
Desplegar una aplicación Hola Mundo en Minikube.
Ejecutar la aplicación.
Ver los logs de la aplicación.
Antes de empezar
Este tutorial provee una imagen de contenedor construida desde los siguientes archivos:
Nota: Si se tiene instalado Minikube local, ejecutar minikube start.
Abrir el tablero de Kubernetes dashboard en un navegador:
minikube dashboard
Solo en el ambiente de Katacoda: En la parte superior de la terminal, haz clic en el símbolo + y luego clic en Select port to view on Host 1.
Solo en el ambiente de Katacoda: Escribir 30000, y hacer clic en Display Port.
Crear un Deployment
Un Pod en Kubernetes es un grupo de uno o más contenedores,
asociados con propósitos de administración y redes. El Pod en este tutorial tiene solo un contenedor.
Un Deployment en Kubernetes verifica la salud del Pod y reinicia su contenedor si este es eliminado. Los Deployments son la manera recomendada de manejar la creación y escalación.
Ejecutar el comando kubectl create para crear un Deployment que maneje un Pod. El Pod ejecuta un contenedor basado en la imagen proveida por Docker.
NAME READY UP-TO-DATE AVAILABLE AGE
hello-node 1/1 1 1 1m
Ver el Pod:
kubectl get pods
El resultado es similar a:
NAME READY STATUS RESTARTS AGE
hello-node-5f76cf6ccf-br9b5 1/1 Running 0 1m
Ver los eventos del clúster:
kubectl get events
Ver la configuración kubectl:
kubectl config view
Nota: Para más información sobre el comando kubectl, ver kubectl overview.
Crear un Service
Por defecto, el Pod es accedido por su dirección IP interna dentro del clúster de Kubernetes, para hacer que el contenedor hello-node sea accesible desde afuera de la red virtual Kubernetes, se debe exponer el Pod como un
Service de Kubernetes.
Exponer el Pod a la red pública de internet utilizando el comando kubectl expose:
El flag --type=LoadBalancer indica que se quiere exponer el Service fuera del clúster.
Ver el Service creado:
kubectl get services
El resultado es similar a:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-node LoadBalancer 10.108.144.78 <pending> 8080:30369/TCP 21s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23m
Para los proveedores Cloud que soportan balanceadores de carga, una dirección IP externa será provisionada para acceder al servicio, en Minikube, el tipo LoadBalancer permite que el servicio sea accesible a través del comando minikube service.
Ejecutar el siguiente comando:
minikube service hello-node
Solo en el ambiente de Katacoda: Hacer clic sobre el símbolo +, y luego en Select port to view on Host 1.
Solo en el ambiente de Katacoda: Anotar el puerto de 5 dígitos ubicado al lado del valor de 8080 en el resultado de servicios. Este número de puerto es generado aleatoriamente y puede ser diferente al indicado en el ejemplo. Escribir el número de puerto en el cuadro de texto y hacer clic en Display Port. Usando el ejemplo anterior, usted escribiría 30369.
Esto abre una ventana de navegador que contiene la aplicación y muestra el mensaje "Hello World".
Habilitar Extensiones
Minikube tiene un conjunto de Extensiones que pueden ser habilitados y desahabilitados en el ambiente local de Kubernetes.
kubeadm - Utilidad CLI para aprovisionar fácilmente un clústeres Kubernetes seguro.
kubefed - Utilidad CLI para ayudarte a administrar tus clústeres federados.
Información de referencia sobre la configuración
kubelet - El principal agente que se ejecuta en cada nodo. El kubelet toma un conjunto de PodSpecs y asegura que los contenedores descritos estén funcionando y en buen estado.
kube-apiserver - API REST que valida y configura datos para objetos API como pods, servicios, controladores de replicación, ...
Kubernetes es posible gracias a la participación de la comunidad y la
documentación es vital para facilitar el acceso al proyecto.
Cualquiera puede contribuir en el proyecto de Kubernetes, tanto si acabas de
descubrir la plataforma como si lleves años involucrado. Tampoco importa si
eres desarrollador, usuario final o alguien que simplemente no soporta ver
errores tipográficos. ¡Cualquier contribución será bien recibida!
Para conocer más formas de involucrarse en la comunidad de Kubernetes o de
aprender sobre nosotros, visite la sección comunidad de Kubernetes.
Para obtener información cómo escribir documentación de Kubernetes,
consulte la guía de estilo.
Tipos de contribuidores
Kubernetes Member, un miembro de la organziación de Kubernetes que ha
firmado el CLA y contribuido al projecto.
Puedes consultar más información en el documento sobre los requisitos para ser
miembro de Kubernetes en el documento Community membership.
SIG Docs reviewer, un revisor del grupo de interés de documentación es
un miembro de la organización Kubernetes que tiene interés en revisar las
pull requests relacionadas con el site y la documentación. Para poder ser
revisor, un aprobador de SIG Docs debe añadirlo al grupo adecuado de GitHub y
al fichero OWNERS del contenido que está interesado en revisar.
SIG Docs approver, un aprobador del grupo de interés de documentación
es un miembro de la organización de Kubernetes con buena reputación y que ha
mostrado una compromiso continuado con el proyecto.
Un aprobador se responsabiliza de mergear las pull requests y publicar
contenido en nombre de la organización Kubernetes. Los aprobadores también
pueden representar a SIG Docs en la comunidad de Kubernetes en general.
Algunas de las responsabilidades de un aprobador de SIG Docs, como por ejemplo
coordinar una release, requieren un compromiso de tiempo significativo.
Cómo contribuir
La siguiente lista está organizada por el nivel de implicación con la comunidad,
desde las contribuciones que cualquiera puede hacer hasta las que requieren un
compromiso con el equipo de documentación y estar familiarizado con los procesos
de SIG Docs. Contribuir consistentemente a lo largo del tiempo puede ayudarte a
comprender algunas de las herramientas y decisiones organizativas que se han ido
tomando a lo largo del proyecto.
La lista no contiene todas las formas de contribución posibles, está pensada
para proporcionar un punto de partida.
Si quieres empezar a contribuir a la documentación de Kubernetes esta página y su temas enlazados pueden ayudarte a empezar. No necesitas ser un desarrollador o saber escribir de forma técnica para tener un gran impacto en la documentación y experiencia de usuario en Kubernetes! Todo lo que necesitas para los temas en esta página es una Cuenta en GitHub y un navegador web.
Si estas buscando información sobre cómo comenzar a contribuir a los repositorios de Kubernetes, entonces dirígete a las guías de la comunidad Kubernetes
Lo básico sobre nuestra documentación
La documentación de Kuberentes esta escrita usando Markdown, procesada y
desplegada usando Hugo. El código fuente está en GitHub accessible en git.k8s.io/website/.
La mayoría de la documentación en castellano está en /content/es/docs. Alguna de
la documentación de referencia se genera automática con los scripts del
directorio /update-imported-docs.
Puedes clasificar incidencias, editar contenido y revisar cambios de otros, todo ello
desde la página de GitHub. También puedes usar la historia embebida de GitHub y
las herramientas de búsqueda.
No todas las tareas se pueden realizar desde la interfaz web de GitHub, también
se discute en las guías de contribución a la documentación
intermedia y
avanzada
Participar en la documentación de los SIG
La documentación de Kubernetes es mantenida por el Special Interest Group (SIG) denominado SIG Docs. Nos comunicamos usando un canal de Slack, una lista de correo
y una reunión semana por video-conferencia. Siempre son bienvenidos nuevos
participantes al grupo. Para más información ver
Participar en SIG Docs.
Guías de estilo
Se mantienen unas guías de estilo con la información sobre las elecciones que cada comunidad SIG Docs ha realizado referente a gramática, sintaxis, formato del código fuente y convenciones tipográficas. Revisa la guía de estilos antes de hacer tu primera contribución y úsala para resolver tus dudas.
Los cambios en la guía de estilos se hacen desde el SIG Docs como grupo. Para añadir o proponer cambios añade tus comentarios en la agenda para las próximas reuniones del SIG Docs y participe en las discusiones durante la reunión. Revisa el apartado avanzado para más información.
Plantillas para páginas
Se usan plantillas para las páginas de documentación con el objeto de que todas tengan la misma presentación. Asegúrate de entender como funcionan estas plantillas y revisa el apartado Uso de plantillas para páginas. Si tienes alguna consulta, no dudes en ponerte en contacto con el resto del equipo en Slack.
Hugo shortcodes
La documentación de Kubernetes se transforma a partir de Markdown para obtener HTML usando Hugo. Hay que conocer los shortcodes estándar de Hugo, así como algunos que son personalizados para la documentación de Kubernetes. Para más información de como usarlos revisa Hugo shortcodes personalizados.
Múltiples idiomas
La documentación original está disponible en múltiples idiomas en /content/. Cada idioma tiene su propia carpeta con el código de dos letras determinado por el estándar ISO 639-1. Por ejemplo, la documentación original en inglés se encuentra en /content/en/docs/.
Para más información sobre como contribuir a la documentación en múltiples idiomas revisa "Localizar contenido"
Si te interesa empezar una nueva localización revisa "Localization".
Registro de incidencias
Cualquier persona con una cuenta de GitHub puede reportar una incidencia en la documentación de Kubernetes. Si ves algo erróneo, aunque no sepas como resolverlo, reporta una incidencia. La única excepción a la regla es si se trata de un pequeño error, como alguno que puedes resolver por ti mismo. En este último caso, puedes tratar de resolverlo sin necesidad de reportar una incidencia primero.
Cómo reportar una incidencia
En una página existente
Si ves un problema en una página existente en la documentación de Kuberenetes ve al final de la página y haz clic en el botón Abrir un Issue. Si no estas autenticado en GitHub, te pedirá que te identifiques y posteriormente un formulario de nueva incidencia aparecerá con contenido pre-cargado.
Utilizando formato Markdown completa todos los detalles que sea posible. En los lugares en que haya corchetes ([ ]) pon una x en medio de los corchetes para representar la elección de una opción. Si tienes una posible solución al problema añádela.
Solicitar una nueva página
Si crees que un contenido debería añadirse, pero no estás seguro de donde debería añadirse o si crees que no encaja en las páginas que ya existen, puedes crear un incidente. También puedes elegir una página ya existente donde pienses que pudiera encajar y crear el incidente desde esa página, o ir directamente a https://github.com/kubernetes/website/issues/new/ y crearlo desde allí.
Cómo reportar correctamente incidencias
Para estar seguros que tu incidencia se entiende y se puede procesar ten en cuenta esta guía:
Usa la plantilla de incidencia y aporta detalles, cuantos más es mejor.
Explica de forma clara el impacto de la incidencia en los usuarios.
Mantén el alcance de una incidencia a una cantidad de trabajo razonable. Para problemas con un alcance muy amplio divídela en incidencias más pequeñas.
Por ejemplo, "Arreglar la documentación de seguridad" no es una incidencia procesable, pero "Añadir detalles en el tema 'Restringir acceso a la red'" si lo es.
Si la incidencia está relacionada con otra o con una petición de cambio puedes referirte a ella tanto por la URL como con el número de la incidencia o petición de cambio con el carácter # delante. Por ejemplo Introducido por #987654.
Se respetuoso y evita desahogarte. Por ejemplo, "La documentación sobre X apesta" no es útil o una crítica constructiva. El Código de conducta también aplica para las interacciones en los repositorios de Kubernetes en GitHub.
Participa en las discusiones de SIG Docs
El equipo de SIG Docs se comunica por las siguientes vías:
Únete al Slack de Kubernetes y entra al canal #sig-docs o #kubernetes-docs-es para la documentación en castellano. En Slack, discutimos sobre las incidencias de documentación en tiempo real, nos coordinamos y hablamos de temas relacionados con la documentación. No olvides presentarte cuando entres en el canal para que podamos saber un poco más de ti!
Participa en la video-conferencia semanal de SIG Docs, esta se anuncia en el canal de Slack y la lista de correo. Actualmente esta reunión tiene lugar usando Zoom, por lo que necesitas descargar el cliente Zoom o llamar usando un teléfono.
Para mejorar contenido existente crea una pull request(PR) después de crear un fork. Estos términos son específicos de GitHub. No es necesario conocer todo sobre estos términos porque todo se realiza a través del navegador web. Cuando continúes con la guía de contribución de documentación intermedia entonces necesitarás un poco más de conocimiento de la metodología Git.
Nota:Desarrolladores de código de Kubernetes: Si estás documentando una nueva característica para una versión futura de Kubernetes, entonces el proceso es un poco diferente. Mira el proceso y pautas en Documentar una característica así como información sobre plazos.
Si ves algo que quieras arreglar directamente, simplemente sigue las instrucciones más abajo. No es necesario que reportes una incidencia (aunque de todas formas puedes).
Si quieres empezar por buscar una incidencia existente para trabajar puedes ir https://github.com/kubernetes/website/issues y buscar una incidencia con la etiqueta good first issue (puedes usar este atajo). Lee los comentarios y asegurate de que no hay una petición de cambio abierta para esa incidencia y que nadie a dejado un comentario indicando que están trabajando en esa misma incidencia recientemente (3 días es una buena regla). Deja un comentario indicando que te gustaría trabajar en la incidencia.
Elije que rama de Git usar
El aspecto más importante a la hora de mandar una petición de cambio es que rama usar como base para trabajar. Usa estas pautas para tomar la decisión:
Utiliza master para arreglar problemas en contenido ya existente publicado, o hacer mejoras en contenido ya existente.
Utiliza una rama de versión (cómo dev-release-1.24 para la versión release-1.24) para documentar futuras características o cambios para futuras versiones que todavía no se han publicado.
Utiliza una rama de características que haya sido acordada por SIG Docs para colaborar en grandes mejoras o cambios en la documentación existente, incluida la reorganización de contenido o cambios en la apariencia del sitio web.
Si todavía no estás seguro con que rama utilizar, pregunta en #sig-docsen Slack o atiende una reunión semanal del SIG Docs para aclarar tus dudas.
Enviar una petición de cambio
Sigue estos pasos para enviar una petición de cambio y mejorar la documentación de Kubernetes.
En la página que hayas visto una incidencia haz clic en el icono del lápiz arriba a la derecha.
Una nueva página de GitHub aparecerá con algunos textos de ayuda.
Si nunca has creado un copia del repositorio de documentación de Kubernetes te pedirá que lo haga.
Crea la copia bajo tu usuario de GitHub en lugar de otra organización de la que seas miembro. La copia generalmente tiene una URL como https://github.com/<username>/website, a menos que ya tengas un repositorio con un nombre en conflicto con este.
La razón por la que se pide crear una copia del repositorio es porque no tienes permisos para subir cambios directamente a rama en el repositorio original de Kubernetes.
Aparecerá el editor Markdown de GitHub con el fichero Markdown fuente cargado. Realiza tus cambios. Debajo del editor completa el formulario Propose file change. El primer campo es el resumen del mensaje de tu commit y no debe ser más largo de 50 caracteres. El segundo campo es opcional, pero puede incluir más información y detalles si procede.
Nota: No incluyas referencias a otras incidencias o peticiones de cambio de GitHub en el mensaje de los commits. Esto lo puedes añadir después en la descripción de la petición de cambio.
Haz clic en Propose file change. El cambio se guarda como un commit en una nueva rama de tu copia, automáticamente se le asignará un nombre estilo patch-1.
La siguiente pantalla resume los cambios que has hecho pudiendo comparar la nueva rama (la head fork y cajas de selección compare) con el estado actual del base fork y la rama base (master en el repositorio por defecto kubernetes/website). Puedes cambiar cualquiera de las cajas de selección, pero no lo hagas ahora. Hecha un vistazo a las distintas vistas en la parte baja de la pantalla y si todo parece correcto haz clic en Create pull request.
Nota: Si no deseas crear una petición de cambio puedes hacerlo más delante, solo basta con navegar a la URL principal del repositorio de Kubernetes website o de tu copia. La página de GitHub te mostrará un mensaje para crear una petición de cambio si detecta que has subido una nueva rama a tu repositorio copia.
La pantalla Open a pull request aparece. El tema de una petición de cambio es el resumen del commit, pero puedes cambiarlo si lo necesitas. El cuerpo está pre-cargado con el mensaje del commit extendido (si lo hay) junto con una plantilla. Lee la plantilla y llena los detalles requeridos, entonces borra el texto extra de la plantilla. Deja la casilla Allow edits from maintainers seleccionada. Haz clic en Create pull request.
Enhorabuena! Tu petición de cambio está disponible en Pull requests.
Después de unos minutos ya podrás pre-visualizar la página con los cambios de tu PR aplicados. Ve a la pestaña de Conversation en tu PR y haz clic en el enlace Details para ver el test deploy/netlify, localizado casi al final de la página. Se abrirá en la misma ventana del navegado por defecto.
Espera una revisión. Generalmente k8s-ci-robot sugiere unos revisores. Si un revisor te pide que hagas cambios puedes ir a la pestaña FilesChanged y hacer clic en el icono del lápiz para hacer tus cambios en cualquiera de los ficheros en la petición de cambio. Cuando guardes los cambios se creará un commit en la rama asociada a la petición de cambio.
Si tu cambio es aceptado, un revisor fusionará tu petición de cambio y tus cambios serán visibles en pocos minutos en la web de kubernetes.io.
Esta es solo una forma de mandar una petición de cambio. Si eres un usuario de Git y GitHub avanzado puedes usar una aplicación GUI local o la linea de comandos con el cliente Git en lugar de usar la UI de GitHub. Algunos conceptos básicos sobre el uso de la línea de comandos Git
cliente se discuten en la guía de documentación intermedia.
Revisar peticiones de cambio de documentación
Las personas que aún no son aprobadores o revisores todavía pueden revisar peticiones de cambio. Las revisiones no se consideran "vinculantes", lo que significa que su revisión por sí sola no hará que se fusionen las peticiones de cambio. Sin embargo, aún puede ser útil. Incluso si no deja ningún comentario de revisión, puede tener una idea de las convenciones y etiquetas en una petición de cambio y acostumbrarse al flujo de trabajo.
Por defecto el único filtro que se aplica es open, por lo que no puedes ver las que ya se han cerrado o fusionado. Es una buena idea aplicar el filtro cncf-cla: yes y para tu primera revisión es una buena idea añadir size/S o size/XS. La etiqueta size se aplica automáticamente basada en el número de lineas modificadas en la PR. Puedes aplicar filtros con las cajas de selección al principio de la página, o usar estos atajos solo para PRs pequeñas. Los filtros son aplicados con AND todos juntos, por lo que no se puede buscar a la vez size/S y size/XS en la misma consulta.
Ve a la pestaña Files changed. Mira los cambios introducidos en la PR, y si aplica, mira también los incidentes enlazados. Si ves un algún problema o posibilidad de mejora pasa el cursor sobre la línea y haz click en el símbolo + que aparece.
Puedes entonces dejar un comentario seleccionando Add single comment o Start a review. Normalmente empezar una revisión es la forma recomendada, ya que te permite hacer varios comentarios y avisar a propietario de la PR solo cuando tu revisión este completada, en lugar de notificar cada comentario.
Cuando hayas acabado de revisar, haz clic en Review changes en la parte superior de la página. Puedes ver un resumen de la revisión y puedes elegir entre comentar, aprobar o solicitar cambios. Los nuevos contribuidores siempre deben elegir Comment.
Gracias por revisar una petición de cambio! Cuando eres nuevo en un proyecto es buena idea solicitar comentarios y opiniones en las revisiones de una petición de cambio. Otro buen lugar para solicitar comentarios es en el canal de Slack #sig-docs.
## Escribir un artículo en el blog
Cualquiera puede escribir un articulo en el blog y enviarlo para revisión. Los artículos del blog no deben ser comerciales y deben consistir en contenido que se pueda aplicar de la forma más amplia posible a la comunidad de Kubernetes.
Para enviar un artículo al blog puedes hacerlo también usando el formulario Kubernetes blog submission form, o puedes seguir los siguientes pasos.
Revisa el formato Markdown en los artículos del blog existentes en el repositorio website.
Escribe tu artículo usando el editor de texto que prefieras.
En el mismo enlace que el paso 2 haz clic en botón Create new file. Pega el contenido de tu editor. Nombra el fichero para que coincida con el título del artículo, pero no pongas la fecha en el nombre. Los revisores del blog trabajarán contigo en el nombre final del fichero y la fecha en la que será publicado.
Cuando guardes el fichero, GitHub te guiará en el proceso de petición de cambio.
Un revisor de artículos del blog revisará tu envío y trabajará contigo aportando comentarios y los detalles finales. Cuando el artículo sea aprobado, se establecerá una fecha de publicación.
Envía un caso de estudio
Un caso de estudio destaca como organizaciones están usando Kubernetes para resolver problemas del mundo real. Estos se escriben en colaboración con el equipo de marketing de Kubernetes que está dirigido por la CNCF.
Cuando entiendas mejor las tareas mostradas en este tema y quieras formar parte del equipo de documentación de Kubernetes de una forma más activa lee la guía intermedia de contribución.
8.2 - Cómo escribir documentación
Los temas de esta sección proporcionan información sobre como escribir,
formatear y organizar el contenido de la documentación de Kubernetes.
También se explican las funciones, templates, variables y otras configuraciones
de Hugo utilizadas para generar y dar formato a
kubernetes.io.
8.3 - Documentación de referencia
Gran parte de la documentación de referencia de Kubernetes se genera a
partir del propio código fuente de Kubernetes utilizando scripts.
Los temas de esta sección documentan cómo generar este tipo de contenido.
8.4 - Contribuir a la documentación de Kubernetes en español
¡Bienvenido(a)!
En esta página encontrarás información sobre convenciones utilizadas en la documentación en castellano y un glosario de términos con sus traducciones.
Glosario de terminología
English
Español
Género
Commentarios
availability zone
zona de disponibilidad
femenino
bearer token
bearer token
masculino
built-in
incorporados
masculino
conditions
condiciones
masculino
para node conditions
container
contenedor
masculino
controller
controlador
masculino
deploy
desplegar
Deployment
Deployment
masculino
objeto Kubernetes
Endpoints
Endpoints
masculino
objeto Kubernetes
file
archivo
masculino
frontend
frontend
masculino
healthy
operativo
high availability
alta disponibilidad
hook
hook
masculino
instance
instancia
femenino
Lease
Lease
masculino
objeto Kubernetes
Pod
Pod
masculino
objeto Kubernetes
ratio
ritmo
runtime
motor de ejecución
masculino
Container Runtime
scheduler
planificador
masculino
Secret
Secret
masculino
objeto Kubernetes
secret
secreto
masculino
información confidencial
shell
terminal
femenino
stateless
stateless
taint
contaminación
worker node
nodo de trabajo
masculino
9 -
Haga clic en las etiquetas o utilice los menús desplegables para filtrar.
Haga clic en los encabezados de tabla para ordenar o invertir ordenación.
Filtrar por concepto: Filtrar por objeto: Filtrar por comando: