diff --git a/60_create_monitors.sh b/60_create_monitors.sh new file mode 100755 index 0000000..00969a1 --- /dev/null +++ b/60_create_monitors.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +function ts { + echo [`date '+%Y-%m-%d %H:%M:%S'`] MASTER: +} + +echo "$(ts) Starting master controller" + +if [ -f /config/sample.conf ]; then + echo "$(ts) /config/sample.conf exists. Rename it to .conf, check the settings, then rerun the container. Exiting." + exit 1 +fi + +readarray -t CONFIG_FILES < <(ls /config/*.conf) + +# If there is no config file copy the default one +if [[ "$CONFIG_FILES" == "" ]] +then + echo "$(ts) Creating sample config file. Rename it to .conf, check the settings, then rerun the container. Exiting." + cp /files/sample.conf /config/sample.conf + chmod a+w /config/sample.conf + exit 1 +fi + +for CONFIG_FILE in "${CONFIG_FILES[@]}" +do + FILENAME=$(basename "$CONFIG_FILE") + + echo "$(ts) Creating monitor for $FILENAME" + + FILEBASE="${FILENAME%.*}" + + mkdir -p /etc/service/$FILEBASE + + cat > /etc/service/$FILEBASE/run < - -# Use baseimage-docker's init system -CMD ["/sbin/my_init"] - -ENV DEBIAN_FRONTEND noninteractive -ADD dpkg-excludes /etc/dpkg/dpkg.cfg.d/excludes +ENV TERM=xterm-256color RUN true && \ +\ +echo "http://dl-cdn.alpinelinux.org/alpine/v3.7/community" >> /etc/apk/repositories && \ +apk --update upgrade && \ +\ +# Basics, including runit +apk add bash curl htop runit && \ +\ +# Needed by our code +apk add --no-cache python3 icu-libs shadow && \ +pip3 install watchdog && \ +wget https://raw.githubusercontent.com/phusion/baseimage-docker/9f998e1a09bdcb228af03595092dbc462f1062d0/image/bin/setuser -O /sbin/setuser && \ +chmod +x /sbin/setuser && \ +\ +rm -rf /var/cache/apk/* && \ +\ +# RunIt stuff +adduser -h /home/user-service -s /bin/sh -D user-service -u 2000 && \ +chown user-service:user-service /home/user-service && \ +mkdir -p /etc/run_once /etc/service -set -x && \ - -# Create dir to keep things tidy. Make sure it's readable by $UID -mkdir /files && \ -chmod a+rwX /files && \ - -# Speed up APT -echo "force-unsafe-io" > /etc/dpkg/dpkg.cfg.d/02apt-speedup && \ -echo "Acquire::http {No-Cache=True;};" > /etc/apt/apt.conf.d/no-cache && \ - -apt-get update && \ -apt-get install -qy python3-watchdog wget && \ - -# clean up -apt-get clean && \ -rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ -/usr/share/man /usr/share/groff /usr/share/info \ -/usr/share/lintian /usr/share/linda /var/cache/man && \ -(( find /usr/share/doc -depth -type f ! -name copyright|xargs rm || true )) && \ -(( find /usr/share/doc -empty|xargs rmdir || true )) +# Boilerplate startup code +COPY ./boot.sh /sbin/boot.sh +RUN chmod +x /sbin/boot.sh +CMD [ "/sbin/boot.sh" ] VOLUME ["/config", \ "/dir1", "/dir2", "/dir3", "/dir4", "/dir5", "/dir6", "/dir7", "/dir8", "/dir9", "/dir10", \ "/dir11", "/dir12", "/dir13", "/dir14", "/dir15", "/dir16", "/dir17", "/dir18", "/dir19", "/dir20"] # Set the locale, to help Python and the user's applications deal with files that have non-ASCII characters -RUN locale-gen en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 @@ -45,11 +42,11 @@ ENV LC_ALL en_US.UTF-8 ENV UMAP "" ENV GMAP "" -# Add local files COPY sample.conf monitor.py runas.sh /files/ +# Make sure it's readable by $UID +RUN chmod a+rwX /files -ADD 50_remap_ids.sh /etc/my_init.d/ - -RUN mkdir /etc/service/monitor -ADD monitor.sh /etc/service/monitor/run -RUN chmod +x /etc/service/monitor/run +# run-parts ignores files with "." in them +ADD 50_remap_ids.sh /etc/run_once/50_remap_ids +ADD 60_create_monitors.sh /etc/run_once/60_create_monitors +RUN chmod +x /etc/run_once/* diff --git a/boot.sh b/boot.sh new file mode 100755 index 0000000..51239ce --- /dev/null +++ b/boot.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +# Based on https://github.com/sanjeevan/baseimage + +shutdown() { + echo + echo "Shutting down container..." + + # first shutdown any service started by runit + for _srv in $(ls -1 /etc/service); do + sv force-stop $_srv + done + + # shutdown runsvdir command + kill -HUP $RUNSVDIR + wait $RUNSVDIR + + # give processes time to stop + sleep 0.5 + + # kill any other processes still running in the container + for _pid in $(ps -eo pid | grep -v PID | tr -d ' ' | grep -v '^1$' | head -n -6); do + timeout -t 5 /bin/sh -c "kill $_pid && wait $_pid || kill -9 $_pid" + done + + exit +} + +# catch shutdown signals +trap shutdown SIGTERM SIGHUP SIGQUIT SIGINT + +# store environment variables +export > /etc/envvars + +PATH=/bin:/sbin:/usr/bin + +# run all scripts in the run_once folder +if ! /bin/run-parts /etc/run_once +then + echo "Run-once scripts failed. Stopping container" + shutdown +fi + +exec env - PATH=$PATH runsvdir -P /etc/service & + +RUNSVDIR=$! +echo "Started runsvdir, PID is $RUNSVDIR. Waiting for processes to start...." + +sleep 5 +for _srv in $(ls -1 /etc/service); do + sv status $_srv +done + +wait $RUNSVDIR + +shutdown diff --git a/dpkg-excludes b/dpkg-excludes deleted file mode 100644 index b028b9d..0000000 --- a/dpkg-excludes +++ /dev/null @@ -1,16 +0,0 @@ -path-exclude /usr/share/doc/* -# we need to keep copyright files for legal reasons -path-include /usr/share/doc/*/copyright -path-exclude /usr/share/man/* -path-exclude /usr/share/groff/* -path-exclude /usr/share/info/* -# lintian stuff is small, but really unnecessary -path-exclude /usr/share/lintian/* -path-exclude /usr/share/linda/* -# Drop locales except English -path-exclude=/usr/share/locale/* -path-include=/usr/share/locale/en/* -path-include=/usr/share/locale/locale.alias - - - diff --git a/monitor.sh b/monitor.sh deleted file mode 100755 index c36d3a0..0000000 --- a/monitor.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash - -function ts { - echo [`date '+%Y-%m-%d %H:%M:%S'`] MASTER: -} - -echo "$(ts) Starting master controller" - -if [ -f /config/sample.conf ]; then - echo "$(ts) /config/sample.conf exists. Rename it, check the settings, then rerun the container. Exiting." - exit 1 -fi - -readarray -t CONFIG_FILES < <(ls /config/*.conf) - -# If there is no config file copy the default one -if [[ "$CONFIG_FILES" == "" ]] -then - echo "$(ts) Creating sample config file. Rename it, check the settings, then rerun the container. Exiting." - cp /files/sample.conf /config/sample.conf - chmod a+w /config/sample.conf - exit 1 -fi - -PIDS=() - -for CONFIG_FILE in "${CONFIG_FILES[@]}" -do - echo "$(ts) Launching monitor for $CONFIG_FILE" - /files/monitor.py $CONFIG_FILE & - PIDS+=($!) -done - -# Sleep for a second to allow the monitors to check their config files -sleep 1 - -while true -do - for ((i = 0; i < ${#PIDS[@]}; i++)) - do - if ps -p ${PIDS[$i]} > /dev/null - then - continue - fi - - echo "$(ts) Monitor for ${CONFIG_FILES[$i]} has died (PID ${PIDS[$i]}). Killing other monitors and exiting." - - for PID in "${PIDS[@]}" - do - kill -9 $PID >/dev/null 2>&1 - done - - exit 2 - done - - sleep 60 -done