Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions gh-podman-in-podman/Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
FROM registry.access.redhat.com/ubi8/python-311

USER root

RUN dnf -y module enable container-tools:rhel8; dnf -y update; rpm --restore --quiet shadow-utils; \
dnf -y install crun podman netavark fuse-overlayfs openssh-clients /etc/containers/storage.conf \
curl git jq hostname procps findutils which openssl --exclude container-selinux; \
rm -rf /var/cache/* /var/log/dnf* /var/log/yum.*

ENV UID=1000
ENV GID=0
ENV USERNAME="runner"
ARG ANSIBLE_VERSION="2.15.0"

RUN useradd -m $USERNAME -u $UID
# This is to mimic the OpenShift behaviour of adding the dynamic user to group 0.
RUN usermod -G 0 $USERNAME
ENV HOME /home/${USERNAME}
WORKDIR /home/${USERNAME}

RUN chmod g+w /etc/passwd && \
touch /etc/sub{g,u}id && \
chmod -v ug+rw /etc/sub{g,u}id && \
echo -e "runner:1:999\nrunner:1001:64535" > /etc/subuid && \
echo -e "runner:1:999\nrunner:1001:64535" > /etc/subgid

COPY --chown=${USERNAME}:0 entrypoint.sh uid.sh register.sh get_github_app_token.sh ./

ADD containers.conf /etc/containers/containers.conf
ADD podman-containers.conf /home/runner/.config/containers/containers.conf

RUN mkdir -p /home/runner/.local/share/containers && \
chown runner:runner -R /home/runner && \
chmod 644 /etc/containers/containers.conf

ADD storage.conf /usr/share/containers/storage.conf
RUN sed -e 's|^#mount_program|mount_program|g' \
-e '/additionalimage.*/a "/var/lib/shared",' \
-e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' \
/usr/share/containers/storage.conf \
> /etc/containers/storage.conf

RUN printf '/run/secrets/etc-pki-entitlement:/run/secrets/etc-pki-entitlement\n/run/secrets/rhsm:/run/secrets/rhsm\n' > /etc/containers/mounts.conf

VOLUME /var/lib/containers
VOLUME /home/runner/.local/share/containers

RUN mkdir -p /var/lib/shared/overlay-images \
/var/lib/shared/overlay-layers \
/var/lib/shared/vfs-images \
/var/lib/shared/vfs-layers && \
touch /var/lib/shared/overlay-images/images.lock && \
touch /var/lib/shared/overlay-layers/layers.lock && \
touch /var/lib/shared/vfs-images/images.lock && \
touch /var/lib/shared/vfs-layers/layers.lock

ENV _CONTAINERS_USERNS_CONFIGURED=""

COPY --chown=${USERNAME}:0 get-runner-release.sh ./
RUN chmod ug+x ./get-runner-release.sh
RUN ./get-runner-release.sh
RUN ./bin/installdependencies.sh
RUN pip install --progress-bar off 'molecule>=24.2.0' 'molecule-plugins[docker]>=23.0.0' 'molecule-plugins[podman]' "ansible-core~=${ANSIBLE_VERSION}"

ENTRYPOINT ./entrypoint.sh

13 changes: 13 additions & 0 deletions gh-podman-in-podman/containers.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[containers]
netns="host"
userns="host"
ipcns="host"
utsns="host"
cgroupns="host"
cgroups="disabled"
log_driver = "k8s-file"
[engine]
cgroup_manager = "cgroupfs"
events_logger="file"
runtime="crun"

38 changes: 38 additions & 0 deletions gh-podman-in-podman/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/sh
# Based on https://github.com/bbrowning/github-runner/blob/master/entrypoint.sh

./uid.sh > /tmp/uid.sh.log

set -eE

CREDS_FILE="${PWD}/.credentials"

# Assume registration artifacts have been persisted from a previous start
# if no PAT or TOKEN is provided, and simply attempt to start.
if [ -n "${GITHUB_PAT:-}" ] || [ -n "${RUNNER_TOKEN:-}" ] || [ -n "${GITHUB_APP_ID:-}" ]; then
source ./register.sh
elif [ -e "${CREDS_FILE}" ]; then
echo "No GITHUB_PAT or RUNNER_TOKEN provided. Using existing credentials file ${CREDS_FILE}."
else
echo "No saved credentials found in ${CREDS_FILE}."
echo "Fatal: GITHUB_PAT or RUNNER_TOKEN must be set in the environment."
exit 1
fi

if [ -n "${GITHUB_PAT:-}" ]; then
trap 'remove; exit 130' INT
trap 'remove; exit 143' TERM
elif [ -n "${GITHUB_APP_ID:-}" ]; then
trap 'remove_github_app; exit 130' INT
trap 'remove_github_app; exit 143' TERM
else
trap 'exit 130' INT
trap 'exit 143' TERM
fi

