Skip to content

Commit

Permalink
Replace docker client with wrapper
Browse files Browse the repository at this point in the history
The wrapper automatically runs on the host network
  • Loading branch information
efrecon committed Feb 5, 2024
1 parent 7ad84f9 commit 7b52b44
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM fedora:${FEDORA_VERSION}

ARG INSTALL_NAMESPACE=/opt/gh-runner-krunvm

COPY base/base.sh ${INSTALL_NAMESPACE}/bin/base.sh
COPY base/*.sh ${INSTALL_NAMESPACE}/bin/
RUN chmod a+x "${INSTALL_NAMESPACE}/bin/base.sh" \
&& "${INSTALL_NAMESPACE}/bin/base.sh" -dv -l /dev/stdout
COPY base/root/ /
53 changes: 53 additions & 0 deletions base/base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,29 @@
# Shell sanity. Stop on errors and undefined variables.
set -eu


# This is a readlink -f implementation so this script can (perhaps) run on MacOS
abspath() {
is_abspath() {
case "$1" in
/* | ~*) true;;
*) false;;
esac
}

if [ -d "$1" ]; then
( cd -P -- "$1" && pwd -P )
elif [ -L "$1" ]; then
if is_abspath "$(readlink "$1")"; then
abspath "$(readlink "$1")"
else
abspath "$(dirname "$1")/$(readlink "$1")"
fi
else
printf %s\\n "$(abspath "$(dirname "$1")")/$(basename "$1")"
fi
}

# Level of verbosity, the higher the more verbose. All messages are sent to the
# stderr.
BASE_VERBOSE=${BASE_VERBOSE:-0}
Expand All @@ -21,6 +44,11 @@ BASE_GID=${BASE_GID:-121}
# Name of the "sudo" group
BASE_SUDO=${BASE_SUDO:-"wheel"}

# Resolve the root directory hosting this script to an absolute path, symbolic
# links resolved.
BASE_ROOTDIR=$( cd -P -- "$(dirname -- "$(command -v -- "$(abspath "$0")")")" && pwd -P )
BASE_DOCKER_WRAPPER=${BASE_DOCKER_WRAPPER:-$BASE_ROOTDIR/docker.sh}

usage() {
# This uses the comments behind the options to show the help. Not extremly
# correct, but effective and simple.
Expand Down Expand Up @@ -64,6 +92,20 @@ verbose() { if [ "${BASE_VERBOSE:-0}" -ge "1" ]; then _log "$1" NFO; fi; }
warn() { _log "$1" WRN; }
error() { _log "$1" ERR && exit 1; }

# Find the executable passed as an argument in the PATH variable and print it.
find_exec() {
while IFS= read -r dir; do
if [ -n "${dir}" ] && [ -d "${dir}" ]; then
if [ -x "${dir%/}/$1" ] && [ "${dir%/}/$1" != "$(abspath "$0")" ]; then
printf %s\\n "${dir%/}/$1"
break
fi
fi
done <<EOF
$(printf %s\\n "$PATH"|tr ':' '\n')
EOF
}

# TODO: one of gosu or su-exec to drop privileges and run as the `runner` user
# TODO: locales?
verbose "Installing base packages"
Expand Down Expand Up @@ -91,6 +133,7 @@ dnf -y install \
python3-virtualenv \
python3 \
dumb-init \
procps \
nodejs \
rsync \
libpq-devel \
Expand All @@ -104,6 +147,16 @@ if [ "$BASE_DOCKER" = "1" ]; then
verbose "Installing docker"
dnf -y config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
dnf -y install docker-ce-cli

# Replace the real docker binary with our wrapper so we will be able to force
# running containers on the host network.
docker=$(find_exec docker)
if [ -z "${docker:-}" ]; then
error "No docker binary found in PATH"
fi
mv -f "$docker" "${docker}.orig"
verbose "Moved regular docker client to ${docker}.orig, installing wrapper from $BASE_DOCKER_WRAPPER instead"
mv -f "$BASE_DOCKER_WRAPPER" "$docker"
fi

verbose "Installing gh CLI"
Expand Down
181 changes: 181 additions & 0 deletions base/docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#!/bin/sh

# Shell sanity. Stop on errors and undefined variables.
set -eu

# This is a readlink -f implementation so this script can (perhaps) run on MacOS
abspath() {
is_abspath() {
case "$1" in
/* | ~*) true;;
*) false;;
esac
}

if [ -d "$1" ]; then
( cd -P -- "$1" && pwd -P )
elif [ -L "$1" ]; then
if is_abspath "$(readlink "$1")"; then
abspath "$(readlink "$1")"
else
abspath "$(dirname "$1")/$(readlink "$1")"
fi
else
printf %s\\n "$(abspath "$(dirname "$1")")/$(basename "$1")"
fi
}

# Find the executable passed as an argument in the PATH variable and print it.
find_exec() {
while IFS= read -r dir; do
if [ -n "${dir}" ] && [ -d "${dir}" ]; then
if [ -x "${dir%/}/$1" ] && [ "${dir%/}/$1" != "$(abspath "$0")" ]; then
printf %s\\n "${dir%/}/$1"
break
fi
fi
done <<EOF
$(printf %s\\n "$PATH"|tr ':' '\n')
EOF
}

# Look for the real docker client executable in the PATH variable. This will not
# work if there is a directory containing a line break in the PATH (but...
# why?!)
__DOCKER_DOCKER=$(find_exec docker.orig)
if [ -z "${__DOCKER_DOCKER:-}" ]; then
__DOCKER_DOCKER=$(find_exec docker)
if [ -z "${__DOCKER_DOCKER:-}" ]; then
printf %s\\n "No docker binary found in PATH" >&2
exit 1
fi
fi

# Parse the global options that the docker client understands.
while [ "$#" -gt 0 ]; do
case "$1" in
--config) # Path to the config file
__DOCKER_CONFIG="$2"; shift 2;;
--config=*) # Path to the config file
__DOCKER_CONFIG="${1#*=}"; shift 1;;

-c | --context) # Name of the context to use
__DOCKER_CONTEXT="$2"; shift 2;;
--context=*) # Name of the context to use
__DOCKER_CONTEXT="${1#*=}"; shift 1;;

-D | --debug) # Enable debug mode
__DOCKER_DEBUG=1; shift 1;;

-H | --host) # Daemon socket(s) to connect to
__DOCKER_HOST="$2"; shift 2;;
--host=*) # Daemon socket(s) to connect to
__DOCKER_HOST="${1#*=}"; shift 1;;

-l | --log-level) # Set the logging level
__DOCKER_LOG_LEVEL="$2"; shift 2;;
--log-level=*) # Set the logging level
__DOCKER_LOG_LEVEL="${1#*=}"; shift 1;;

--tls) # Use TLS; implied by --tlsverify
__DOCKER_TLS=1; shift 1;;

--tlscacert) # Trust certs signed only by this CA
__DOCKER_TLS_CA_CERT="$2"; shift 2;;
--tlscacert=*) # Trust certs signed only by this CA
__DOCKER_TLS_CA_CERT="${1#*=}"; shift 1;;

--tlscert) # Path to TLS certificate file
__DOCKER_TLS_CERT="$2"; shift 2;;
--tlscert=*) # Path to TLS certificate file
__DOCKER_TLS_CERT="${1#*=}"; shift 1;;

--tlskey) # Path to TLS key file
__DOCKER_TLS_KEY="$2"; shift 2;;
--tlskey=*) # Path to TLS key file
__DOCKER_TLS_KEY="${1#*=}"; shift 1;;

--tlsverify) # Use TLS and verify the remote
__DOCKER_TLS_VERIFY=1; shift 1;;

-v | --version) # Print version information and quit
__DOCKER_VERSION=1; shift 1;;
--)
shift; break;;
-*)
exec "$__DOCKER_DOCKER" "$@";;
*)
break;;
esac
done

# Nothing more? Show the help
if [ "$#" = 0 ]; then
exec "$__DOCKER_DOCKER" help
fi

# Run the docker client with the options we have parsed
run_docker() {
if [ -n "${__DOCKER_CONFIG:-}" ]; then
set -- --config "${__DOCKER_CONFIG}" "$@"
fi
if [ -n "${__DOCKER_CONTEXT:-}" ]; then
set -- --context "${__DOCKER_CONTEXT}" "$@"
fi
if [ "${__DOCKER_DEBUG:-0}" = 1 ]; then
set -- --debug "$@"
fi
if [ -n "${__DOCKER_HOST:-}" ]; then
set -- --host "${__DOCKER_HOST}" "$@"
fi
if [ -n "${__DOCKER_LOG_LEVEL:-}" ]; then
set -- --log-level "${__DOCKER_LOG_LEVEL}" "$@"
fi
if [ "${__DOCKER_TLS:-0}" = 1 ]; then
set -- --tls "$@"
fi
if [ -n "${__DOCKER_TLS_CA_CERT:-}" ]; then
set -- --tlscacert "${__DOCKER_TLS_CA_CERT}" "$@"
fi
if [ -n "${__DOCKER_TLS_CERT:-}" ]; then
set -- --tlscert "${__DOCKER_TLS_CERT}" "$@"
fi
if [ -n "${__DOCKER_TLS_KEY:-}" ]; then
set -- --tlskey "${__DOCKER_TLS_KEY}" "$@"
fi
if [ "${__DOCKER_TLS_VERIFY:-0}" = 1 ]; then
set -- --tlsverify "$@"
fi
if [ "${__DOCKER_VERSION:-0}" = 1 ]; then
set -- --version "$@"
fi
# Execute the docker client with the options we have parsed, in place.
exec "$__DOCKER_DOCKER" "$@"
}

# Pick the command (and perhaps sub command). When it is a container run
# command, automatically add --network host. Otherwise, just run as-is.
cmd=$1; shift
case "$cmd" in
container)
sub=$1; shift
case "$sub" in
run)
set -- "$cmd" "$sub" --network host "$@"
run_docker "$@"
;;
*)
set -- "$cmd" "$sub" "$@"
run_docker "$@"
;;
esac
;;
run)
set -- "$cmd" --network host "$@"
run_docker "$@"
;;
*)
set -- "$cmd" "$@"
run_docker "$@"
;;
esac

0 comments on commit 7b52b44

Please sign in to comment.