|
| 1 | +--- |
| 2 | +reviewers: |
| 3 | +- TBD |
| 4 | +- TBD |
| 5 | +title: Хуки жизненного цикла контейнеров |
| 6 | +content_type: concept |
| 7 | +weight: 30 |
| 8 | +--- |
| 9 | + |
| 10 | +<!-- overview --> |
| 11 | + |
| 12 | +На этой странице описывается, как контейнеры под управлением kubelet могут использовать механизм хуков для запуска кода, инициированного событиями во время своего жизненного цикла. |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +<!-- body --> |
| 18 | + |
| 19 | +## Общая информация |
| 20 | + |
| 21 | +Многие платформы для разработки предлагают хуки жизненного цикла компонентов (например, Angular). Kubernetes имеет аналогичный механизм. Хуки позволяют контейнерам оставаться в курсе событий своего жизненного цикла и запускать запакованный в обработчик код при наступлении определенных событий, приводящих к вызову хука. |
| 22 | + |
| 23 | +## Хуки контейнеров |
| 24 | + |
| 25 | +В распоряжении контейнеров имеются два хука: |
| 26 | + |
| 27 | +`PostStart` |
| 28 | + |
| 29 | +Выполняется сразу после создания контейнера. Однако нет гарантии, что хук закончит работу до ENTRYPOINT контейнера. Параметры обработчику не передаются. |
| 30 | + |
| 31 | +`PreStop` |
| 32 | + |
| 33 | +Вызывается непосредственно перед завершением работы контейнера в результате запроса API или иного события (например, неудачное завершение теста liveness/startup, вытеснение, борьба за ресурсы и т.п.). Вызов хука `PreStop` завершается неудачно, если контейнер уже находится в прерванном (terminated) или завершенном (completed) состоянии. Кроме того, работа хука должна закончиться до того, как будет отправлен сигнал TERM для остановки контейнера. Отсчет задержки перед принудительной остановкой Pod'а (grace-период) начинается до вызова хука `PreStop`. Таким образом, независимо от результата выполнения обработчика, контейнер будет остановлен в течение этого grace-периода. Параметры обработчику не передаются. |
| 34 | + |
| 35 | +Более подробное описание поведения при прекращении работы можно найти в разделе [Прекращение работы Pod'ов](/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination). |
| 36 | + |
| 37 | +### Реализации обработчиков хуков |
| 38 | + |
| 39 | +Чтобы контейнер имел доступ к хуку, необходимо реализовать и зарегистрировать обработчик для этого хука. Существует два типа обработчиков хуков, доступных для контейнеров: |
| 40 | + |
| 41 | +* Exec — Выполняет определенную команду, например, `pre-stop.sh`, внутри cgroups и пространств имен контейнера. Ресурсы, потребляемые командой, прибавляются к ресурсам, потребляемым контейнером. |
| 42 | +* HTTP — Выполняет HTTP-запрос к определенной конечной точке контейнера. |
| 43 | + |
| 44 | +### Выполнение обработчиков хуков |
| 45 | + |
| 46 | +При вызове хука, привязанного к жизненному циклу контейнера, система управления Kubernetes выполняет обработчик в соответствии с типом хука: kubelet отвечает за `httpGet` и `tcpSocket`, а `exec` выполняется в контейнере. |
| 47 | + |
| 48 | +Вызовы обработчиков хуков синхронны в контексте Pod'а, содержащего контейнер. Это означает, что в случае `PostStart`-хука ENTRYPOINT контейнера и хук запускаются асинхронно. При этом если хук выполняется слишком долго или зависает, контейнер не может достичь состояния `Running`. |
| 49 | + |
| 50 | +Хуки `PreStop` не запускаются асинхронно с сигналом на остановку контейнера; хук должен завершить свою работу до отправки сигнала TERM. Если хук `PreStop` зависнет во время выполнения, Pod будет пребывать в состоянии `Terminating` до истечения периода `terminationGracePeriodSeconds`, после чего Kubernetes "убьет" его. Этот grace-период включает как время, которое требуется для выполнения хука `PreStop`, так и время, необходимое для нормальной остановки контейнера. Например, если `terminationGracePeriodSeconds` равен 60, работа хука занимает 55 секунд, а контейнеру требуется 10 секунд для нормальной остановки после получения сигнала, то контейнер будет "убит" до того, как сможет нормально завершить свою работу, поскольку `terminationGracePeriodSeconds` меньше, чем суммарное время (55+10), необходимое для работы хука и остановки контейнера. |
| 51 | + |
| 52 | +Если любой из хуков `postStart` / `preStop` завершается неудачей, Kubernetes "убивает" контейнер. |
| 53 | + |
| 54 | +Поэтому обработчики для хуков должны быть максимально простыми. Однако бывают случаи, когда применение "тяжелых" команд оправдано – например, при сохранении состояния перед остановкой контейнера. |
| 55 | + |
| 56 | +### Гарантии поставки хука |
| 57 | + |
| 58 | +Хук должен выполниться *хотя бы один раз*. Это означает, что он может вызываться неоднократно для любого события вроде `PostStart` или `PreStop`. Задача по правильной обработке подобных вызовов возложена на сам хук. |
| 59 | + |
| 60 | +Как правило, поставка хука выполняется однократно. Если, например, приемник HTTP-хука не работает и не может принимать трафик, повторная попытка отправки не предпринимается. В редких случаях может происходить двойная поставка. Например, если kubelet перезапустится в процессе доставки хука, тот может быть отправлен повторно. |
| 61 | + |
| 62 | +### Отладка обработчиков хуков |
| 63 | + |
| 64 | +Логи обработчиков хуков не отображаются в событиях 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`, вы увидите следующее: |
| 65 | + |
| 66 | +``` |
| 67 | +Events: |
| 68 | + Type Reason Age From Message |
| 69 | + ---- ------ ---- ---- ------- |
| 70 | + Normal Scheduled 7s default-scheduler Successfully assigned default/lifecycle-demo to ip-XXX-XXX-XX-XX.us-east-2... |
| 71 | + Normal Pulled 6s kubelet Successfully pulled image "nginx" in 229.604315ms |
| 72 | + Normal Pulling 4s (x2 over 6s) kubelet Pulling image "nginx" |
| 73 | + Normal Created 4s (x2 over 5s) kubelet Created container lifecycle-demo-container |
| 74 | + Normal Started 4s (x2 over 5s) kubelet Started container lifecycle-demo-container |
| 75 | + 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" |
| 76 | + Normal Killing 4s (x2 over 5s) kubelet FailedPostStartHook |
| 77 | + Normal Pulled 4s kubelet Successfully pulled image "nginx" in 215.66395ms |
| 78 | + Warning BackOff 2s (x2 over 3s) kubelet Back-off restarting failed container |
| 79 | +``` |
| 80 | + |
| 81 | + |
| 82 | + |
| 83 | +## {{% heading "whatsnext" %}} |
| 84 | + |
| 85 | + |
| 86 | +* Дополнительная информация о [контейнерном окружении](/docs/concepts/containers/container-environment/). |
| 87 | +* Упражнение: [Подключаем обработчики к событиям жизненного цикла контейнера](/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/). |
0 commit comments