From 506fd0f3e3670557be2ecb41424a2702fd7bd01e Mon Sep 17 00:00:00 2001 From: Olliver Schinagl Date: Sun, 4 Jun 2023 16:59:20 +0200 Subject: [PATCH] entrypoint: Monitor config dir for changes We see a lot of crudges and hacks to notify nginx or the nginx container informing it it needs to restart. While there certainly cases that require manual control, for the most, this could be easily automated. With inotify, we can recursively monitor /etc/nginx (or any directory per config) for changes (currently, not monitoring for for access time changes, e.g. reads or `touch` (not creating new files) events). On an event, we sleep first for (configurable) seconds, the default is 10, so that multiple updates don't cause multiple restarts. E.g. copying 10 certificates into /etc/nginx/certs, won't trigger 10 reloads. The monitor will run indefinably, but to ensure there is 'some' way to exit it, is to remove the pid file (configurable location) and triggering a `/etc/nginx` change (`touch '/etc/nginx/exit'` for example to create a file. It's not perfect, but probably will never be used anyway. The current configuration won't change existing behavior, it needs to be explicitly enabled. Signed-off-by: Olliver Schinagl --- Dockerfile-alpine-slim.template | 2 ++ Dockerfile-alpine.template | 2 ++ Dockerfile-debian.template | 1 + entrypoint/99-monitor-config-changes.sh | 44 +++++++++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100755 entrypoint/99-monitor-config-changes.sh diff --git a/Dockerfile-alpine-slim.template b/Dockerfile-alpine-slim.template index f6803565..580dbd14 100644 --- a/Dockerfile-alpine-slim.template +++ b/Dockerfile-alpine-slim.template @@ -102,6 +102,8 @@ RUN set -x \ # Ensure we can run our entrypoint and make it debian compatible && apk add --no-cache tini \ && ln -s /sbin/tini /usr/bin/tini \ +# Add support for manually monitoring files to trigger server reloads + && apk add --no-cache inotify-tools \ # create a docker-entrypoint.d directory && mkdir /docker-entrypoint.d diff --git a/Dockerfile-alpine.template b/Dockerfile-alpine.template index dede8171..ac0e81d5 100644 --- a/Dockerfile-alpine.template +++ b/Dockerfile-alpine.template @@ -79,3 +79,5 @@ RUN set -x \ # Ensure we can run our entrypoint and do it compatible with alpine && apk add --no-cache tini \ && ln -s /sbin/tini /usr/bin/tini +# Add support for manually monitoring files to trigger server reloads + && apk add --no-cache inotify-tools diff --git a/Dockerfile-debian.template b/Dockerfile-debian.template index e323235f..dd1cd9bd 100644 --- a/Dockerfile-debian.template +++ b/Dockerfile-debian.template @@ -83,6 +83,7 @@ RUN set -x \ gettext-base \ curl \ tini \ + inotify-tools \ && ln -s /usr/bin/tini /sbin/tini \ && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ \ diff --git a/entrypoint/99-monitor-config-changes.sh b/entrypoint/99-monitor-config-changes.sh new file mode 100755 index 00000000..c2ed02b3 --- /dev/null +++ b/entrypoint/99-monitor-config-changes.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu +if [ -n "${DEBUG_TRACE_SH:-}" ] && \ + [ "${DEBUG_TRACE_SH:-}" != "${DEBUG_TRACE_SH#*"$(basename "${0}")"*}" ] || \ + [ "${DEBUG_TRACE_SH:-}" = 'all' ]; then + set -x +fi + +LC_ALL=C + +if [ -e "${NGINX_ENTRYPOINT_MONITOR_PID:=/run/nginx_monitor.pid}" ] || + [ -z "${NGINX_ENTRYPOINT_MONITOR_CONFIG+monitor}" ] || \ + ! command -v inotifywait; then + exit 0 +fi + +echo "Monitoring for changes in '${NGINX_ENTRYPOINT_MONITOR_CONFIG:=/etc/nginx}'" +while true; do + inotifywait \ + --recursive \ + --event 'create' \ + --event 'delete' \ + --event 'modify' \ + --event 'move' \ + "${NGINX_ENTRYPOINT_MONITOR_CONFIG}" + + sleep "${NGINX_ENTRYPOINT_MONITOR_DELAY:-10s}" + + if [ ! -e "${NGINX_ENTRYPOINT_MONITOR_PID}" ]; then + logger -s -t 'nginx' -p 'local0.3' 'Monitor failure or exit requested' + break + fi + + if nginx -t; then + nginx -s + else + logger -s -t 'nginx' -p 'local0.3' 'Refusing to reload config, config error' + fi +done & +echo "${!}" > "${NGINX_ENTRYPOINT_MONITOR_PID}" + +exit 0