set -x
./bin/runsvc.sh --once &
svc_pid=$!

wait $svc_pid

38 changes: 38 additions & 0 deletions gh-podman-in-podman/get-runner-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/sh

# Use the GitHub API to find the latest release of the GitHub Action runner,
# then download and extract the tarball for that release.

set -eE -o pipefail

release_file=/tmp/latest-runner-release.json
releases_api=https://api.github.com/repos/actions/runner/releases/latest

echo "Fetching latest release from $releases_api"

if [ ! $GITHUB_PAT = '' ]; then
# Set this to work around rate-limiting issues
echo "GITHUB_PAT is set; using for GitHub API"
auth_header="Authorization: token $GITHUB_PAT"
fi

curl -sSLf -H "$auth_header" -H 'Accept: application/json' -o $release_file $releases_api

latest_tag=$(jq -r '.tag_name' $release_file)
echo "Latest runner is ${latest_tag}"
echo $latest_tag >> ".RUNNER_VERSION"
rm $release_file

tag_without_v=$(echo $latest_tag | cut -c 2-)

os="linux" # could be "win" or "osx"
arch="x64" # for linux os, could be "arm" or "arm64"

runner_tar="actions-runner-${os}-${arch}-${tag_without_v}.tar.gz"
runner_url="https://github.com/actions/runner/releases/download/${latest_tag}/${runner_tar}"

set -x
curl -sSLf -O ${runner_url}
tar fxzp ${runner_tar}
rm ${runner_tar}

29 changes: 29 additions & 0 deletions gh-podman-in-podman/get_github_app_token.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/sh
# Adapted from https://stackoverflow.com/a/62646786 and
# Github's docs: https://docs.github.com/en/developers/apps/building-github-apps/authenticating-with-github-apps#authenticating-as-a-github-app

