add: Зависимости и хелсчеки (6)
This commit is contained in:
parent
9de84306d8
commit
a64615386d
@ -479,4 +479,119 @@ dd0b7a683dde certbot/certbot:latest "/bin/sh -c 'apk add…" 13
|
||||
**Все!** Теперь у нас полностью контейнеризированное решение, без лишних зависимостей на хосте, и при переносе каталога
|
||||
`~/docker-data` на другой сервер (с Docker + docker-compose) всё должно точно также запуститься.
|
||||
|
||||
## Зависимости и "проверки здоровья"
|
||||
|
||||
В нашем случае контейнеры не особо зависят друг от друга, но если стремиться к идеальной контейнеризации, то можно
|
||||
рассмотреть "кто на ком стоит", какие зависимости и какой порядок запуска контейнеров.
|
||||
|
||||
Самый независимый контейнер — это `portainer`. Он просто запускается и работает. Начали его проксировать через nginx
|
||||
или нет — ему важно.
|
||||
|
||||
Контейнер `letsencrypt-certbot` зависит от контейнера `nginx`, так как он без него не пройдет валидация домена.
|
||||
Решение установить `depends_on` от контейнера `nginx` не идеально, т.к. старт контейнера `nginx` не означает, что он
|
||||
готов принимать запросы. Избежать проблем можно сделав **healthcheck** для Nginx.
|
||||
|
||||
В docker-compose.yml добавим:
|
||||
```yaml
|
||||
nginx:
|
||||
...
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
...
|
||||
...
|
||||
|
||||
certbot:
|
||||
...
|
||||
depends_on:
|
||||
nginx:
|
||||
condition: service_healthy
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
Что тут происходит:
|
||||
- `healthcheck: ...` — добавляем блок в контейнере `nginx` для проверки его здоровья. В данном случае проверяем
|
||||
доступность Nginx выполняя команду `curl -f http://localhost`. Если Nginx отвечает, то контейнер считается здоровым;
|
||||
- `interval: 10s` — проверка состояния каждые 10 секунд;
|
||||
- `timeout: 3s` — ожиданий проверки 3 секунды (когда curl зависнет дольше 3 секунд, то это считается ошибкой);
|
||||
- `retries: 3` — количество попыток проверки (если команда завершается с ошибкой (код ≠ 0) — Docker попробует ещё
|
||||
раз... и так до 3-х раз);
|
||||
- `start_period: 10s` — время ожидания перед началом проверок (первая проверка будет выполнена через 10 секунд после
|
||||
старта контейнера);
|
||||
- `depends_on: ...` — добавляем зависимость контейнера `certbot` от контейнера `nginx`. Но не просто так, а с условием
|
||||
`service_healthy`. Это означает, что контейнер `certbot` не будет запущен, пока контейнер `nginx` не будет здоров.
|
||||
|
||||
Теперь при запуске контейнера `certbot` он будет ждать, пока контейнер `nginx` не станет здоровым (а еще задержку
|
||||
в 10 секунд будет заметно даже на глаз).
|
||||
|
||||
К сожалению, если `nginx` упадет в процессе, то `certbot` не будет перезапущен. Но это уже другая история,
|
||||
мир не идеален.
|
||||
|
||||
### Погасить проверку здоровья после первого успешного запуска (раздел для параноиков)
|
||||
|
||||
Бдительный читатель может заметить, что проверка `curl -f http://localhost` будет порождать бесполезную нагрузку на
|
||||
сервере (ведь кажется, что по locahost будет отвечать `portainer`, а не `nginx`). Но это не так. Прокси на `portainer`
|
||||
отвечать там не будет (ведь он настроен на домен `portainer.you.domain.name`), а будет отдавать дефолтную страницу
|
||||
`nginx`. У нас она даже не настроена, и будет 301, а это вообще очень-очень мало не потребляет...
|
||||
|
||||
Тем не менее есть способ погасить проверку здоровья, как только контейнер стал `healthy` (допустим, чтобы "не следить"
|
||||
в логах). У нас есть мапп `/home/web/docker-data/letsencrypt/_cert:/etc/letsencrypt` внутри контейнера `nginx`. Если мы
|
||||
создадим скрипт в каталоге `/home/web/docker-data/letsencrypt/_cert` он будет доступен внутри контейнера в каталоге
|
||||
`/etc/letsencrypt`. Создадим скрипт `healthcheck-nginx.sh`:
|
||||
```bash
|
||||
nano /home/web/docker-data/letsencrypt/_cert/healthcheck-nginx.sh
|
||||
```
|
||||
|
||||
И поместим в него следующее содержимое:
|
||||
```bash
|
||||
#!/bin/sh
|
||||
HEALTH_FILE_FLAG="/tmp/nginx_healthy"
|
||||
|
||||
if [ -f "HEALTH_FILE_FLAG" ]; then
|
||||
exit 0 # Уже healthy, больше не проверяем
|
||||
fi
|
||||
|
||||
if curl -fs http://localhost > /dev/null; then
|
||||
touch "HEALTH_FILE_FLAG" # Создаем файл-флаг
|
||||
exit 0 # Успешная проверка
|
||||
else
|
||||
exit 1 # Nginx еще не поднялся, пусть проверяют еще
|
||||
fi
|
||||
```
|
||||
|
||||
Что будет происходить. При старте контейнера `nginx` через *healthcheck* будем запускать этот скрипт.
|
||||
При первом запуске он проверит есть ли файл-флаг `/tmp/nginx_healthy` внутри контейнера. Сразу после старта контейнера
|
||||
этого фал-флага нет (контейнер запускается "чистым"). Затем скрипт попытается выполнить `curl -fs http://localhost`.
|
||||
Если Nginx еще не поднялся, то **curl** возвращает ошибку и контейнер остается *unhealthy*. Но если Nginx уже работает,
|
||||
то **touch** создается файл-флаг `/tmp/nginx_healthy` то **exit 0** ответит, что контейнер *healthy*.⃣ При всех
|
||||
следующих *healthcheck* проверка файл-флага пройдет успешно, сразу будет получен `exit 0` и проверка *healthy* будет
|
||||
завершена без вызова `curl`.
|
||||
|
||||
Осталось добавить этот скрипт в `docker-compose.yml`:
|
||||
```yaml
|
||||
nginx:
|
||||
...
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "/etc/letsencrypt/healthcheck-nginx.sh"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
...
|
||||
...
|
||||
```
|
||||
|
||||
### Зависимости и healthcheck для `portainer` (или параноики могут сломать бизнес-логику)
|
||||
|
||||
А что с `nginx` и `portainer`? Они зависят друг от друга? Кажется нет. Если `nginx` упадет, то `portainer` просто
|
||||
станет недоступен (ничего не будет доступно вообще). Если же `portainer` упадет, то `nginx` будет отдавать ошибку 502.
|
||||
Ошибка, в данном случае, это тоже информация. Как минимум мы увидим что nginx работает, а упало приложение.
|
||||
|
||||
Тем не менее можно добавить `healthcheck` в `portainer`, проверять, что он отвечает внутри себя по порту 9000,
|
||||
а затем установить зависимость `nginx` от здоровья `portainer`.
|
||||
|
||||
Но, кажется, это уже перебор.
|
Loading…
Reference in New Issue
Block a user