1 - RuntimeClass
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.
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.io
kind: RuntimeClass
metadata:
name: myclass # Nombre por el que se referenciará la RuntimeClass
# no contiene espacio de nombres
handler: myconfiguration # El nombre de la configuración CRI correspondiente
El nombre de un objeto RuntimeClass debe ser un nombre de subdominio DNS válido.
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:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
runtimeClassName: myclass
# ...
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.
containerd
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:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.${HANDLER_NAME}]
Véase la configuración de containerd para más detalles: https://github.com/containerd/containerd/blob/main/docs/cri/config.md
CRI-O
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
[crio.runtime.runtimes.${HANDLER_NAME}]
runtime_path = "${PATH_TO_BINARY}"
Véase la documentación de la configuración de CRI-O para más detalles.
Planificación
Kubernetes v1.16 [beta]
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
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.
Siguientes pasos
- Diseño de RuntimeClass
- Diseño de programación de RuntimeClass
- Leer sobre el concepto de Pod Overhead
- Diseño de capacidad de PodOverhead
2 - Variables de entorno de un Container
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.
- Practica añadiendo handlers a los lifecycle events de un Container .
3 - 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
Siguientes pasos
- Aprende más sobre variables de entorno de contenedores.
- Practica adjuntando controladores a los eventos de lifecycle de los contenedores.