Skip to content

Commit

Permalink
Docker Build Again (#704)
Browse files Browse the repository at this point in the history
* Remove composer update hook to also run composer update in control site. 

* put back bin-tools so they are available in bin/ and fix path lookup, aligning with composer's new bin trick.

* Put back Ansible playbook run in docker build command so we can save images.

* Fix up docker-systemd-prepare file.

* Adding run-quiet script to main scripts.

* Run both devshop-install-prerequisites (to install ansible) AND docker-systemd-prepare to ensure fully functioning container.

* Default to ubuntu1804 when using docker/docker-compose.yml

* fix entry points, missing env vars in docker compose, build args, etc.

* Fix robo up and build.

* output more debugging info in GitHub actions.

* Get systems working right in GitHub actions and locally, by REMOVING the systems volume! ¯⁠\⁠_⁠(⁠ツ⁠)⁠_⁠/⁠¯

* thanks geerlingguy/docker-ubuntu2004-ansible#18 (comment)
  • Loading branch information
jonpugh authored Jan 20, 2023
0 parents commit fbf20fb
Show file tree
Hide file tree
Showing 2 changed files with 348 additions and 0 deletions.
116 changes: 116 additions & 0 deletions docker-systemd-entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/bin/env bash
set -e
#
# This script performs some magic to allow Docker container "Commands" to be run
# as a process other than 1 so that SystemD can be running in the background.
#
# Currently, if CMD runs successfully, the container stays running with SystemD.
# If CMD fails, it triggers the "shutdown" command to exit the container.
#
# The DOCKER_COMMAND is the actual Docker CMD used for this container image.
# $@ is every argument and option passed to the entrypoint (which is the same way CMD/ENTRPOINT work)
INIT_COMMAND=${INIT_COMMAND:-/lib/systemd/systemd}
DOCKER_COMMAND=${@:-$DEVSHOP_DOCKER_COMMAND_RUN}
DOCKER_COMMAND_POST=${DOCKER_COMMAND_POST:-"echo 'No DOCKER_COMMAND_POST variable set. Which should never happen, because it is in the Dockerfile. Probably means you are running this outside of a container.'"}
SYSTEM_STATUS_COMMAND=${SYSTEM_STATUS_COMMAND:-systemctl status --no-pager}
WELCOME_MESSAGE="Enjoy the DevShop Containers!"

DEVSHOP_PATH="$( cd "$(dirname "$0")"/.. ; pwd -P )"
PATH="$DEVSHOP_PATH/bin:$DEVSHOP_PATH/scripts:$PATH"
export PATH

devshop_logo() {
echo '
____ ____ _
| _ \ _____ __/ ___|| |__ ___ _ __
| | | |/ _ \ \ / /\___ \| _ \ / _ \| _ \
| |_| | __/\ V / ___) | | | | (_) | |_) |
|____/ \___| \_/ |____/|_| |_|\___/| .__/
http://getdevshop.com |_|'
if [ -z "$1" ]; then exit; fi

devshop_line
echo " $1 "
devshop_line
}

devshop_line() {
CHARACTER="${1:--}"
COLUMNS="$2"
printf '%*s\n' "${COLUMNS:-$(tput cols -T xterm)}" '' | tr ' ' $CHARACTER
}

devshop_logo "Starting /docker/bin/docker-systemd-entrypoint..."

echo "Hi! I'm docker-systemd-entrypoint."
echo "In a few seconds, I'm going to launch the Docker Command you specified as a new process."
echo "Then, I'm going to pass my process off to SystemD!"
echo "That way, you can specify any docker CMD but it will run inside a container with SystemD running properly."

devshop_line
echo "Environment Variables"

echo "INIT_COMMAND: $INIT_COMMAND"
echo "DOCKER_COMMAND: $DOCKER_COMMAND"
echo "DEVSHOP_DOCKER_COMMAND_RUN: $DEVSHOP_DOCKER_COMMAND_RUN"
echo "DOCKER_COMMAND_POST: $DOCKER_COMMAND_POST"
echo "SYSTEM_STATUS_COMMAND: $SYSTEM_STATUS_COMMAND"
echo "PATH: $PATH"

devshop_line
echo "Starting command chain..."

