init
process¶To enable running multiple processes, containers require process/service management. This is normally provided by some kind of init
task (e.g. from sysvinit
).
There are Docker-compatible replacements for full-fledged init
's. Unfortunately they require either custom init scripts or service configurations (https://wiki.gentoo.org/wiki/Comparison_of_init_systems). The process of migration from OS-provided OpenRC init scripts is time consuming and error prone.
sysvinit
is hampered by following shortcomings:
init
as PID 1 ends with error code 137:CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b755c0f1b1d8 gentoo-base "/sbin/init" About a minute ago Exited (137) 9 seconds ago gentoo-base
shutdown
from within container, init
process remains running afterwards, keeping container in running state:# docker-compose top gentoo-base UID PID PPID C STIME TTY TIME CMD ---------------------------------------------------------- root 3510 3489 0 17:40 ? 00:00:00 init [0]
Nevertheless it is possible to use sysvinit
inside Docker container as an init
process. Required steps are following:
sysvinit
to exit init
process on hard shutdown (runlevel 0) with following patch¶--- sysvinit-3.01/src/init.c 2021-12-13 20:21:26.000000000 +0100
+++ sysvinit-3.01/src/init.c 2022-04-18 01:21:47.966751774 +0200
@@ -2367,6 +2367,11 @@
read_inittab();
fail_cancel();
setproctitle("init [%c]", (int)runlevel);
+
+ /*
+ * Exit on halt - causes Docker container to stop.
+ */
+ if (runlevel == '0') exit(0);
}
}
Write_Runlevel_Log(runlevel);
On Gentoo it's enough to put this patch inside /etc/portage/patches/sys-apps/sysvinit/exit-on-halt.patch and reemerge sysvinit
.
inittab
¶Container's docker-compose.yml:
services: gentoo-base: ... stop_signal: SIGINT
/etc/inittab inside container - replace reboot action with shutdown:
# What to do at the "Three Finger Salute". ca:12345:ctrlaltdel:/sbin/shutdown -h now
cd /var/www/localhost/htdocs/rubydocs git clone --branch v3_3_0 --depth 1 https://github.com/ruby/ruby.git sdoc --all --exclude='./test/*' --exclude='./spec/*' --main=ruby/README.md --output=ruby-3.3.0 ruby git clone --branch v7.1.2 --depth 1 https://github.com/rails/rails.git sdoc --all --exclude='./*/test/*' --main=rails/README.md --output=rails-7.1.2 rails sdoc-merge --op=ruby-3.3-rails-7.1 ruby-3.3.0 rails-7.1.2 rm -rf ruby/ ruby-3.3.0/ rails/ rails-7.1.2/
This is also available as Redmine HowTo
This is a solution in case you don't want to install additional plugins just to keep repository synchronised. It requires you to have Apache webserver with access to repository you are trying to sync. Apache has to support running CGI scripts.
Clone repository and make sure it is accessible by webserver:
mkdir /var/lib/redmine/repo chown apache /var/lib/redmine/repo su -u apache git -C /var/lib/redmine/repo clone https://github.com/username/repo_name.git
https://your.redmine.com/settings?tab=repositories
and:
Any script you run on your server will do. Below is an example of Bash script that pulls git repository and notifies Redmine to fetch changesets (substitute <repository-api-key>
with your own):
#!/bin/sh # Requires: jq REPO_PATH='/var/lib/redmine/repo' # Empty stdin, Apache issue https://bz.apache.org/bugzilla/show_bug.cgi?id=44782 REPO_NAME=$(cat <&0 | jq '.repository.name' | tr -cd 'A-Za-z0-9_-') if [ -z "${REPO_NAME}" ] || [ ! -d "${REPO_PATH}/${REPO_NAME}" ]; then echo "Status: 400 Bad Request" echo "Content-Type: text/plain; charset=utf-8" echo echo "project: unrecognized" exit 0 fi /usr/bin/git -C "${REPO_PATH}/${REPO_NAME}" pull -n -q result1=$? PROJECT_NAME=$(echo "${REPO_NAME}" | tr '_' '-') /usr/bin/curl --max-time 60 -s "https://your.redmine.com/sys/fetch_changesets?id=${PROJECT_NAME}&key=<repository-api-key>" >/dev/null result2=$? if [[ $result1 && $result2 ]]; then echo "Status: 200 OK" else echo "Status: 500 Internal Server Error" fi echo "Content-Type: text/plain; charset=utf-8" echo echo "project: ${PROJECT_NAME}" if [[ $result1 ]]; then echo "git pull: ok" else echo "git pull: failed" fi if [[ $result2 ]]; then echo "fetch changesets: ok" else echo "fetch changesets: failed" fi
Let's say you save this script under: /var/www/cgi-bin/update-repo.cgi
You can test if script executes properly:
echo <copy-input-from-github-webhook-request> | sudo -u apache /var/www/cgi-bin/update-repo.cgi
Inside VirtualHost
of your choice just add:
... # Github webhook for repository pull/update ScriptAlias /update-repo.cgi /var/www/cgi-bin/update-repo.cgi <Directory /var/www/cgi-bin/> Options ExecCGI AllowOverride None Require all granted </Directory> ...
In case you use the same VirtualHost
to proxy requests to your Redmine rails server
, you should exclude your special URL from being proxied with:
ProxyPass /update-repo.cgi !
https://your.virtualhost.com/update-repo.cgi
Update webhook and you're done.