Information in this document may be out of date
This document has an older update date than the original, so the information it contains may be out of date. If you're able to read English, see the English version for the most up-to-date information: Init Containers
Esta página proporciona una descripción general de los contenedores de inicialización (init containers): contenedores especializados que se ejecutan antes de los contenedores de aplicación en un Pod. Los contenedores de inicialización pueden contener utilidades o scripts de instalación no presentes en una imagen de aplicación.
Tú puedes especificar contenedores de inicialización en la especificación del Pod junto con el arreglo de containers
(el cual describe los contenedores de aplicación).
Un Pod puede tener múltiples contenedores ejecutando aplicaciones dentro de él, pero también puede tener uno o más contenedores de inicialización que se ejecutan antes de que se inicien los contenedores de aplicación.
Los contenedores de inicialización son exactamente iguales a los contenedores regulares excepto por:
Si el contenedor de inicialización de un Pod falla, kubelet reinicia repetidamente ese contenedor de inicialización hasta que tenga éxito.
Sin embargo, si el Pod tiene una restartPolicy de Never y un contenedor de inicialización falla durante el inicio de ese Pod, Kubernetes trata al Pod en general como fallido.
Para especificar un contenedor de inicialización para un Pod, agrega el campo initContainers en
la especificación del Pod,
como un arreglo de elementos container (similar al campo containers de aplicación y su contenido).
Consulta Container en la
referencia de API para más detalles.
El estado de los contenedores de inicialización se devuelve en el campo .status.initContainerStatuses
como un arreglo de los estados del contenedor (similar al campo .status.containerStatuses).
Los contenedores de inicialización admiten todos los campos y características de los contenedores de aplicaciones, incluidos los límites de recursos, los volúmenes y la configuración de seguridad. Sin embargo, las solicitudes de recursos y los límites para un contenedor de inicialización se manejan de manera diferente, como se documenta en Recursos.
Además, los contenedores de inicialización no admiten lifecycle, livenessProbe, readinessProbe o
startupProbe porque deben de ejecutarse hasta su finalización antes de que el Pod pueda estar listo.
Si especificas varios contenedores de inicialización para un Pod, kubelet ejecuta cada contenedor de inicialización secuencialmente. Cada contenedor de inicialización debe tener éxito antes de que se pueda ejecutar el siguiente. Cuando todos los contenedores de inicialización se hayan ejecutado hasta su finalización, kubelet inicializa los contenedores de aplicación para el Pod y los ejecuta como de costumbre.
Dado que los contenedores de inicialización tienen imágenes separadas de los contenedores de aplicaciones, estos tienen algunas ventajas sobre el código relacionado de inicio:
FROM de otra imagen solo para usar una herramienta como
sed, awk, python o dig durante la instalación.A continuación, se muestran algunas ideas sobre cómo utilizar los contenedores de inicialización:
Esperar a que se cree un Service usando una sola linea de comando de shell:
for i in {1..100}; do sleep 1; if nslookup myservice; then exit 0; fi; done; exit 1
Registrar este Pod con un servidor remoto desde la downward API con un comando como:
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
Esperar algo de tiempo antes de iniciar el contenedor de aplicación con un comando como:
sleep 60
Clonar un repositorio de Git en un Volume
Colocar valores en un archivo de configuración y ejecutar una herramienta de plantilla para generar
dinámicamente un archivo de configuración para el contenedor de aplicación principal. Por ejemplo,
colocar el valor POD_IP en una configuración y generar el archivo de configuración
de la aplicación principal usando Jinja.
Este ejemplo define un simple Pod que tiene dos contenedores de inicialización.
El primero espera por myservice y el segundo espera por mydb. Una vez que ambos
contenedores de inicialización se completen, el Pod ejecuta el contenedor de aplicación desde su sección spec.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo ¡La aplicación se está ejecutando! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo esperando a myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo esperando a mydb; sleep 2; done"]
Puedes iniciar este Pod ejecutando:
kubectl apply -f myapp.yaml
El resultado es similar a esto:
pod/myapp-pod created
Y verificar su estado con:
kubectl get -f myapp.yaml
El resultado es similar a esto:
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
o para más detalles:
kubectl describe -f myapp.yaml
El resultado es similar a esto:
Name: myapp-pod
Namespace: default
[...]
Labels: app.kubernetes.io/name=MyApp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
Para ver los logs de los contenedores de inicialización en este Pod ejecuta:
kubectl logs myapp-pod -c init-myservice # Inspecciona el primer contenedor de inicialización
kubectl logs myapp-pod -c init-mydb # Inspecciona el segundo contenedor de inicialización
En este punto, estos contenedores de inicialización estarán esperando para descubrir los Servicios denominados
mydb y myservice.
Aquí hay una configuración que puedes usar para que aparezcan esos Servicios:
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
Para crear los servicios de mydb y myservice:
kubectl apply -f services.yaml
El resultado es similar a esto:
service/myservice created
service/mydb created
Luego verás que esos contenedores de inicialización se completan y que el Pod myapp-pod
pasa al estado Running:
kubectl get -f myapp.yaml
El resultado es similar a esto:
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
Este sencillo ejemplo debería servirte de inspiración para crear tus propios contenedores de inicialización. ¿Qué es lo que sigue? contiene un enlace a un ejemplo más detallado.
Durante el inicio del Pod, kubelet retrasa la ejecución de contenedores de inicialización hasta que la red y el almacenamiento estén listos. Después, kubelet ejecuta los contenedores de inicialización del Pod en el orden que aparecen en la especificación del Pod.
Cada contenedor de inicialización debe salir correctamente antes de que
comience el siguiente contenedor. Si un contenedor falla en iniciar debido al tiempo de ejecución o
sale con una falla, se vuelve a intentar de acuerdo con el restartPolicy del Pod. Sin embargo,
si el restartPolicy del Pod se establece en Always, los contenedores de inicialización usan
el restartPolicy como OnFailure.
Un Pod no puede estar Ready sino hasta que todos los contenedores de inicialización hayan tenido éxito. Los puertos en un
contenedor de inicialización no se agregan a un Servicio. Un Pod que se está inicializando,
está en el estado de Pending, pero debe tener una condición Initialized configurada como falsa.
Si el Pod se reinicia o es reiniciado, todos los contenedores de inicialización deben ejecutarse de nuevo.
Los cambios en la especificación del contenedor de inicialización se limitan al campo de la imagen del contenedor. Alterar un campo de la imagen del contenedor de inicialización equivale a reiniciar el Pod.
Debido a que los contenedores de inicialización se pueden reiniciar, reintentar o volverse a ejecutar, el código del contenedor de inicialización
debe ser idempotente. En particular, el código que escribe en archivos en EmptyDirs
debe estar preparado para la posibilidad de que ya exista un archivo de salida.
Los contenedores de inicialización tienen todos los campos de un contenedor de aplicaciones. Sin embargo, Kubernetes
prohíbe el uso de readinessProbe porque los contenedores de inicialización no pueden
definir el readiness distinto de la finalización. Esto se aplica durante la validación.
Usa activeDeadlineSeconds en el Pod para prevenir que los contenedores de inicialización fallen por siempre.
La fecha límite incluye contenedores de inicialización.
Sin embargo, se recomienda utilizar activeDeadlineSeconds si el usuario implementa su aplicación
como un Job porque activeDeadlineSeconds tiene un efecto incluso después de que initContainer finaliza.
El Pod que ya se está ejecutando correctamente sería eliminado por activeDeadlineSeconds si lo estableces.
El nombre de cada aplicación y contenedor de inicialización en un Pod debe ser único; un error de validación es arrojado para cualquier contenedor que comparta un nombre con otro.
Dado el orden y la ejecución de los contenedores de inicialización, las siguientes reglas para el uso de recursos se aplican:
QoS (calidad de servicio) del nivel de QoS efectivo del Pod es el
nivel de QoS tanto para los contenedores de inicialización como para los contenedores de aplicación.La cuota y los límites son aplicados con base en la solicitud y límite efectivos de Pod.
Los grupos de control de nivel de Pod (cgroups) se basan en la solicitud y el límite de Pod efectivos, al igual que el planificador de Kubernetes (kube-scheduler).
Un Pod puede reiniciarse, provocando la re-ejecución de los contenedores de inicialización por las siguientes razones:
restartPolicy esté configurado en Always,
forzando un reinicio y el registro de finalización del contenedor de inicialización se ha perdido debido a
la recolección de basura.El Pod no se reiniciará cuando se cambie la imagen del contenedor de inicialización o cuando se pierda el registro de finalización del contenedor de inicialización debido a la recolección de basura. Esto se aplica a Kubernetes v1.20 y posteriores. Si estás utilizando una versión anterior de Kubernetes, consulta la documentación de la versión que estás utilizando.