Init контейнеры в Pod
В этом посте представлен обзор init контейнеров: специализированных контейнеров, которые запускаются перед контейнерами приложений в Pod. Init контейнеры могут содержать утилиты или сценарии установки, отсутствующие в образе приложения.
Вы можете указать init контейнеры в спецификации Pod вместе с массивом Containers (который описывает контейнеры приложения).
Pod может иметь несколько контейнеров, в которых выполняются приложения, но он также может иметь один или несколько init контейнеров (контейнеров инициализации), которые запускаются до запуска контейнеров приложений.
Init контейнеры точно такие же, как обычные контейнеры, за исключением:
- Init контейнеры всегда выполняются до конца.
- Каждый init контейнер должен успешно завершиться до запуска следующего.
В случае сбоя контейнера инициализации Pod'а Kubernetes несколько раз перезапускает Pod, пока init контейнер не будет успешно выполнен. Однако, если у Pod есть RestartPolicy равная Never, Kubernetes не перезапускает Pod.
Чтобы указать init контейнер для Pod, добавьте поле initContainers в спецификацию Pod как массив объектов типа Container вместе с массивом контейнеров приложения. Статус контейнеров инициализации возвращается в поле .status.initContainerStatuses в виде массива статусов контейнера (аналогично полю .status.containerStatuses).
Отличия от обычных контейнеров
Init контейнеры поддерживают все поля и функции контейнеров приложений, включая ограничения ресурсов, объемы и параметры безопасности.
Кроме того, init контейнеры не поддерживают пробы готовности (readiness probes), потому что они должны быть выполнены до завершения, прежде чем Pod будет готов.
Если вы указываете несколько init контейнеров для Pod, Kubelet запускает каждый init контейнер последовательно. Каждый контейнер инициализации должен успешно завершиться, прежде чем будет запущен следующий. Когда все init контейнеры завершены, Kubelet инициализирует контейнеры приложений для Pod и запускает их как обычно.
Использование init контейнеров
Поскольку у init контейнеров есть отдельные от контейнеров приложений образы, у них есть некоторые преимущества для кода, связанного с запуском:
- Init контейнеры могут содержать утилиты или пользовательский код для настройки, которых нет в образе приложения. Например, нет необходимости создавать образ из другого образа только для того, чтобы использовать такой инструмент, как sed, awk, python или dig во время установки.
- Init контейнеры могут безопасно запускать утилиты, которые сделали бы образ контейнера приложения менее безопасным.
- Роль конструктора приложений и роль развертывания могут работать независимо друг от друга без необходимости совместного создания одного образа приложения.
- Init контейнеры могут работать с другим видом файловой системы, чем контейнеры приложений в одном Pod. Следовательно, им может быть предоставлен доступ к секретам, к которым контейнеры приложения не могут получить доступ.
- Поскольку init контейнеры выполняются полностью до запуска любых контейнеров приложения, init контейнеры предлагают механизм, блокирующий или задерживающий запуск контейнера приложения, пока не будет выполнен набор предварительных условий. После выполнения предварительных условий все контейнеры приложений в Pod могут запускаться параллельно.
Примеры init контейнеров
Вот несколько идей о том, как использовать init контейнеры:
- Дождаться создания службы (Service), используя однострочную команду оболочки, например:
for i in {1..100}; do sleep 1; if dig myservice; then exit 0; fi; done; exit 1
- Зарегистрировать Pod на удаленном сервере из нисходящего API (downward API) с помощью команды:
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
- Подождать некоторое время, прежде чем запускать контейнер приложения с помощью команды:
sleep 60
- Клонировать Git репозиторий в том
- Поместить значения в файл конфигурации и запустить инструмент шаблона для динамической генерации файла конфигурации для основного контейнера приложения. Например, поместите значение POD_IP в конфигурацию и создайте основной файл конфигурации приложения, используя Jinja.
Init контейнеры в действии
Этот пример определяет простой Pod, который имеет два init контейнера. Первый ждет myservice, а второй ждет mydb. Как только оба init контейнера завершены, Pod запускает контейнер приложения из своего раздела spec.
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
Следующий YAML файл описывает службы mydb и myservice:
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
Вы можете запустить этот Pod, выполнив:
kubectl apply -f myapp.yaml
pod/myapp-pod created
И проверьте его статус с:
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
или для более подробной информации:
kubectl describe -f myapp.yaml
Name: myapp-pod
Namespace: default
[...]
Labels: app=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
Чтобы просмотреть журналы для init контейнеров в этом Pod, выполните:
kubectl logs myapp-pod -c init-myservice # Проверить первый init контейнер
kubectl logs myapp-pod -c init-mydb # Проверить второй init контейнер
На этом этапе эти init контейнеры будут ожидать обнаружения служб с именами mydb и myservice.
Вот конфигурация, которую вы можете использовать, чтобы эти службы появились:
---
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
Чтобы создать сервисы mydb и myservice:
kubectl apply -f services.yaml
service/myservice created
service/mydb created
Затем вы увидите, что эти init контейнеры завершены, и что myapp-pod Pod переходит в состояние Running:
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
Подробности поведения Pod
Во время запуска Pod каждый init контейнер запускается по порядку, после инициализации сети и томов. Каждый контейнер должен успешно завершиться до запуска следующего контейнера. Если контейнер не запускается из-за времени выполнения или завершается с ошибкой, он повторяется в соответствии с Pod restartPolicy. Однако, если Pod restartPolicy установлен в Always, init контейнеры используют restartPolicy OnFailure.
Pod не может быть готов, пока все init контейнеры не будут выполнены успешно. Порты в init контейнере не агрегированы под Службой (Service). Pod, который инициализируется, находится в состоянии Pending, но для условия Initializing должно быть установлено значение true.
Если Pod перезапускается сам или его перезапускают, все init контейнеры должны выполняться снова.
Изменения в спецификации init контейнера ограничены полем container image. Изменение init поля container image эквивалентно перезапуску Pod.
Поскольку init контейнеры можно перезапустить, повторить или повторно выполнить, код init контейнера должен быть идемпотентным. В частности, код, который записывает файлы в EmptyDirs, должен быть подготовлен к тому, что выходной файл уже существует.
Init контейнеры содержат все поля контейнера приложения. Однако Kubernetes запрещает использование readinessProbe, поскольку init контейнеры не могут определять готовность, отличную от завершения. Это применяется во время валидации.
Используйте activeDeadlineSeconds на Pod и livenessProbe на контейнере, чтобы предотвратить бесконечный сбой init контейнеров. Активный срок включает в себя init контейнеры.
Имя каждого приложения и init контейнера в Pod должно быть уникальным; выдается ошибка проверки для любого контейнера, разделяющего имя с другим.
Ресурсы
Учитывая порядок и выполнение для init контейнеров, применяются следующие правила использования ресурсов:
- Наибольшим из любого конкретного запроса ресурса или лимита, определенного для всех init контейнеров, является эффективный запрос/лимит инициализации (effective init request/limit).
- Эффективный запрос/лимит Pod на ресурс выше:
- сумма всех запросов/лимитов контейнеров приложения для ресурса
- эффективный запрос инициализации/лимит для ресурса
- Планирование выполняется на основе эффективных запросов/ограничений, что означает, что init контейнеры могут резервировать ресурсы для инициализации, которые не используются в течение срока службы Pod'а.
- Уровень QoS (качество обслуживания) эффективного уровня QoS Pod - это уровень QoS для контейнеров init и контейнеров приложений.
Квота и лимиты применяются на основании действующего запроса и лимита Pod.
Группы управления уровнями Pod (cgroups) основаны на действующем запросе и ограничении Pod, так же как и планировщик.
Причины перезапуска Pod
Pod может перезапускаться, вызывая повторное выполнение init контейнеров по следующим причинам:
- Пользователь обновляет спецификацию Pod, вызывая изменение образа init контейнера. Любые изменения в образе init контейнера перезапускают Pod. Изменения образа контейнера приложения только перезапускают контейнер приложения.
- Контейнер инфраструктуры Pod перезапущен. Это необычно и должно быть сделано кем-то с корневым доступом к узлам.
Все контейнеры в Pod завершаются, пока для restartPolicy установлено значение Always, что приводит к принудительному перезапуску, а запись о завершении init контейнера была потеряна из-за сборки мусора.
Читайте также:
Комментарии
Отправить комментарий