88 lines
10 KiB
Markdown
88 lines
10 KiB
Markdown
---
|
||
reviewers:
|
||
- TBD
|
||
- TBD
|
||
title: Хуки жизненного цикла контейнеров
|
||
content_type: concept
|
||
weight: 30
|
||
---
|
||
|
||
<!-- overview -->
|
||
|
||
На этой странице описывается, как контейнеры под управлением kubelet могут использовать механизм хуков для запуска кода, инициированного событиями во время своего жизненного цикла.
|
||
|
||
|
||
|
||
|
||
<!-- body -->
|
||
|
||
## Общая информация
|
||
|
||
Многие платформы для разработки предлагают хуки жизненного цикла компонентов (например, Angular). Kubernetes имеет аналогичный механизм. Хуки позволяют контейнерам оставаться в курсе событий своего жизненного цикла и запускать запакованный в обработчик код при наступлении определенных событий, приводящих к вызову хука.
|
||
|
||
## Хуки контейнеров
|
||
|
||
В распоряжении контейнеров имеются два хука:
|
||
|
||
`PostStart`
|
||
|
||
Выполняется сразу после создания контейнера. Однако нет гарантии, что хук закончит работу до ENTRYPOINT контейнера. Параметры обработчику не передаются.
|
||
|
||
`PreStop`
|
||
|
||
Вызывается непосредственно перед завершением работы контейнера в результате запроса API или иного события (например, неудачное завершение теста liveness/startup, вытеснение, борьба за ресурсы и т.п.). Вызов хука `PreStop` завершается неудачно, если контейнер уже находится в прерванном (terminated) или завершенном (completed) состоянии. Кроме того, работа хука должна закончиться до того, как будет отправлен сигнал TERM для остановки контейнера. Отсчет задержки перед принудительной остановкой Pod'а (grace-период) начинается до вызова хука `PreStop`. Таким образом, независимо от результата выполнения обработчика, контейнер будет остановлен в течение этого grace-периода. Параметры обработчику не передаются.
|
||
|
||
Более подробное описание поведения при прекращении работы можно найти в разделе [Прекращение работы Pod'ов](/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination).
|
||
|
||
### Реализации обработчиков хуков
|
||
|
||
Чтобы контейнер имел доступ к хуку, необходимо реализовать и зарегистрировать обработчик для этого хука. Существует два типа обработчиков хуков, доступных для контейнеров:
|
||
|
||
* Exec — Выполняет определенную команду, например, `pre-stop.sh`, внутри cgroups и пространств имен контейнера. Ресурсы, потребляемые командой, прибавляются к ресурсам, потребляемым контейнером.
|
||
* HTTP — Выполняет HTTP-запрос к определенной конечной точке контейнера.
|
||
|
||
### Выполнение обработчиков хуков
|
||
|
||
При вызове хука, привязанного к жизненному циклу контейнера, система управления Kubernetes выполняет обработчик в соответствии с типом хука: kubelet отвечает за `httpGet` и `tcpSocket`, а `exec` выполняется в контейнере.
|
||
|
||
Вызовы обработчиков хуков синхронны в контексте Pod'а, содержащего контейнер. Это означает, что в случае `PostStart`-хука ENTRYPOINT контейнера и хук запускаются асинхронно. При этом если хук выполняется слишком долго или зависает, контейнер не может достичь состояния `Running`.
|
||
|
||
Хуки `PreStop` не запускаются асинхронно с сигналом на остановку контейнера; хук должен завершить свою работу до отправки сигнала TERM. Если хук `PreStop` зависнет во время выполнения, Pod будет пребывать в состоянии `Terminating` до истечения периода `terminationGracePeriodSeconds`, после чего Kubernetes "убьет" его. Этот grace-период включает как время, которое требуется для выполнения хука `PreStop`, так и время, необходимое для нормальной остановки контейнера. Например, если `terminationGracePeriodSeconds` равен 60, работа хука занимает 55 секунд, а контейнеру требуется 10 секунд для нормальной остановки после получения сигнала, то контейнер будет "убит" до того, как сможет нормально завершить свою работу, поскольку `terminationGracePeriodSeconds` меньше, чем суммарное время (55+10), необходимое для работы хука и остановки контейнера.
|
||
|
||
Если любой из хуков `postStart` / `preStop` завершается неудачей, Kubernetes "убивает" контейнер.
|
||
|
||
Поэтому обработчики для хуков должны быть максимально простыми. Однако бывают случаи, когда применение "тяжелых" команд оправдано – например, при сохранении состояния перед остановкой контейнера.
|
||
|
||
### Гарантии поставки хука
|
||
|
||
Хук должен выполниться *хотя бы один раз*. Это означает, что он может вызываться неоднократно для любого события вроде `PostStart` или `PreStop`. Задача по правильной обработке подобных вызовов возложена на сам хук.
|
||
|
||
Как правило, поставка хука выполняется однократно. Если, например, приемник HTTP-хука не работает и не может принимать трафик, повторная попытка отправки не предпринимается. В редких случаях может происходить двойная поставка. Например, если kubelet перезапустится в процессе доставки хука, тот может быть отправлен повторно.
|
||
|
||
### Отладка обработчиков хуков
|
||
|
||
Логи обработчиков хуков не отображаются в событиях Pod'а. В случае сбоя обработчика тот транслирует событие. Для `PostStart` это событие `FailedPostStartHook`, для `PreStop` — событие `FailedPreStopHook`. Чтобы самостоятельно сгенерировать событие `FailedPreStopHook`, в манифесте [lifecycle-events.yaml](https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/lifecycle-events.yaml) замените команду для postStart на что-то заведомо невыполнимое (`badcommand`) и примените его. Если теперь выполнить команду `kubectl describe pod lifecycle-demo`, вы увидите следующее:
|
||
|
||
```
|
||
Events:
|
||
Type Reason Age From Message
|
||
---- ------ ---- ---- -------
|
||
Normal Scheduled 7s default-scheduler Successfully assigned default/lifecycle-demo to ip-XXX-XXX-XX-XX.us-east-2...
|
||
Normal Pulled 6s kubelet Successfully pulled image "nginx" in 229.604315ms
|
||
Normal Pulling 4s (x2 over 6s) kubelet Pulling image "nginx"
|
||
Normal Created 4s (x2 over 5s) kubelet Created container lifecycle-demo-container
|
||
Normal Started 4s (x2 over 5s) kubelet Started container lifecycle-demo-container
|
||
Warning FailedPostStartHook 4s (x2 over 5s) kubelet Exec lifecycle hook ([badcommand]) for Container "lifecycle-demo-container" in Pod "lifecycle-demo_default(30229739-9651-4e5a-9a32-a8f1688862db)" failed - error: command 'badcommand' exited with 126: , message: "OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: \"badcommand\": executable file not found in $PATH: unknown\r\n"
|
||
Normal Killing 4s (x2 over 5s) kubelet FailedPostStartHook
|
||
Normal Pulled 4s kubelet Successfully pulled image "nginx" in 215.66395ms
|
||
Warning BackOff 2s (x2 over 3s) kubelet Back-off restarting failed container
|
||
```
|
||
|
||
|
||
|
||
## {{% heading "whatsnext" %}}
|
||
|
||
|
||
* Дополнительная информация о [контейнерном окружении](/docs/concepts/containers/container-environment/).
|
||
* Упражнение: [Подключаем обработчики к событиям жизненного цикла контейнера](/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/).
|