From b856b3a770d8358127fc56d25d7198ef0c6a60a9 Mon Sep 17 00:00:00 2001 From: Austin Best Date: Tue, 14 Nov 2023 18:45:09 -0500 Subject: [PATCH] Initial commit based on the cron container, adding nginx --- .dockerignore | 4 ++ .github/renovate.json | 16 +++++++ .github/workflows/docker-publish.yml | 67 ++++++++++++++++++++++++++++ Dockerfile | 44 ++++++++++++++++++ LICENSE | 21 +++++++++ README.md | 51 +++++++++++++++++++++ crontab | 5 +++ supervisor/conf.d/cron.conf | 12 +++++ supervisor/conf.d/php.worker | 9 ++++ supervisor/init | 35 +++++++++++++++ supervisor/supervisord.conf | 25 +++++++++++ 11 files changed, 289 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/renovate.json create mode 100644 .github/workflows/docker-publish.yml create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 crontab create mode 100644 supervisor/conf.d/cron.conf create mode 100644 supervisor/conf.d/php.worker create mode 100644 supervisor/init create mode 100644 supervisor/supervisord.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5160ce4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +/Dockerfile +/LICENSE +/README.md +/.github diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..d431426 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base", + "docker:enableMajor", + "default:automergeDigest" + ], + "packageRules": [ + { + "matchDatasources": ["docker"], + "matchPackageNames": ["ubuntu"], + "matchUpdateTypes": ["minor", "patch", "pin", "digest"], + "automerge": true + } + ] + } diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..5f13420 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,67 @@ +name: Docker + +# This all came from github. I wrote none of it, but I did remove some bits that didn't work. + +on: + push: + branches: [ "main" ] + # Publish semver tags as releases. + tags: [ 'v*.*.*' ] + pull_request: + branches: [ "main" ] + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + # This is used to complete the identity challenge + # with sigstore/fulcio when running outside of PRs. + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + + # Workaround: https://github.com/docker/build-push-action/issues/461 + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v3 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d392188 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +# Ubuntu 22. Renovate keeps the sha up to date. +FROM ubuntu:jammy@sha256:2b7412e6465c3c7fc5bb21d3e6f1917c167358449fecac8176c6e496e5c1f05f + +# These can be changed, and the container runs usermod/groupmod to apply changes. +ENV PUID=99 +ENV PGID=100 +ENV TZ=America/New_York + +# The user matches swag, where the website runs the same code that we run in crontabs. +# software-properties-common and gpg-agent are needed to run apt-add-repository. +RUN DEBIAN_FRONTEND=noninteractive apt update \ + && groupadd --system --non-unique --gid ${PGID} abc \ + && useradd --system --non-unique --uid ${PUID} --gid ${PGID} \ + --no-create-home --home-dir / --shell /usr/sbin/nologin abc \ + && apt -y install --no-install-recommends \ + cron supervisor tzdata ca-certificates software-properties-common gpg-agent \ + && apt-add-repository ppa:ondrej/php \ + && echo "TZ=${TZ}" >> /etc/environment \ + && echo "${TZ}" > /etc/timezone \ + && ([ ! -f "/usr/share/zoneinfo/${TZ}" ] \ + || ln -sf "/usr/share/zoneinfo/${TZ}" /etc/localtime) + +# This is where we install our custom packages we use in our crontabs. +ARG PHPVERS=8.1 +ARG PHPMODS=cli,mysqli,curl,xml,memcached,mbstring +ARG PACKAGES=mysql-client,nginx,nano +RUN DEBIAN_FRONTEND=noninteractive apt update && /bin/bash -c \ + "apt install -y --no-install-recommends php${PHPVERS}-{${PHPMODS}} ${PACKAGES}" + +# Clean up a few things. The cron changes are important. +RUN DEBIAN_FRONTEND=noninteractive apt purge -y software-properties-common gpg-agent \ + && apt autoremove -y \ + && apt clean \ + && rm -rf /etc/cron.*/* + +LABEL org.opencontainers.image.source = "https://github.com/Notifiarr/dockwatch" + +COPY supervisor /etc/supervisor +COPY crontab /etc/crontab + +RUN chmod +x "/etc/supervisor/init" +RUN service nginx start + +ENTRYPOINT ["/etc/supervisor/init"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6906ae7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Notifiarr + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..113d7c9 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# dockwatch +Container to manage updates, health, etc for containers + +It also runs supervisor so you can drop in other tasks real easy. +An [example PHP worker](https://github.com/Notifiarr/cron-docker/blob/main/supervisor/conf.d/php.worker) is provided. + +# Use + +This thing fits our needs, but if you want to try it, feel free. + +### Image + +``` +docker pull ghcr.io/notifiarr/dockwatchr:main +``` + +### Example + +You must mount a folder at `/config/log` to capture log files. +The other two folders shown here are optional depending on what you want to do. +Put crons into `/config/cron` and put supervisor configs into `/config/supervisor`. + +``` +docker run -d \ + --name cron \ + -p '9999:80/tcp' \ + -l net.unraid.docker.webui='http://[IP]:[PORT:9999]' \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /host/logs:/config/log:rw \ + -v /host/cron.d:/config/cron:ro \ + -v /host/supervisor.d:/config/supervisor:ro \ + ghcr.io/notifiarr/dockwatch:main +``` + +### Configuration + +Available variables that control things in the container. Setting a username and +password is recommended. The password may be SHA1 encoded if it begins with the +string `{SHA}`. Read more [here](http://supervisord.org/configuration.html#inet-http-server-section-settings). + +You can use the `abc` user however you want. Set its user ID and group ID to +avoid perissions problems with your crontabs. + +| Variable | Default | Purpose | +| --------------- | ---------------- | ----------------------------------- | +| PUID | 99 | Controls the `abc` user UID | +| PGID | 100 | Controls the `abc` user GID | +| TZ | America/New_York | Sets the time zone in the container | +| SUPERVISOR_PORT | 9911 | Sets the XML RPC interface TCP port | +| SUPERVISOR_USER | `""` (empty) | Sets the XML RPC interface username | +| SUPERVISOR_PASS | `""` (empty) | Sets the XML RPC interface password | \ No newline at end of file diff --git a/crontab b/crontab new file mode 100644 index 0000000..9382ba9 --- /dev/null +++ b/crontab @@ -0,0 +1,5 @@ +#### This is the default /etc/crontab file installed into the container. +#### Not intended to be overwritten, but it can be if you'd really like to. + +# Periodically copy new files into cron.d that get added from outside the container. +*/5 * * * * root cp --no-preserve all -u /config/cron/* /etc/cron.d/ 2>/dev/null diff --git a/supervisor/conf.d/cron.conf b/supervisor/conf.d/cron.conf new file mode 100644 index 0000000..865f333 --- /dev/null +++ b/supervisor/conf.d/cron.conf @@ -0,0 +1,12 @@ +; This is the built-in supervisor configuraiton file to start and run crontab. +; ---------------------------------------------------------------------------- + +[program:cron] +user=root +autorestart=true +directory=/ +command=/usr/sbin/cron -f +redirect_stderr=true +; It does not log anything anyway, so do not make an empty file. +stdout_logfile=/dev/null +stdout_logfile_maxbytes=0 diff --git a/supervisor/conf.d/php.worker b/supervisor/conf.d/php.worker new file mode 100644 index 0000000..f846dd7 --- /dev/null +++ b/supervisor/conf.d/php.worker @@ -0,0 +1,9 @@ +; This exanmple file does not end with .conf so it is not included by supervisord. +[program:php] +user=%(ENV_PUID)s +numprocs_start=1 +numprocs=2 +process_name=php%(process_num)02d +command=/usr/bin/php -f /config/script.php +autorestart=true +redirect_stderr=true diff --git a/supervisor/init b/supervisor/init new file mode 100644 index 0000000..fe4e157 --- /dev/null +++ b/supervisor/init @@ -0,0 +1,35 @@ +#!/usr/bin/env dash + +# Custom Dockerfile init script for custom cron/supervisor container. +# Makes folders, copies files, sets UID/GID, applies time zone, starts supervisor. + +# If the /config directory is mounted, make sure it has a log directory. +[ ! -d "/config" ] || mkdir -p /config/log /config/supervisor /config/cron + +# Copy crontab files into container as root-owned. +rm -f /etc/cron.d/* 2>/dev/null +[ ! -d "/config/cron" ] || cp --no-preserve all -u /config/cron/* /etc/cron.d/ + +# Update abc user with provided PUID and PGID. +[ -z "$PUID" ] || /usr/sbin/usermod -o -u $PUID abc >/dev/null 2>&1 +[ -z "$PGID" ] || /usr/sbin/groupmod -o -g $PGID abc >/dev/null 2>&1 + +# Set a default PORT if one is not provided. +[ -n "$SUPERVISOR_PORT" ] || export SUPERVISOR_PORT=9911 + +# These need to be set so supervisor doesn't complain. +# Pass values in from Docker if you'd like. +# Password should begin with {SHA} and be SHA1 encoded. +[ -n "$SUPERVISOR_USER" ] || export SUPERVISOR_USER="" +[ -n "$SUPERVISOR_PASS" ] || export SUPERVISOR_PASS="" + +# Update the provided time zone in the global environment file. +# This allows cron to pass the time zone to apps it runs. +if [ -n "$TZ" ]; then + /usr/bin/sed -i'' /etc/environment -e "s#^TZ=.*#TZ=$TZ#g" + echo "$TZ" > /etc/timezone + [ ! -f /usr/share/zoneinfo/$TZ ] || ln -sf /usr/share/zoneinfo/$TZ /etc/localtime +fi + +# Start supervisor, which starts cron any other workers. +exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf diff --git a/supervisor/supervisord.conf b/supervisor/supervisord.conf new file mode 100644 index 0000000..af96d54 --- /dev/null +++ b/supervisor/supervisord.conf @@ -0,0 +1,25 @@ +[supervisord] +nodaemon = true +user = root +pidfile = /run/supervisord.pid +logfile = /config/log/supervisord.log +childlogdir = /config/log +silent = true +umask = 022 + +[supervisorctl] +serverurl = unix:///run/supervisord.sock + +[unix_http_server] +file = /run/supervisord.sock + +[inet_http_server] +port = 0.0.0.0:%(ENV_SUPERVISOR_PORT)s +username = %(ENV_SUPERVISOR_USER)s +password = %(ENV_SUPERVISOR_PASS)s + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[include] +files = /etc/supervisor/conf.d/*.conf /config/supervisor/*.conf