if [ ! -z "$DOCKER_COMMAND" ]; then
# This launches a group of commands in a new process:
# Sleep for 3 seconds, to allow INIT_COMMAND to launch.
# Run $DOCKER_COMMAND, and exit with it's exit code.
(( \
sleep ${INIT_COMMAND_WAIT:-3} && \
echo "System Status before running DOCKER_COMMAND: " && $SYSTEM_STATUS_COMMAND &&
echo "Running Docker Command '$DOCKER_COMMAND' ..." && $DOCKER_COMMAND &&
# If not successful, kill the container.
# If successful, run DEVSHOP_DOCKER_COMMAND_RUN and mention that system D continues.
echo "The DOCKER_COMMAND completed. (exit 0) Continuing on to DEVSHOP_DOCKER_COMMAND_RUN...." && \
echo "System Status after running DOCKER_COMMAND: " && $SYSTEM_STATUS_COMMAND && \
(
echo "Running DEVSHOP_DOCKER_COMMAND_RUN Command '$DEVSHOP_DOCKER_COMMAND_RUN' ..." && $DEVSHOP_DOCKER_COMMAND_RUN &&
echo "The DEVSHOP_DOCKER_COMMAND_RUN completed. (exit 0) Continuing on to DOCKER_COMMAND_POST..." && \
(
echo "Running DOCKER_COMMAND_POST Command '$DOCKER_COMMAND_POST' ..." && $DOCKER_COMMAND_POST &&
echo "The DOCKER_COMMAND_POST completed. (exit 0). The INIT_COMMAND continues on." ||
if [ -n "$DOCKER_COMMAND_RUN_POST_EXIT" ]; then
echo "The DOCKER_COMMAND_POST failed, and DOCKER_COMMAND_RUN_POST_EXIT was set. (exit $?) Triggering a shutdown to end INIT_COMMAND ..."
shutdown
else
echo "The DOCKER_COMMAND_POST failed. (exit $?) Continuing on. If you wish to exit on failure, set DOCKER_COMMAND_RUN_POST_EXIT=1"
fi
)
) || (
echo "The DEVSHOP_DOCKER_COMMAND_RUN failed. (exit $?) Continuing on. If you wish to exit on failure, run the command as the docker 'command' instead."
)
) || ( \
echo "The DOCKER_COMMAND failed. (exit $?) Triggering a shutdown to end INIT_COMMAND ..." && \
shutdown
)) &
DOCKER_COMMAND_PID=$!
echo "The Docker Command is about to start with PID $DOCKER_COMMAND_PID ..."

else
echo "There is no Docker command set. If you set one, it would run after INIT_COMMAND in a separate process."

# Let INIT COMMAND run, then wait 3 seconds, then show some messages and check system status.
( \
echo "Waiting 3 seconds for systemd to start..." &&
sleep ${INIT_COMMAND_WAIT:-5} && \
echo "System Status: " && $SYSTEM_STATUS_COMMAND && \
echo $WELCOME_MESSAGE \
) &

fi

# @TODO: Detect an unprivileged container or missing cgroup volume and inform the user.

echo "Running $INIT_COMMAND ..."
exec "$INIT_COMMAND"

232 changes: 232 additions & 0 deletions docker-systemd-prepare
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
#!/usr/bin/env bash
set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
PATH="$DIR:$PATH"

#
# docker-systemd-prepare
#
# This script prepares the operating system to run a full systemd setup inside a docker container.
#
# It was appropriated from Jeff Geerling's Dockerfiles:
#
# Ubuntu

# - https://github.com/geerlingguy/docker-ubuntu2004-ansible/blob/master/Dockerfile
# - https://github.com/geerlingguy/docker-ubuntu1804-ansible/blob/master/Dockerfile
# - https://github.com/geerlingguy/docker-ubuntu1604-ansible/blob/master/Dockerfile
#
# CentOS
# - https://github.com/geerlingguy/docker-centos7-ansible/blob/master/Dockerfile
# - https://github.com/geerlingguy/docker-centos8-ansible/blob/master/Dockerfile
#
# Each OS needs slightly different preparation. This script contains logic to work on any of the listed OS.
#

set -e

command_exists() {
command -v "$@" > /dev/null 2>&1
}

