Как использовать хуки Kubernetes для отслеживания жизненного цикла контейнера
Хуки обычно используются для регистрации событий контейнера, реализации сценариев очистки и запуска асинхронных задач после присоединения нового пода к вашему кластеру. В этой статье мы покажем, как прикрепить обработчики ловушек к вашим подам и получить больше контроля над жизненными циклами контейнеров.
Два доступных крючка
Текущие выпуски Kubernetes поддерживают два хука жизненного цикла контейнера:
PostStart
— обработчики этого хука вызываются сразу после создания нового контейнера.PreStop
. Этот хук вызывается непосредственно перед тем, как Kubernetes завершает работу контейнера.
Их можно обрабатывать с помощью двух разных механизмов:
Exec
— запускает указанную команду внутри контейнера.HTTP
— делает HTTP-запрос к URL-адресу внутри контейнера.
Ни один из хуков не предоставляет никаких аргументов своим обработчикам. Каждый контейнер поддерживает один обработчик для каждого хука; невозможно вызвать несколько конечных точек или объединить команду exec с HTTP-запросом.
Определение обработчиков ловушек
Вы определяете обработчики ловушек для модулей, используя их поле манифеста containers.lifecycle
. В этом поле задайте свойства postStart
и preStop
, чтобы реализовать один или оба доступных хука.
Вот простой модуль, который регистрирует сообщение при запуске:
apiVersion: v1 kind: Pod metadata: name: pod-with-hooks spec: containers: - name: pod-hook-container image: nginx:latest lifecycle: postStart: exec: command: ["/bin/sh", "-c", "echo STARTED > /startup_message"]
Примените Pod к своему кластеру с помощью Kubectl:
$ kubectl apply -f pod.yaml
Теперь добавьте оболочку в работающий контейнер внутри пода:
$ kubectl exec --stdin --tty pod/pod-with-hooks -- sh
Прочтите содержимое файла /startup_message
:
$ cat /startup_message
STARTED
Это показывает, что хук был вызван успешно. Хук exec считается успешным, если его команда завершается с нулевым кодом состояния.
HTTP-обработчики
Вы можете настроить обработчик HTTP, заменив поле exec
на httpGet
. Поддерживаются только запросы HTTP GET
(отсутствует поле httpPost
).
apiVersion: v1 kind: Pod metadata: name: pod-with-hooks spec: containers: - name: pod-hook-container image: nginx:latest lifecycle: postStart: httpGet: path: /startup port: 80
В этом примере Kubernetes отправляет запрос GET
в /startup
через порт 80 контейнера. Поле httpGet
также принимает scheme
и host
для дальнейшей настройки запроса.
Вот модуль, в котором /shutdown
вызывается через HTTPS до завершения работы контейнера:
apiVersion: v1 kind: Pod metadata: name: pod-with-hooks spec: containers: - name: pod-hook-container image: nginx:latest lifecycle: preStop: httpGet: path: /startup scheme: HTTPS
Обработчики HTTP-ловушек считаются успешными, если код ответа HTTP находится в диапазоне 200-299.
Отладка ваших обработчиков
Обработчики хуков управляются независимо от модулей, к которым они подключены. Их журналы не собираются и не хранятся вместе с обычными журналами Pod, поэтому вы не увидите команды exec, такие как echo Started
, при запуске kubectl logs pod/pod-with-hooks
.
Вы можете отлаживать хуки, просматривая историю событий пода. О неудачных вызовах сообщается как о событиях FailedPostStartHook
и FailedPreStophook
. Сообщение об ошибке включает описание того, что вызвало ошибку.
Попробуйте добавить этот модуль в свой кластер:
apiVersion: v1 kind: Pod metadata: name: pod-with-hooks spec: containers: - name: pod-hook-container image: nginx:latest lifecycle: postStart: exec: command: ["missing-command"]
Сломанный хук PostStart приведет к сбою запуска пода. Используйте kubectl описать
, чтобы получить доступ к его истории событий:
$ kubectl describe pod/pod-with-hooks
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 30s default-scheduler Successfully assigned pod-with-hooks...
Normal Created 10s (x2 over 11s) kubelet Created container pod-hook-container
Normal Started 10s (x2 over 11s) kubelet Started container pod-hook-container
Warning FailedPostStartHook 10s (x2 over 11s) kubelet Exec lifecycle hook ([missing-command]) for Container "pod-hook-container" in Pod "pod-with-hooks" failed - error: command 'missing-command' exited with 126: , message: "OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: "missing-command": executable file not found in $PATH: unknownrn"
Normal Killing 10s (x2 over 11s) kubelet FailedPostStartHook
Warning BackOff 5s (x2 over 6s) kubelet Back-off restarting failed container
Событие FailedPostStartHook
указывает на сбой обработчика, поскольку missing-command
не является допустимым исполняемым файлом внутри контейнера. Это привело к тому, что контейнер был уничтожен и перезапущен в цикле отсрочки. Это застрянет навечно, так как missing-command
никогда не будет исполняемым.
На что обратить внимание
Вызовы хуков имеют несколько характеристик, которые могут вас застать врасплох. Помня об этом, вы сможете избежать странного поведения и неожиданных сбоев.
- Хуки могут вызываться более одного раза. Kubernetes гарантирует, что ваши обработчики
PostStart
иPreStop
будут вызываться «как минимум» один раз для каждого контейнера. . В некоторых ситуациях хук может вызываться несколько раз. Ваши обработчики должны быть идемпотентными, чтобы они могли противостоять этой возможности. - Неудачные перехватчики уничтожают свой контейнер. Как показано в приведенном выше примере отладки, неудачные перехватчики немедленно уничтожают свой контейнер. Вам нужно убедиться, что ваши команды и конечные точки HTTP не содержат ошибок, чтобы избежать непредвиденных проблем с запуском Pod. Обработчики хуков должны быть легкими и свободными от зависимостей. Не пытайтесь получить доступ к ресурсу, который может быть недоступен сразу после запуска вашего контейнера. Перехватчики
PostStart
соревнуются сENTRYPOINT
контейнера.PostStart
срабатывает примерно в то же время, когда создается контейнер . Однако Kubernetes не ждет хука — он будет вызываться асинхронно вместе сENTRYPOINT
контейнера, что может завершиться до того, как будет вызван обработчик вашего хука. Это означает, что скрипт точки входа вашего контейнера начнет выполняться, даже если ваш обработчик сообщит об ошибке и в конечном итоге уничтожит контейнер. Перехватчики PreStop
будут блокировать завершение работы контейнера. Kubernetes гарантирует, что ваши контейнеры не будут завершены до тех пор, пока их перехватчикиPreStop
не будут завершены, но не более время, определяемое льготным периодом завершения Pod. Контейнер будет закрыт независимо от того, работает ли хук по истечении льготного периода. Перехватчики PreStop
не вызываются для завершенных модулей. Это может быть особенно эффективным в зависимости от вашего варианта использования. Текущая реализацияPreStop
срабатывает только тогда, когда Pod завершается из-за удаления, исчерпания ресурсов, сбоя проверки или подобного события. Ловушка не будет вызываться для контейнеров, которые останавливаются естественным образом, потому что их процесс завершает свою задачу и завершается с нулевым кодом ошибки.
Хуки напрямую влияют на жизненный цикл ваших модулей. Поды не могут быть помечены как Running
, пока их хук PostStart
не завершится; аналогично, Pod будет зависать Завершение
до тех пор, пока PreStop
не завершится.
Заключение
События жизненного цикла Kubernetes — это способ уведомить контейнеры об их собственном создании и предстоящем удалении. Предоставляя команды или конечные точки API внутри своего контейнера, вы можете отслеживать критические этапы жизненного цикла и сообщать о них другим компонентам вашей инфраструктуры.
События жизненного цикла легко настроить, но они также имеют некоторые распространенные ловушки. Вы можете использовать смежные механизмы, такие как тесты запуска и готовности, если вам нужен более надежный вызов. Это лучший вариант для сценариев, которые необходимы при подготовке среды нового контейнера.