get_github_app_token() {
NOW=$( date +%s )
IAT=$((${NOW} - 60))
EXP=$((${NOW} + 540))
HEADER_RAW='{"alg":"RS256"}'
HEADER=$( echo -n "${HEADER_RAW}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
PAYLOAD_RAW='{"iat":'"${IAT}"',"exp":'"${EXP}"',"iss":'"${GITHUB_APP_ID}"'}'
PAYLOAD=$( echo -n "${PAYLOAD_RAW}" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
HEADER_PAYLOAD="${HEADER}"."${PAYLOAD}"

# Making a tmp directory here because /bin/sh doesn't support process redirection <()
tmp_dir=/tmp/github_app_tmp
mkdir "${tmp_dir}"
echo -n "${GITHUB_APP_PEM}" > "${tmp_dir}/github.pem"
echo -n "${HEADER_PAYLOAD}" > "${tmp_dir}/header"
SIGNATURE=$( openssl dgst -sha256 -sign "${tmp_dir}/github.pem" "${tmp_dir}/header" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n' )
rm -rf "${tmp_dir}"

JWT="${HEADER_PAYLOAD}"."${SIGNATURE}"
INSTALL_URL="https://${GITHUB_API_SERVER}/app/installations/${GITHUB_APP_INSTALL_ID}/access_tokens"
INSTALL_TOKEN_PAYLOAD=$(curl -sSfLX POST -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github.v3+json" "${INSTALL_URL}")
INSTALL_TOKEN=$(echo ${INSTALL_TOKEN_PAYLOAD} | jq .token --raw-output)

echo "${INSTALL_TOKEN}"
}
6 changes: 6 additions & 0 deletions gh-podman-in-podman/podman-containers.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[containers]
volumes = [
"/proc:/proc",
]
default_sysctls = []

121 changes: 121 additions & 0 deletions gh-podman-in-podman/register.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/bin/sh
# Based on https://github.com/bbrowning/github-runner/blob/master/entrypoint.sh

set -eE

# Load Github app authentication helper function
source ./get_github_app_token.sh

if [ -z "${GITHUB_OWNER:-}" ]; then
echo "Fatal: \$GITHUB_OWNER must be set in the environment"
exit 1
fi

if [ -z "${GITHUB_DOMAIN:-}" ]; then
echo "Connecting to public GitHub"
GITHUB_DOMAIN="github.com"
GITHUB_API_SERVER="api.github.com"
else
echo "Connecting to GitHub server at '$GITHUB_DOMAIN'"
GITHUB_API_SERVER="${GITHUB_DOMAIN}/api/v3"
fi

echo "GitHub API server is '$GITHUB_API_SERVER'"

if [ -z "${GITHUB_REPOSITORY:-}" ] && [ -n "${GITHUB_REPO:-}" ]; then
GITHUB_REPOSITORY=$GITHUB_REPO
fi

# https://docs.github.com/en/free-pro-team@latest/rest/reference/actions#create-a-registration-token-for-an-organization

registration_url="https://${GITHUB_DOMAIN}/${GITHUB_OWNER}${GITHUB_REPOSITORY:+/$GITHUB_REPOSITORY}"

if [ -z "${GITHUB_PAT:-}" ] && [ -z "${GITHUB_APP_ID:-}" ]; then
echo "Neither GITHUB_PAT nor the GITHUB_APP variables are set in the environment. Automatic runner removal will be disabled."
echo "Visit ${registration_url}/settings/actions/runners to manually force removal of runner."
fi

if [ -z "${RUNNER_TOKEN:-}" ]; then
if [ -z "${GITHUB_REPOSITORY:-}" ]; then
echo "Runner is scoped to organization '${GITHUB_OWNER}'"
echo "View runner status at https://${GITHUB_DOMAIN}/organizations/${GITHUB_OWNER}/settings/actions"

token_url="https://${GITHUB_API_SERVER}/orgs/${GITHUB_OWNER}/actions/runners/registration-token"
else
echo "Runner is scoped to repository '${GITHUB_OWNER}/${GITHUB_REPOSITORY}'"
echo "View runner status at https://${GITHUB_DOMAIN}/${GITHUB_OWNER}/${GITHUB_REPOSITORY}/settings/actions"

token_url="https://${GITHUB_API_SERVER}/repos/${GITHUB_OWNER}/${GITHUB_REPOSITORY}/actions/runners/registration-token"
fi
echo "Obtaining runner token from ${token_url}"

if [ -n "${GITHUB_APP_ID:-}" ] && [ -n "${GITHUB_APP_INSTALL_ID:-}" ] && [ -n "${GITHUB_APP_PEM:-}" ]; then
echo "GITHUB_APP environment variables are set. Using GitHub App authentication."
app_token=$(get_github_app_token)
payload=$(curl -sSfLX POST -H "Authorization: token ${app_token}" ${token_url})
else
echo "Using GITHUB_PAT for authentication."
payload=$(curl -sSfLX POST -H "Authorization: token ${GITHUB_PAT}" ${token_url})
fi

export RUNNER_TOKEN=$(echo $payload | jq .token --raw-output)
echo "Obtained registration token"
else
echo "Using RUNNER_TOKEN from environment"
fi

labels_arg=""
if [ -n "${RUNNER_LABELS:-}" ]; then
labels_arg="--labels $RUNNER_LABELS"
else
echo "No labels provided"
fi

runner_group_arg=""
# Runner groups are only valid for organization-wide runners
if [ -n "${RUNNER_GROUP:-}" ]; then
if [ -z "${GITHUB_REPOSITORY:-}" ]; then
runner_group_arg="--runnergroup $RUNNER_GROUP"
else
echo "Not applying runner group '${RUNNER_GROUP}' - Runner groups are not valid for repository-scoped runners."
fi
else
echo "No runner group provided"
fi

ephemeral_arg=""
if [ -n "${EPHEMERAL:-}" ]; then
ephemeral_arg="--ephemeral"
fi

if [ -n "${RUNNER_TOKEN:-}" ]; then
set -x
./config.sh \
--name $(hostname) \
--token ${RUNNER_TOKEN} \
--url ${registration_url} \
--work ${RUNNER_WORKDIR} \
${labels_arg} \
${runner_group_arg} \
${ephemeral_arg} \
--unattended \
--replace
set +x
fi

remove() {
payload=$(curl -sSfLX POST -H "Authorization: token ${GITHUB_PAT}" ${token_url%/registration-token}/remove-token)
export REMOVE_TOKEN=$(echo $payload | jq .token --raw-output)

./config.sh remove --unattended --token "${REMOVE_TOKEN}"
}

remove_github_app() {
app_token=$(get_github_app_token)
payload=$(curl -sSfLX POST -H "Authorization: token ${app_token}" ${token_url%/registration-token}/remove-token)
export REMOVE_TOKEN=$(echo $payload | jq .token --raw-output)

./config.sh remove --unattended --token "${REMOVE_TOKEN}"
}


12 changes: 12 additions & 0 deletions gh-podman-in-podman/runnner-2.16@.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[Unit]
Description=GitHub self-hosted runner %i
After=network.target

[Service]
ExecStart=podman run --name=runner-2.16-%i --replace --secret github_token --security-opt label=disable --security-opt seccomp=unconfined --device /dev/fuse:rw -v /var/lib/runner-2.16-%i:/var/lib/containers:Z --privileged -ti --rm -e GITHUB_OWNER=ansible-middleware -e RUNNER_LABELS='molecule-2.16,runner-1' -e RUNNER_ALLOW_RUNASROOT=1 -e EPHEMERAL=1 localhost/runner-3.11-2.16
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Loading