get_distribution() {
lsb_dist=""
# Every system that we officially support has /etc/os-release
if [ -r /etc/os-release ]; then
lsb_dist="$(. /etc/os-release && echo "$ID")"
fi
# Returning an empty string here should be alright since the
# case statements don't act unless you provide an actual value
echo "$lsb_dist"
}
# From https://github.com/geerlingguy/docker-ubuntu2004-ansible/blob/master/Dockerfile
prepare_ubuntu2004() {
PYTHON_DEFAULT=/usr/bin/python3
DEBIAN_FRONTEND=noninteractive

apt-get update \
&& apt-get install -y --no-install-recommends \
apt-utils \
build-essential \
locales \
libffi-dev \
libssl-dev \
libyaml-dev \
python3-dev \
python3-setuptools \
python3-pip \
python3-yaml \
software-properties-common \
rsyslog systemd systemd-cron sudo iproute2 \
curl git \
&& apt-get clean \
&& rm -Rf /var/lib/apt/lists/* \
&& rm -Rf /usr/share/doc && rm -Rf /usr/share/man

sed -i 's/^\($ModLoad imklog\)/#\1/' /etc/rsyslog.conf
locale-gen en_US.UTF-8

# Install the initctl faker script from @geerlingguy
initctl_faker_url="https://raw.githubusercontent.com/geerlingguy/docker-ubuntu2004-ansible/a7d1e71/initctl_faker"
initctl_faker_path="/sbin/initctl"

curl -ksSL $initctl_faker_url -o $initctl_faker_path
chmod +x $initctl_faker_path

rm -f /lib/systemd/system/systemd*udev* \
&& rm -f /lib/systemd/system/getty.target

}

prepare_ubuntu1804() {
apt-get update \
&& apt-get install -y --no-install-recommends \
apt-utils \
locales \
rsyslog \
systemd \
systemd-cron \
sudo \
iproute2 \
curl \
ca-certificates \
&& rm -Rf /var/lib/apt/lists/* \
&& rm -Rf /usr/share/doc && rm -Rf /usr/share/man \
&& apt-get clean

sed -i 's/^\($ModLoad imklog\)/#\1/' /etc/rsyslog.conf
locale-gen en_US.UTF-8

# Install the initctl faker script from @geerlingguy
initctl_faker_url="https://raw.githubusercontent.com/geerlingguy/docker-ubuntu1804-ansible/d75f3d7/initctl_faker"
initctl_faker_path="/sbin/initctl"

curl -ksSL $initctl_faker_url -o $initctl_faker_path
chmod +x $initctl_faker_path

# Remove unnecessary getty and udev targets that result in high CPU usage when using
# multiple containers with Molecule (https://github.com/ansible/molecule/issues/1104)
rm -f /lib/systemd/system/systemd*udev* \
&& rm -f /lib/systemd/system/getty.target

# Allow mysql to be installed?
# Error: https://github.com/opendevshop/devshop/pull/586/checks?check_run_id=675721197#step:4:484
# Proposed solution: https://stackoverflow.com/questions/24988947/install-mysql-in-docker-and-expose-mysql-service-to-outside
echo exit 0 > /usr/sbin/policy-rc.d
}

prepare_centos7() {
# Install systemd -- See https://hub.docker.com/_/centos/
yum -y update; yum clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;

# Install requirements.
yum makecache fast \
&& yum -y install deltarpm epel-release initscripts \
&& yum -y update \
&& yum -y install \
sudo \
which \
python-pip \
&& yum clean all

# Disable requiretty.
sed -i -e 's/^\(Defaults\s*requiretty\)/#--- \1/' /etc/sudoers

}

prepareAll() {
mkdir -p /etc/ansible
}

# perform some very rudimentary platform detection
lsb_dist=$( get_distribution )
lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"

case "$lsb_dist" in

ubuntu)
if command_exists lsb_release; then
dist_version="$(lsb_release --release | cut -f2)"
case "$dist_version" in
"14.04")
dist_version_name="trusty"
;;
"16.04")
dist_version_name="xenial"
;;
"18.04")
dist_version_name="bionic"
;;
"20.04")
dist_version_name="focal"
;;
esac
fi
if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
dist_version="$(. /etc/lsb-release && echo "$DISTRIB_RELEASE")"
dist_version_name="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")"
fi
;;

debian|raspbian)
dist_version="$(sed 's/\/.*//' /etc/debian_version | sed 's/\..*//')"
case "$dist_version" in
10)
dist_version_name="buster"
;;
9)
dist_version_name="stretch"
;;
8)
dist_version_name="jessie"
;;
esac
;;

centos)
if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
fi
;;

rhel|ol|sles)
ee_notice "$lsb_dist"
exit 1
;;

*)
if command_exists lsb_release; then
dist_version="$(lsb_release --release | cut -f2)"
fi
if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
fi
;;

esac

echo "OS Detected: $lsb_dist $dist_version ($dist_version_name)"

# Break out preparation into separate functions.
case "$lsb_dist $dist_version" in
"ubuntu 20.04")
prepare_ubuntu2004
;;
"ubuntu 18.04")
prepare_ubuntu1804
;;
"centos 7")
prepare_centos7
;;
esac

# Run OS-agnostic preparation scripts.
prepareAll

0 comments on commit fbf20fb

Please sign in to comment.