Table of Contents

About

This docker build file is created in order to build monit.

Usage

Download the file Dockerfile to an empty directory and issue:

docker build -t TAG .

where:

After caddy is built, a container can be created and ran either via docker run or deployed within the swarm with docker stack deploy.

Note that if the image is to be deployed to a swarm, then more than likely the image should be committed to a local registry serving the local docker swarm.

Developer Notes

One of the problem with daemons like Monit is that daemons typically do not reload their configuration file, nor any subsequent "additional files" such that any change to the configuration must be succeeded by a manual reload or signalling of the process.

In cases similar to Docker where there is no direct access to the system, the reload is difficult to perform due to no direct access to the machine. By contrast, changing a configuration is fairly robust, even remotely and is covered by the many remote filesystems available. For this reasons, daemons created by us such as Corrade are built to monitor their own configuration and reload it when changes are perceived, even if that breaks imperative programming tradition in favor of functional, or rather, event-driven programming.

To counter the shortage of this feature, one cool way is to leverage filesystem notifications, for example inotify, particularly via tools such as inotifywait and to then (preferrably) schedule an interruptible execution of a daemon reload similar to the alarm(2) function in systems programming. In what regards Docker, a second program is added, conveniently a simple bash script, that runs continuously and waits for the mapped folder containing the configuration to issue a MODIFY event. When the MODIFY event is raised, a configuration reload is scheduled (in this case, via monit reload, others could consist in delivering a HUP signal) into the future. Whilst the user keeps changing the configuration, any followup MODIFY events raised by the filesystem increase the wait duration (reset the alarm) by cancelling the previous timer and re-installing it. Once the user stops tampering with the configuration, and when the alarm elapses, the configuration is reloaded.

The script relevant to this scheme is mentioned in the Source section and its applicability extends far beyond this Docker build of the Monit daemon to any daemon that is not able to automatically sense a configuration change and reload its own configuration.

Source

Here are the various components found in the Subversion repository at:

monitrc

include /conf/*

supervisor.conf

[supervisord]
user=root
nodaemon=true
 
[program:monit]
command=/usr/local/bin/monit -v -I -l /dev/stdout -c /etc/monitrc
autorestart=true
stdout_logfile=/dev/stdout
stderr_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile_maxbytes=0
 
[program:monit_config]
command=/bin/bash /usr/local/bin/monit-watch-services
autorestart=true
stdout_logfile=/dev/stdout
stderr_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile_maxbytes=0

Dockerfile

FROM debian:bookworm-slim
 
# add filesystem requirements
ADD rootfs /
 
# update package manager
RUN  apt-get update -y && \
     apt-get upgrade -y && \
     apt-get dist-upgrade -y && \
     apt-get -y autoremove && \
     apt-get clean
 
# install preliminary packages
RUN apt-get install -y \
    coreutils \
    bash \
    curl \
    ca-certificates \
    build-essential \
    distcc \
    autoconf \
    automake \
    libtool \
    zlib1g \
    zlib1g-dev \
    libssl3 \
    libssl-dev \
    supervisor \
    inotify-tools
 
# compile
WORKDIR /tmp
RUN mkdir -p /tmp/build && \
  curl -o /tmp/build/source.tar.gz "https://mmonit.com/monit/dist/monit-latest.tar.gz" && \
  cd /tmp/build && \
  tar --strip=1 -xf source.tar.gz && \
  export DISTCC_HOSTS="docker1.internal:35001 docker2.internal:35002 docker3.internal:35003" CC="distcc" CXX="distcc g++" && \
  ./configure --without-pam && \
  make -j4 && \
  make install && \
  rm -rf /tmp/build
 
# remove packages that will not be used
RUN apt-get purge -y \
        curl \
        git \
        build-essential \
        autoconf \
        automake \
        libtool \
        pkgconf && \
    apt-get autoremove -y
 
EXPOSE 2812
 
WORKDIR /
 
ENTRYPOINT [ "supervisord", "-t", "-n", "-c", "/etc/supervisor.conf" ]

monit-watch-services

#!/usr/bin/env bash
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2024 - License: MIT            ##
###########################################################################
# The following script will reload monit upon configuration changes and   #
# the script is meant to be ran as a standalone long-runnng process.      #
# Note that the script uses "inotifywait" and leverages filesystem file   #
# notifiacations for a lower CPU usage and only asynchronously reloads    #
# the configuration when changes have been made (ie: instead of polling). #
###########################################################################
 
# alarm(2)
function alarm {
    sleep $1
    monit reload
}
 
ALARM_PID=0
trap '{ test $ALARM_PID = 0 || kill -9 $ALARM_PID; }' KILL QUIT TERM EXIT INT HUP
 
MONIT_DIRECTORY=/conf
inotifywait -q -m "$MONIT_DIRECTORY" -r \
    -e "modify" -e "create" -e "delete" | \
    while IFS=$'\n' read -r LINE; do
    if [ -d /proc/"$ALARM_PID" ]; then    
        kill -9 $ALARM_PID
    fi
    alarm "5" &
    ALARM_PID=$!
done