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) всё должно точно также запуститься.
|
`~/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