From ae8654513a931ec4f45d5efb1c53de69c580342b 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 | 4 ++- Dockerfile-debian.template | 1 + entrypoint/99-monitor-config-changes.sh | 44 +++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100755 entrypoint/99-monitor-config-changes.sh diff --git a/Dockerfile-alpine-slim.template b/Dockerfile-alpine-slim.template index 3b85b5c73..638630ce2 100644 --- a/Dockerfile-alpine-slim.template +++ b/Dockerfile-alpine-slim.template @@ -101,6 +101,8 @@ RUN set -x \ && ln -sf /dev/stderr /var/log/nginx/error.log \ # Ensure we can run our entrypoint && apk add --no-cache dumb-init \ +# 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 7e9ba1566..5f3d7c1a8 100644 --- a/Dockerfile-alpine.template +++ b/Dockerfile-alpine.template @@ -77,4 +77,6 @@ RUN set -x \ # Bring in curl and ca-certificates to make registering on DNS SD easier && apk add --no-cache curl ca-certificates \ # Ensure we can run our entrypoint - && apk add --no-cache dumb-init + && apk add --no-cache dumb-init \ +# 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 bb72fabcc..99941508d 100644 --- a/Dockerfile-debian.template +++ b/Dockerfile-debian.template @@ -83,6 +83,7 @@ RUN set -x \ gettext-base \ curl \ dumb-init \ + inotify-tools \ && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list \ \ # if we have leftovers from building, let's purge them (including extra, unnecessary build deps) diff --git a/entrypoint/99-monitor-config-changes.sh b/entrypoint/99-monitor-config-changes.sh new file mode 100755 index 000000000..c2ed02b3d --- /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