Легковесная реализация Docker HEALTHCHECK
без использования внешних утилит (curl
, wget
и тд.), когда требуется проверять результат HTTP-запроса
к приложению. На примере проверки статуса Java-приложения с включенным модулем
Spring Boot Actuator
.
Если базовый образ основан на Alpine
Alpine использует программу BusyBox,
которая реализует в том числе усечённую версию утилиты ncat (nc
).
Общая часть Dockerfile:
FROM eclipse-temurin:21-jre-alpine
ENV TZ=Europe/Moscow
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
RUN addgroup --system --gid 10001 appuser && \
adduser --system --uid 10001 --ingroup appuser --home /opt/app appuser
Варианты:
-
через формирование дополнительного shell-скрипта
healthcheck.sh
, в который "вшивается" номер порта на этапе сборки образа:<общая часть Dockerfile> ARG PORT=8080 EXPOSE ${PORT} WORKDIR /opt/app RUN cat <<EOF > healthcheck.sh && chmod 555 healthcheck.sh #!/bin/sh echo -e "GET /actuator/health HTTP/1.1\r\nHost: localhost:${PORT}\r\n\r\n" \ | nc -w1 localhost ${PORT} \ | grep status | grep UP || exit 1 EOF HEALTHCHECK --start-period=30s --interval=10s --timeout=3s --retries=3 \ CMD ["/opt/app/healthcheck.sh"] ...
-
через использование переменной окружения
PORT
времени выполнения контейнера:<общая часть Dockerfile> ARG PORT=8080 ENV PORT=${PORT} EXPOSE ${PORT} HEALTHCHECK --start-period=30s --interval=10s --timeout=3s --retries=3 \ CMD echo -e "GET /actuator/health HTTP/1.1\r\nHost: localhost:${PORT}\r\n\r\n" \ | nc -w1 localhost ${PORT} \ | grep status | grep UP || exit 1 ...
-
максимально быстрый вариант, но номер порта необходимо прописывать в нескольких местах:
<общая часть Dockerfile> EXPOSE 8080 HEALTHCHECK --start-period=30s --interval=10s --timeout=3s --retries=3 \ CMD echo -e "GET /actuator/health HTTP/1.1\r\nHost: localhost:8080\r\n\r\n" \ | nc -w1 localhost 8080 \ | grep status | grep UP || exit 1 ...
Используется возможность в оболочке bash работать напрямую с TCP-сокетами:
- https://rus-linux.net/MyLDP/consol/tcp-udp-socket-bash-shell.html
- https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Redirections
Общая часть Dockerfile:
FROM eclipse-temurin:21-jre-noble # Ubuntu 24.04
ENV TZ=Europe/Moscow
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
RUN useradd --system --uid 10001 --user-group --home-dir /opt/app --create-home appuser
Варианты:
-
через формирование дополнительного shell-скрипта
healthcheck.sh
, в который "вшивается" номер порта на этапе сборки образа:<общая часть Dockerfile> ARG PORT=8080 EXPOSE ${PORT} WORKDIR /opt/app RUN cat <<EOF > healthcheck.sh && chmod 555 healthcheck.sh #!/bin/bash exec 3<>/dev/tcp/localhost/${PORT} echo -e "GET /actuator/health HTTP/1.1\r\nHost: localhost:${PORT}\r\n\r\n" >&3 timeout 1 cat <&3 | grep status | grep UP || exit 1 EOF HEALTHCHECK --start-period=30s --interval=10s --timeout=3s --retries=3 \ CMD ["/opt/app/healthcheck.sh"] ...
-
через использование переменной окружения
PORT
времени выполнения контейнера:<общая часть Dockerfile> ARG PORT=8080 ENV PORT=${PORT} EXPOSE ${PORT} HEALTHCHECK --start-period=30s --interval=10s --timeout=3s --retries=3 \ CMD ["/usr/bin/bash", "-c", "exec 3<>/dev/tcp/localhost/${PORT}; \ echo -e \"GET /actuator/health HTTP/1.1\r\nHost: localhost:${PORT}\r\n\r\n\" >&3; \ timeout 1 cat <&3 | grep status | grep UP || exit 1"] ...
-
максимально быстрый вариант, но номер порта необходимо прописывать в нескольких местах:
<общая часть Dockerfile> EXPOSE 8080 HEALTHCHECK --start-period=30s --interval=10s --timeout=3s --retries=3 \ CMD ["/usr/bin/bash", "-c", "exec 3<>/dev/tcp/localhost/8080; \ echo -e \"GET /actuator/health HTTP/1.1\r\nHost: localhost:8080\r\n\r\n\" >&3; \ timeout 1 cat <&3 | grep status | grep UP || exit 1"] ...