From db1f675e50a8c73cf166a2c5ff1a844fd78487f7 Mon Sep 17 00:00:00 2001 From: merith-xyz Date: Wed, 25 Sep 2024 09:46:06 -0700 Subject: [PATCH 01/29] basic entrypoint, automatic registration of runner works --- Dockerfile | 5 ++-- entrypoint.sh | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 6acc805..4c06f4b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,10 +38,11 @@ LABEL maintainer="contact@forgejo.org" \ ENV HOME=/data -USER 1000:1000 +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh WORKDIR /data VOLUME ["/data"] -CMD ["/bin/forgejo-runner"] +ENTRYPOINT ["/entrypoint.sh"] diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..4fd5ae8 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +set -e + +## Initial setup +if [[ ! -d /data ]]; then + mkdir -p /data +fi +cd /data + +if [[ -z "${RUNNER_FILE}" ]]; then + RUNNER_FILE="/data/.runner" +fi + +if [[ ! -f "${RUNNER_FILE}" ]]; then + touch "${RUNNER_FILE}" +fi + +if [[ -z "${CONFIG_FILE}" ]]; then + CONFIG_FILE="/data/config.yml" +fi +CONFIG_ARG="--config ${CONFIG_FILE}" + +if [[ ! -f "${CONFIG_FILE}" ]]; then + forgejo-runner generate-config > ${CONFIG_FILE} +fi + +EXTRA_ARGS="" +if [[ ! -z "${RUNNER_LABELS}" ]]; then + EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" +fi + +# For simplicity sake, I am not using the same ENV variable names as the original script + +if [[ -z "${RUNNER_FILE}" ]]; then + RUNNER_FILE=".runner" +fi +sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} + +if [[ ! -s "${RUNNER_FILE}" ]]; then + try=$((try + 1)) + success=0 + if [[ -z "${RUNNER_TOKEN}" ]]; then + echo "RUNNER_TOKEN is not set" + exit 1 + fi + + if [[ -z "${FORGEJO_URL}" ]]; then + echo "FORGEJO_URL is not set" + echo "Defaulting to http://forgejo:8080" + fi + + + # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, + # for the forgejo-runner to wait a moment for gitea to become available before erroring out. Within + # the context of a single docker-compose, something similar could be done via healthchecks, but + # this is more flexible. + while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do + forgejo-runner register \ + --instance "${FORGEJO_URL:-http://forgejo:8080}" \ + --token "${RUNNER_TOKEN}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log + + cat /tmp/reg.log | grep 'Runner registered successfully' >/dev/null + if [[ $? -eq 0 ]]; then + echo "SUCCESS" + success=1 + else + echo "Waiting to retry ..." + sleep 5 + fi + done +fi +# Prevent reading the token from the forgejo-runner process +unset RUNNER_TOKEN + +forgejo-runner daemon ${CONFIG_ARG} From 6308afc42e331a100176e8e0954b492f8d294086 Mon Sep 17 00:00:00 2001 From: Merith Date: Wed, 25 Sep 2024 13:00:54 -0700 Subject: [PATCH 02/29] address dockerfile feedback, further work on entrypoint --- Dockerfile | 3 +-- entrypoint.sh | 71 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4c06f4b..d371bdf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,8 +38,7 @@ LABEL maintainer="contact@forgejo.org" \ ENV HOME=/data -COPY entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh +COPY --chmod=555 entrypoint.sh /entrypoint.sh WORKDIR /data diff --git a/entrypoint.sh b/entrypoint.sh index 4fd5ae8..a11508c 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -8,36 +8,71 @@ if [[ ! -d /data ]]; then fi cd /data -if [[ -z "${RUNNER_FILE}" ]]; then - RUNNER_FILE="/data/.runner" -fi +RUNNER_USERID="${RUNNER_USERID:-1000}" -if [[ ! -f "${RUNNER_FILE}" ]]; then - touch "${RUNNER_FILE}" +## Setup User +if id "forgejo-runner" &>/dev/null; then + if [[ ! -z "${RUNNER_USERID}" ]]; then + echo "Changing UID of forgejo-runner to ${RUNNER_USERID}" + sed -i "s/^forgejo-runner:[^:]*:[^:]*:/forgejo-runner:x:${RUNNER_USERID}:/" /etc/passwd + fi +else + echo "Creating user forgejo-runner with UID ${RUNNER_USERID}" + adduser --uid "${RUNNER_USERID}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner fi +chown -R forgejo-runner:forgejo-runner /data +## Handle and alter the config file if [[ -z "${CONFIG_FILE}" ]]; then CONFIG_FILE="/data/config.yml" fi CONFIG_ARG="--config ${CONFIG_FILE}" +DOCKER_HOST=${DOCKER_HOST:-docker} +echo "DOCKER_HOST: ${DOCKER_HOST}" if [[ ! -f "${CONFIG_FILE}" ]]; then - forgejo-runner generate-config > ${CONFIG_FILE} + su -c "forgejo-runner generate-config > ${CONFIG_FILE}" forgejo-runner + + # Remove test environment variables if they exist in the config file + sed -i "/^ A_TEST_ENV_NAME_1:/d" ${CONFIG_FILE} + sed -i "/^ A_TEST_ENV_NAME_2:/d" ${CONFIG_FILE} + + # apply default values for docker + sed -i "/\"labels\":/c\ \"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} + + sed -i "/^ network:/c\ network: host" config.yml + sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} + sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" config.yml + sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} fi +if [[ ! -z "${ENV_FILE}" ]]; then + sed -i "/^ env_file:/c\ env_file: ${ENV_FILE}" ${CONFIG_FILE} +else + ENV_FILE="/data/.env" +fi +if [[ ! -f "${ENV_FILE}" ]]; then + echo "Creating ${ENV_FILE} and populating with default values" + cat < ${ENV_FILE} + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: /certs/client +EOF +fi + + EXTRA_ARGS="" if [[ ! -z "${RUNNER_LABELS}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" fi -# For simplicity sake, I am not using the same ENV variable names as the original script - +# Set the runner file if [[ -z "${RUNNER_FILE}" ]]; then - RUNNER_FILE=".runner" + RUNNER_FILE=".runner.json" # use json so editors know how to highlight fi sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} if [[ ! -s "${RUNNER_FILE}" ]]; then + touch ${RUNNER_FILE} try=$((try + 1)) success=0 if [[ -z "${RUNNER_TOKEN}" ]]; then @@ -45,22 +80,16 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then exit 1 fi - if [[ -z "${FORGEJO_URL}" ]]; then - echo "FORGEJO_URL is not set" - echo "Defaulting to http://forgejo:8080" - fi - - # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, # for the forgejo-runner to wait a moment for gitea to become available before erroring out. Within # the context of a single docker-compose, something similar could be done via healthchecks, but # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do - forgejo-runner register \ - --instance "${FORGEJO_URL:-http://forgejo:8080}" \ - --token "${RUNNER_TOKEN}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ - ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log + su -c "forgejo-runner register \ + --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ + --token \"${RUNNER_TOKEN}\" \ + --name \"${RUNNER_NAME:-$(hostname)}\" \ + ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log" forgejo-runner cat /tmp/reg.log | grep 'Runner registered successfully' >/dev/null if [[ $? -eq 0 ]]; then @@ -75,4 +104,4 @@ fi # Prevent reading the token from the forgejo-runner process unset RUNNER_TOKEN -forgejo-runner daemon ${CONFIG_ARG} +su -c "forgejo-runner daemon ${CONFIG_ARG}" forgejo-runner From a8066c365e8367164ecf1a6eb783e38becf96483 Mon Sep 17 00:00:00 2001 From: Merith Date: Wed, 25 Sep 2024 13:34:18 -0700 Subject: [PATCH 03/29] add a root-user check, clean up some formatting --- entrypoint.sh | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index a11508c..bed8152 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,7 +2,13 @@ set -e -## Initial setup +# Check if the script is run as root +if [ "$EUID" -ne 0 ]; then + echo "This script must be run as root" + exit 1 +fi + +# Initial setup if [[ ! -d /data ]]; then mkdir -p /data fi @@ -10,7 +16,7 @@ cd /data RUNNER_USERID="${RUNNER_USERID:-1000}" -## Setup User +# Setup User if id "forgejo-runner" &>/dev/null; then if [[ ! -z "${RUNNER_USERID}" ]]; then echo "Changing UID of forgejo-runner to ${RUNNER_USERID}" @@ -20,9 +26,11 @@ else echo "Creating user forgejo-runner with UID ${RUNNER_USERID}" adduser --uid "${RUNNER_USERID}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner fi + +# Ensure /data is owned by the runner user chown -R forgejo-runner:forgejo-runner /data -## Handle and alter the config file +# Handle and alter the config file if [[ -z "${CONFIG_FILE}" ]]; then CONFIG_FILE="/data/config.yml" fi @@ -37,12 +45,12 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then sed -i "/^ A_TEST_ENV_NAME_1:/d" ${CONFIG_FILE} sed -i "/^ A_TEST_ENV_NAME_2:/d" ${CONFIG_FILE} - # apply default values for docker + # Apply default values for docker sed -i "/\"labels\":/c\ \"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} - sed -i "/^ network:/c\ network: host" config.yml + sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" config.yml + sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} fi @@ -51,6 +59,7 @@ if [[ ! -z "${ENV_FILE}" ]]; then else ENV_FILE="/data/.env" fi + if [[ ! -f "${ENV_FILE}" ]]; then echo "Creating ${ENV_FILE} and populating with default values" cat < ${ENV_FILE} @@ -59,7 +68,6 @@ if [[ ! -f "${ENV_FILE}" ]]; then EOF fi - EXTRA_ARGS="" if [[ ! -z "${RUNNER_LABELS}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" @@ -101,6 +109,7 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then fi done fi + # Prevent reading the token from the forgejo-runner process unset RUNNER_TOKEN From 2b990ce2407cfd4dacc7b3e03f697ee599ce950d Mon Sep 17 00:00:00 2001 From: Merith Date: Wed, 25 Sep 2024 14:05:56 -0700 Subject: [PATCH 04/29] push example docker-compose for runner and forgejo --- entrypoint.sh | 1 + examples/docker-compose/.gitignore | 2 + .../compose-forgejo-and-runner.yml | 89 +++++++------------ 3 files changed, 36 insertions(+), 56 deletions(-) create mode 100644 examples/docker-compose/.gitignore diff --git a/entrypoint.sh b/entrypoint.sh index bed8152..c19b9cd 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -51,6 +51,7 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} + sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} fi diff --git a/examples/docker-compose/.gitignore b/examples/docker-compose/.gitignore new file mode 100644 index 0000000..294fcad --- /dev/null +++ b/examples/docker-compose/.gitignore @@ -0,0 +1,2 @@ +forgejo/ +forgejo-runner/ diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 4794985..c15c63d 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -11,18 +11,23 @@ # NOTE: a token obtained from the Forgejo web interface cannot be used # as a shared secret. # -# Replace {ROOT_PASSWORD} with a secure password +# Replace {RUNNER_TOKEN} with the token obtained from the Forgejo web interface. # +networks: + forgejo: + volumes: docker_certs: services: - docker-in-docker: image: code.forgejo.org/oci/docker:dind + container_name: docker # needed for docker internal DNS resolution hostname: docker # Must set hostname as TLS certificates are only valid for docker or localhost privileged: true + networks: + - forgejo environment: DOCKER_TLS_CERTDIR: /certs DOCKER_HOST: docker-in-docker @@ -31,63 +36,35 @@ services: forgejo: image: codeberg.org/forgejo/forgejo:1.21 - command: >- - bash -c ' - /bin/s6-svscan /etc/s6 & - sleep 10 ; - su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; - su -c "forgejo admin user create --admin --username root --password {ROOT_PASSWORD} --email root@example.com" git ; - sleep infinity - ' - environment: - FORGEJO__security__INSTALL_LOCK: "true" - FORGEJO__log__LEVEL: "debug" - FORGEJO__repository__ENABLE_PUSH_CREATE_USER: "true" - FORGEJO__repository__DEFAULT_PUSH_CREATE_PRIVATE: "false" - FORGEJO__repository__DEFAULT_REPO_UNITS: "repo.code,repo.actions" + container_name: forgejo + networks: + - forgejo volumes: - - /srv/forgejo-data:/data + - ./forgejo:/data ports: - 8080:3000 - runner-register: - image: code.forgejo.org/forgejo/runner:3.4.1 - links: - - docker-in-docker - - forgejo - environment: - DOCKER_HOST: tcp://docker-in-docker:2376 + forgejo-runner: + ## TODO: Update image to the the release + ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 + + # image: code.forgejo.org/forgejo/runner:3.4.1 + build: ../../ + container_name: forgejo-runner volumes: - - /srv/runner-data:/data - user: 0:0 - command: >- - bash -ec ' - while : ; do - forgejo-runner create-runner-file --connect --instance http://forgejo:3000 --name runner --secret {SHARED_SECRET} && break ; - sleep 1 ; - done ; - sed -i -e "s|\"labels\": null|\"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]|" .runner ; - forgejo-runner generate-config > config.yml ; - sed -i -e "s|network: .*|network: host|" config.yml ; - sed -i -e "s|^ envs:$$| envs:\n DOCKER_HOST: tcp://docker:2376\n DOCKER_TLS_VERIFY: 1\n DOCKER_CERT_PATH: /certs/client|" config.yml ; - sed -i -e "s|^ options:| options: -v /certs/client:/certs/client|" config.yml ; - sed -i -e "s| valid_volumes: \[\]$$| valid_volumes:\n - /certs/client|" config.yml ; - chown -R 1000:1000 /data - ' - - runner-daemon: - image: code.forgejo.org/forgejo/runner:3.4.1 - links: - - docker-in-docker - - forgejo - environment: - DOCKER_HOST: tcp://docker:2376 - DOCKER_CERT_PATH: /certs/client - DOCKER_TLS_VERIFY: "1" - volumes: - - /srv/runner-data:/data + - ./forgejo-runner:/data - docker_certs:/certs - command: >- - bash -c ' - while : ; do test -w .runner && forgejo-runner --config config.yml daemon ; sleep 1 ; done - ' + networks: + - forgejo + depends_on: + - docker-in-docker + - forgejo + environment: + CONFIG_FILE: config.yml # defaults to /data/config.yml + + FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 + + RUNNER_FILE: runner.json # defaults to /data/runner.json + RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration + RUNNER_TOKEN: "{RUNNER_TOKEN}" + RUNNER_USER: 1000 # defaults to 1000 From ba8fc919ec374ce968f21aef4142723d478bff75 Mon Sep 17 00:00:00 2001 From: Merith Date: Wed, 25 Sep 2024 15:21:53 -0700 Subject: [PATCH 05/29] update entrypoint and dockerfile, fix test workflow update dockerfile, rework entrypoint execution, update compose and test --- .forgejo/workflows/example-docker-compose.yml | 11 ++- Dockerfile.rootless | 6 ++ entrypoint.sh | 89 ++++++++++++------- .../compose-forgejo-and-runner.yml | 44 ++++++++- 4 files changed, 111 insertions(+), 39 deletions(-) create mode 100644 Dockerfile.rootless diff --git a/.forgejo/workflows/example-docker-compose.yml b/.forgejo/workflows/example-docker-compose.yml index 6e017db..1ce6b1f 100644 --- a/.forgejo/workflows/example-docker-compose.yml +++ b/.forgejo/workflows/example-docker-compose.yml @@ -36,8 +36,11 @@ jobs: # Launch Forgejo & the runner # $cli up -d - for delay in $(seq 60) ; do test -f /srv/runner-data/.runner && break ; sleep 30 ; done - test -f /srv/runner-data/.runner + for delay in $(seq 60) ; do + test -f ./forgejo-runner/runner.json && break + sleep 30 + done + test -f ./forgejo-runner/runner.json # # Run the demo workflow # @@ -53,11 +56,11 @@ jobs: grep --quiet "$success" /tmp/out && break grep --quiet "$failure" /tmp/out && break $cli ps --all - $cli logs --tail=20 runner-daemon demo-workflow + $cli logs --tail=20 forgejo-runner demo-workflow sleep 30 done grep --quiet "$success" /tmp/out - $cli logs runner-daemon > /tmp/runner.log + $cli logs forgejo-runner > /tmp/runner.log grep --quiet 'Start image=code.forgejo.org/oci/node:20-bookworm' /tmp/runner.log - name: full docker compose logs diff --git a/Dockerfile.rootless b/Dockerfile.rootless new file mode 100644 index 0000000..882be5c --- /dev/null +++ b/Dockerfile.rootless @@ -0,0 +1,6 @@ +FROM code.forgejo.org/forgejo/runner:3.4.1 + +USER 1000:1000 +## In Theory these can be removed on next release of the runner image +COPY --chown=forgejo-runner:forgejo-runner --chmod=555 ./entrypoint.sh /entrypoint +ENTRYPOINT [ "/entrypoint" ] \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index c19b9cd..c6145e9 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,11 +2,15 @@ set -e -# Check if the script is run as root -if [ "$EUID" -ne 0 ]; then - echo "This script must be run as root" - exit 1 -fi +run_command() { + local cmd="$1" + echo "Running $cmd as $(id -u)" + if [[ "$ISROOT" == true ]]; then + su -c "$cmd" forgejo-runner + else + eval "$cmd" + fi +} # Initial setup if [[ ! -d /data ]]; then @@ -16,38 +20,48 @@ cd /data RUNNER_USERID="${RUNNER_USERID:-1000}" -# Setup User -if id "forgejo-runner" &>/dev/null; then - if [[ ! -z "${RUNNER_USERID}" ]]; then - echo "Changing UID of forgejo-runner to ${RUNNER_USERID}" - sed -i "s/^forgejo-runner:[^:]*:[^:]*:/forgejo-runner:x:${RUNNER_USERID}:/" /etc/passwd - fi -else - echo "Creating user forgejo-runner with UID ${RUNNER_USERID}" - adduser --uid "${RUNNER_USERID}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner +# Check if the script is running as root +if [[ $(id -u) -eq 0 ]]; then + ISROOT=true fi -# Ensure /data is owned by the runner user -chown -R forgejo-runner:forgejo-runner /data +if [[ "$ISROOT" == true ]]; then + # Check if the forgejo-runner user exists + if id "forgejo-runner" &>/dev/null; then + echo "forgejo-runner user exists." + + # Change the user ID if needed + CURRENT_UID=$(id -u forgejo-runner) + if [[ "${CURRENT_UID}" -ne "${RUNNER_USERID}" ]]; then + echo "Changing UID of forgejo-runner to ${RUNNER_USERID}" + sed -i "s/^forgejo-runner:[^:]*:[^:]*:/forgejo-runner:x:${RUNNER_USERID}:/" /etc/passwd + fi + else + echo "Creating user forgejo-runner with UID ${RUNNER_USERID}" + adduser --uid "${RUNNER_USERID}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner + fi + + # Ensure /data is owned by the runner user + chown -R forgejo-runner:forgejo-runner /data +fi # Handle and alter the config file if [[ -z "${CONFIG_FILE}" ]]; then + echo "CONFIG_FILE is not set" CONFIG_FILE="/data/config.yml" fi CONFIG_ARG="--config ${CONFIG_FILE}" DOCKER_HOST=${DOCKER_HOST:-docker} -echo "DOCKER_HOST: ${DOCKER_HOST}" if [[ ! -f "${CONFIG_FILE}" ]]; then - su -c "forgejo-runner generate-config > ${CONFIG_FILE}" forgejo-runner + run_command "forgejo-runner generate-config > ${CONFIG_FILE}" forgejo-runner # Remove test environment variables if they exist in the config file sed -i "/^ A_TEST_ENV_NAME_1:/d" ${CONFIG_FILE} sed -i "/^ A_TEST_ENV_NAME_2:/d" ${CONFIG_FILE} # Apply default values for docker - sed -i "/\"labels\":/c\ \"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} - + sed -i "/^ labels:/c\ \"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} @@ -63,7 +77,7 @@ fi if [[ ! -f "${ENV_FILE}" ]]; then echo "Creating ${ENV_FILE} and populating with default values" - cat < ${ENV_FILE} + cat <${ENV_FILE} DOCKER_TLS_VERIFY: 1 DOCKER_CERT_PATH: /certs/client EOF @@ -76,7 +90,7 @@ fi # Set the runner file if [[ -z "${RUNNER_FILE}" ]]; then - RUNNER_FILE=".runner.json" # use json so editors know how to highlight + RUNNER_FILE=".runner.json" # use json so editors know how to highlight fi sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} @@ -84,9 +98,15 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then touch ${RUNNER_FILE} try=$((try + 1)) success=0 - if [[ -z "${RUNNER_TOKEN}" ]]; then - echo "RUNNER_TOKEN is not set" - exit 1 + + if [[ ! -z "${FORGEJO_SECRET}" ]]; then + EXTRA_ARGS="${EXTRA_ARGS} --secret ${FORGEJO_SECRET}" + else + if [[ -z "${RUNNER_TOKEN}" ]]; then + echo "RUNNER_TOKEN is not set" + exit 1 + fi + EXTRA_ARGS="${EXTRA_ARGS} --token ${RUNNER_TOKEN}" fi # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, @@ -94,13 +114,18 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then # the context of a single docker-compose, something similar could be done via healthchecks, but # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do - su -c "forgejo-runner register \ - --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ - --token \"${RUNNER_TOKEN}\" \ - --name \"${RUNNER_NAME:-$(hostname)}\" \ - ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log" forgejo-runner + # run_command "forgejo-runner register \ + # --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ + # --name \"${RUNNER_NAME:-$(hostname)}\" \ + # ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log" - cat /tmp/reg.log | grep 'Runner registered successfully' >/dev/null + run_command "forgejo-runner create-runner-file --connect \ + --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ + --name \"${RUNNER_NAME:-$(hostname)}\" \ + ${CONFIG_ARG} ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" + + + cat /tmp/reg.log | grep 'connection successful' >/dev/null if [[ $? -eq 0 ]]; then echo "SUCCESS" success=1 @@ -114,4 +139,4 @@ fi # Prevent reading the token from the forgejo-runner process unset RUNNER_TOKEN -su -c "forgejo-runner daemon ${CONFIG_ARG}" forgejo-runner +run_command "forgejo-runner daemon ${CONFIG_ARG}" diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index c15c63d..eb6006e 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -11,7 +11,7 @@ # NOTE: a token obtained from the Forgejo web interface cannot be used # as a shared secret. # -# Replace {RUNNER_TOKEN} with the token obtained from the Forgejo web interface. +# Replace ${RUNNER_TOKEN} with the token obtained from the Forgejo web interface. # networks: @@ -43,14 +43,24 @@ services: - ./forgejo:/data ports: - 8080:3000 + command: >- + bash -c ' + /bin/s6-svscan /etc/s6 & + sleep 10 ; + su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; + sleep infinity + ' forgejo-runner: ## TODO: Update image to the the release ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 # image: code.forgejo.org/forgejo/runner:3.4.1 - build: ../../ + build: + context: ../../ + dockerfile: Dockerfile container_name: forgejo-runner + # user: "1000" # set to run rootless, overrides RUNNER_USER volumes: - ./forgejo-runner:/data - docker_certs:/certs @@ -63,8 +73,36 @@ services: CONFIG_FILE: config.yml # defaults to /data/config.yml FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 + FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's RUNNER_FILE: runner.json # defaults to /data/runner.json RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration - RUNNER_TOKEN: "{RUNNER_TOKEN}" + RUNNER_TOKEN: "${RUNNER_TOKEN}" RUNNER_USER: 1000 # defaults to 1000 + + forgejo-runner-rootless: + ## TODO: Update image to the the release + ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 + + # image: code.forgejo.org/forgejo/runner:3.4.1 + build: + context: ../../ + dockerfile: Dockerfile.rootless + container_name: forgejo-runner-rootless + volumes: + - ./forgejo-runner:/data + - docker_certs:/certs + networks: + - forgejo + depends_on: + - docker-in-docker + - forgejo + environment: + CONFIG_FILE: config-rootless.yml # defaults to /data/config.yml + + FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 + FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's + + RUNNER_FILE: runner-rootless.json # defaults to /data/runner.json + RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration + RUNNER_TOKEN: "${RUNNER_TOKEN}" \ No newline at end of file From b13eec8fde7b2fde057f7593b7992b912ba19351 Mon Sep 17 00:00:00 2001 From: Merith Date: Wed, 25 Sep 2024 17:10:50 -0700 Subject: [PATCH 06/29] disabled TLS in example, not needed for a closed docker network --- entrypoint.sh | 26 +++++++++---------- .../compose-forgejo-and-runner.yml | 6 ++--- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index c6145e9..d1376c0 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -64,9 +64,14 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then sed -i "/^ labels:/c\ \"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} - sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} - sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} + + if [[ "${DOCKER_TLS_VERIFY}" -ne 1 ]]; then + sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2375" ${CONFIG_FILE} + else + sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} + sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} + sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} + fi fi if [[ ! -z "${ENV_FILE}" ]]; then @@ -76,11 +81,8 @@ else fi if [[ ! -f "${ENV_FILE}" ]]; then - echo "Creating ${ENV_FILE} and populating with default values" - cat <${ENV_FILE} - DOCKER_TLS_VERIFY: 1 - DOCKER_CERT_PATH: /certs/client -EOF + echo "Creating ${ENV_FILE}" + touch ${ENV_FILE} fi EXTRA_ARGS="" @@ -101,12 +103,14 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then if [[ ! -z "${FORGEJO_SECRET}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --secret ${FORGEJO_SECRET}" + echo "Registering with SECRET" else if [[ -z "${RUNNER_TOKEN}" ]]; then echo "RUNNER_TOKEN is not set" exit 1 fi EXTRA_ARGS="${EXTRA_ARGS} --token ${RUNNER_TOKEN}" + echo "Registering with TOKEN" fi # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, @@ -114,17 +118,11 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then # the context of a single docker-compose, something similar could be done via healthchecks, but # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do - # run_command "forgejo-runner register \ - # --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ - # --name \"${RUNNER_NAME:-$(hostname)}\" \ - # ${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log" - run_command "forgejo-runner create-runner-file --connect \ --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ --name \"${RUNNER_NAME:-$(hostname)}\" \ ${CONFIG_ARG} ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" - cat /tmp/reg.log | grep 'connection successful' >/dev/null if [[ $? -eq 0 ]]; then echo "SUCCESS" diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index eb6006e..e38e841 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -7,7 +7,7 @@ # openssl rand -hex 20 # # Replace all occurences of {SHARED_SECRET} below with the output. -# +# # NOTE: a token obtained from the Forgejo web interface cannot be used # as a shared secret. # @@ -29,7 +29,7 @@ services: networks: - forgejo environment: - DOCKER_TLS_CERTDIR: /certs + DOCKER_TLS_CERTDIR: "" # set to "certs" to use the TLS certificates, also update existing runner configs to use port 2376 DOCKER_HOST: docker-in-docker volumes: - docker_certs:/certs @@ -104,5 +104,5 @@ services: FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's RUNNER_FILE: runner-rootless.json # defaults to /data/runner.json - RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration + RUNNER_NAME: forgejo-runner-rootless # defaults to forgejo-runner, used for registration RUNNER_TOKEN: "${RUNNER_TOKEN}" \ No newline at end of file From 2cf2bdeb759891a0292070a4da05db0b85bf3f80 Mon Sep 17 00:00:00 2001 From: Merith Date: Thu, 26 Sep 2024 07:28:00 -0700 Subject: [PATCH 07/29] revert changes to workflow --- .forgejo/workflows/example-docker-compose.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.forgejo/workflows/example-docker-compose.yml b/.forgejo/workflows/example-docker-compose.yml index 1ce6b1f..c45fddb 100644 --- a/.forgejo/workflows/example-docker-compose.yml +++ b/.forgejo/workflows/example-docker-compose.yml @@ -36,11 +36,8 @@ jobs: # Launch Forgejo & the runner # $cli up -d - for delay in $(seq 60) ; do - test -f ./forgejo-runner/runner.json && break - sleep 30 - done - test -f ./forgejo-runner/runner.json + for delay in $(seq 60) ; do test -f /srv/runner-data/.runner && break ; sleep 30 ; done + test -f /srv/runner-data/.runner # # Run the demo workflow # @@ -56,15 +53,15 @@ jobs: grep --quiet "$success" /tmp/out && break grep --quiet "$failure" /tmp/out && break $cli ps --all - $cli logs --tail=20 forgejo-runner demo-workflow + $cli logs --tail=20 runner-daemon demo-workflow sleep 30 done grep --quiet "$success" /tmp/out - $cli logs forgejo-runner > /tmp/runner.log + $cli logs runner-daemon > /tmp/runner.log grep --quiet 'Start image=code.forgejo.org/oci/node:20-bookworm' /tmp/runner.log - name: full docker compose logs if: always() run: | cd examples/docker-compose - docker compose -f compose-forgejo-and-runner.yml -f compose-demo-workflow.yml logs + docker compose -f compose-forgejo-and-runner.yml -f compose-demo-workflow.yml logs \ No newline at end of file From 9252e5d66730f8e2fa336dd51d812d94f1b9545c Mon Sep 17 00:00:00 2001 From: Merith Date: Thu, 26 Sep 2024 15:08:31 -0700 Subject: [PATCH 08/29] remove rootless dockerfile, updatedate entrypoint, update docker compose Removed the rootless dockerfile as upon further investigation into how a `rootless` container works, the entrypoint that has been written fully accomodates that to reflect this the compose file has had the rootless config removed from it as it is no longer needed to test a seperate container image, added a debug echo function `decho` to the entrypoint, when `DEBUG=true` it will print "[entrypoint] message content" added a 10 second wait to the entrypoint to allow other services such as docker-in-docker and forgejo to finish launching before the runner is launched, this is bypassable by `SKIP_WAIT=true` applied several modifications requested by viceice, --- Dockerfile.rootless | 6 -- entrypoint.sh | 73 ++++++++++++++----- .../compose-forgejo-and-runner.yml | 70 +++++++----------- 3 files changed, 78 insertions(+), 71 deletions(-) delete mode 100644 Dockerfile.rootless diff --git a/Dockerfile.rootless b/Dockerfile.rootless deleted file mode 100644 index 882be5c..0000000 --- a/Dockerfile.rootless +++ /dev/null @@ -1,6 +0,0 @@ -FROM code.forgejo.org/forgejo/runner:3.4.1 - -USER 1000:1000 -## In Theory these can be removed on next release of the runner image -COPY --chown=forgejo-runner:forgejo-runner --chmod=555 ./entrypoint.sh /entrypoint -ENTRYPOINT [ "/entrypoint" ] \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index d1376c0..ed17b19 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,25 +4,32 @@ set -e run_command() { local cmd="$1" - echo "Running $cmd as $(id -u)" + redacted_cmd=$(echo "$cmd" | sed -E 's/(--secret\s+|--token\s+)[^ ]+/--\1[REDACTED]/g') + decho "Running command: $redacted_cmd" if [[ "$ISROOT" == true ]]; then + decho "Running as forgejo-runner" su -c "$cmd" forgejo-runner else + decho "Running as RUNNER_USER: ${RUNNER_USER}" eval "$cmd" fi } +decho() { + if [[ "${DEBUG}" == "true" ]]; then + echo "[entrypoint] $@" + fi +} + # Initial setup -if [[ ! -d /data ]]; then - mkdir -p /data -fi cd /data -RUNNER_USERID="${RUNNER_USERID:-1000}" - +decho "RUNNER_USER: ${RUNNER_USER}" +RUNNER_USER="${RUNNER_USER:-1000}" # Check if the script is running as root if [[ $(id -u) -eq 0 ]]; then ISROOT=true + decho "Running as root" fi if [[ "$ISROOT" == true ]]; then @@ -32,17 +39,21 @@ if [[ "$ISROOT" == true ]]; then # Change the user ID if needed CURRENT_UID=$(id -u forgejo-runner) - if [[ "${CURRENT_UID}" -ne "${RUNNER_USERID}" ]]; then - echo "Changing UID of forgejo-runner to ${RUNNER_USERID}" - sed -i "s/^forgejo-runner:[^:]*:[^:]*:/forgejo-runner:x:${RUNNER_USERID}:/" /etc/passwd + decho "CURRENT_UID: ${CURRENT_UID}" + if [[ "${CURRENT_UID}" -ne "${RUNNER_USER}" ]]; then + echo "Changing UID of forgejo-runner to ${RUNNER_USER}" + sed -i "s/^forgejo-runner:[^:]*:[^:]*:/forgejo-runner:x:${RUNNER_USER}:/" /etc/passwd fi else - echo "Creating user forgejo-runner with UID ${RUNNER_USERID}" - adduser --uid "${RUNNER_USERID}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner + echo "Creating user forgejo-runner with UID ${RUNNER_USER}" + adduser --uid "${RUNNER_USER}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner fi # Ensure /data is owned by the runner user - chown -R forgejo-runner:forgejo-runner /data + if [[ $(stat -c "%u" /data) != "${RUNNER_USER}" ]]; then + decho "Changing ownership of /data to ${RUNNER_USER}" + chown -R forgejo-runner:forgejo-runner /data + fi fi # Handle and alter the config file @@ -51,9 +62,16 @@ if [[ -z "${CONFIG_FILE}" ]]; then CONFIG_FILE="/data/config.yml" fi CONFIG_ARG="--config ${CONFIG_FILE}" +decho "CONFIG: ${CONFIG_ARG}" DOCKER_HOST=${DOCKER_HOST:-docker} +DOCKER_TLS_CERTDIR=${DOCKER_TLS_CERTDIR:-"/certs/client"} +DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-0} +decho "DOCKER_HOST: ${DOCKER_HOST}" +decho "DOCKER_TLS_CERTDIR: ${DOCKER_TLS_CERTDIR}" +decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" if [[ ! -f "${CONFIG_FILE}" ]]; then + echo "Creating ${CONFIG_FILE}" run_command "forgejo-runner generate-config > ${CONFIG_FILE}" forgejo-runner # Remove test environment variables if they exist in the config file @@ -65,41 +83,53 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} + if [[ "${DOCKER_TLS_VERIFY}" -ne 1 ]]; then + decho "Docker TLS diabled" sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2375" ${CONFIG_FILE} else + decho "Docker TLS enabled" sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} - sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} + sed -i "/^ valid_volumes:/c\ valid_volumes:\n - ${DOCKER_TLS_CERTDIR}" ${CONFIG_FILE} + sed -i "/^ options:/c\ options: -v ${DOCKER_TLS_CERTDIR}:${DOCKER_TLS_CERTDIR}" ${CONFIG_FILE} fi fi -if [[ ! -z "${ENV_FILE}" ]]; then - sed -i "/^ env_file:/c\ env_file: ${ENV_FILE}" ${CONFIG_FILE} -else - ENV_FILE="/data/.env" -fi +ENV_FILE=${ENV_FILE:-"/data/.env"} +decho "ENV_FILE: ${ENV_FILE}" +sed -i "/^ env_file:/c\ env_file: ${ENV_FILE}" ${CONFIG_FILE} if [[ ! -f "${ENV_FILE}" ]]; then echo "Creating ${ENV_FILE}" touch ${ENV_FILE} + echo "DOCKER_HOST=${DOCKER_HOST}" >> ${ENV_FILE} + echo "DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY}" >> ${ENV_FILE} + echo "DOCKER_TLS_CERTDIR=${DOCKER_TLS_CERTDIR}" >> ${ENV_FILE} fi EXTRA_ARGS="" if [[ ! -z "${RUNNER_LABELS}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" fi +decho "EXTRA_ARGS: ${EXTRA_ARGS}" # Set the runner file if [[ -z "${RUNNER_FILE}" ]]; then - RUNNER_FILE=".runner.json" # use json so editors know how to highlight + RUNNER_FILE="runner.json" # use json so editors know how to highlight fi +decho "RUNNER_FILE: ${RUNNER_FILE}" sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} +if [[ "${SKIP_WAIT}" != "true" ]]; then + secho "Waiting 10s to allow other services to start up..." + sleep 10 +fi + if [[ ! -s "${RUNNER_FILE}" ]]; then touch ${RUNNER_FILE} try=$((try + 1)) success=0 + decho "try: ${try}, success: ${success}" if [[ ! -z "${FORGEJO_SECRET}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --secret ${FORGEJO_SECRET}" @@ -112,6 +142,7 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --token ${RUNNER_TOKEN}" echo "Registering with TOKEN" fi + decho "EXTRA_ARGS after secret/token: ${EXTRA_ARGS}" # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, # for the forgejo-runner to wait a moment for gitea to become available before erroring out. Within @@ -131,10 +162,12 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then echo "Waiting to retry ..." sleep 5 fi + decho "try: ${try}, success: ${success}" done fi # Prevent reading the token from the forgejo-runner process unset RUNNER_TOKEN +unset FORGEJO_SECRET run_command "forgejo-runner daemon ${CONFIG_ARG}" diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index e38e841..e644a4f 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -7,7 +7,7 @@ # openssl rand -hex 20 # # Replace all occurences of {SHARED_SECRET} below with the output. -# +# # NOTE: a token obtained from the Forgejo web interface cannot be used # as a shared secret. # @@ -23,20 +23,19 @@ volumes: services: docker-in-docker: image: code.forgejo.org/oci/docker:dind - container_name: docker # needed for docker internal DNS resolution - hostname: docker # Must set hostname as TLS certificates are only valid for docker or localhost + # container_name: docker # Must set container_name to docker for both internal DNS and TLS to work + hostname: docker privileged: true networks: - forgejo environment: - DOCKER_TLS_CERTDIR: "" # set to "certs" to use the TLS certificates, also update existing runner configs to use port 2376 - DOCKER_HOST: docker-in-docker + DOCKER_TLS_CERTDIR: "/certs" # set to "" to disable the use of TLS, also manually update existing runner configs to use port 2375 volumes: - docker_certs:/certs forgejo: image: codeberg.org/forgejo/forgejo:1.21 - container_name: forgejo + hostname: forgejo networks: - forgejo volumes: @@ -47,20 +46,21 @@ services: bash -c ' /bin/s6-svscan /etc/s6 & sleep 10 ; + su -c "forgejo admin user create --admin --username root --password examplepassword --email root@example.com" git ; su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; sleep infinity ' + # all values that have defaults listed are optional + # only FORGEJO_SECRET or RUNNER_TOKEN is required + # FORGEJO_URL is required if forgejo is in this compose file or docker network forgejo-runner: ## TODO: Update image to the the release ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 - - # image: code.forgejo.org/forgejo/runner:3.4.1 - build: - context: ../../ - dockerfile: Dockerfile - container_name: forgejo-runner - # user: "1000" # set to run rootless, overrides RUNNER_USER + + # image: code.forgejo.org/forgejo/runner:3.4.1 + build: ../../ + # user: "1000" # set to run rootless, overrides RUNNER_USER and disables automatic file ownership volumes: - ./forgejo-runner:/data - docker_certs:/certs @@ -70,39 +70,19 @@ services: - docker-in-docker - forgejo environment: - CONFIG_FILE: config.yml # defaults to /data/config.yml + CONFIG_FILE: config.yml # defaults to /data/config.yml - FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 - FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's + DOCKER_HOST: "docker" # defaults to docker + DOCKER_TLS_CERTDIR: "/certs/client" # defaults to /certs/client + DOCKER_TLS_VERIFY: "1" # defaults to 0, set to 1 to enable TLS - RUNNER_FILE: runner.json # defaults to /data/runner.json - RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration + FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 + FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN + + RUNNER_FILE: .runner # defaults to /data/runner.json + RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration RUNNER_TOKEN: "${RUNNER_TOKEN}" - RUNNER_USER: 1000 # defaults to 1000 + RUNNER_USER: 1000 # defaults to 1000, allows for automatic file ownership - forgejo-runner-rootless: - ## TODO: Update image to the the release - ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 - - # image: code.forgejo.org/forgejo/runner:3.4.1 - build: - context: ../../ - dockerfile: Dockerfile.rootless - container_name: forgejo-runner-rootless - volumes: - - ./forgejo-runner:/data - - docker_certs:/certs - networks: - - forgejo - depends_on: - - docker-in-docker - - forgejo - environment: - CONFIG_FILE: config-rootless.yml # defaults to /data/config.yml - - FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 - FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's - - RUNNER_FILE: runner-rootless.json # defaults to /data/runner.json - RUNNER_NAME: forgejo-runner-rootless # defaults to forgejo-runner, used for registration - RUNNER_TOKEN: "${RUNNER_TOKEN}" \ No newline at end of file + DEBUG: "true" # defaults to false, set to true to enable debug logging + SKIP_WAIT: "false" # defaults to false, set to true to skip the 10 second wait to allow for forgejo and docker-in-docker to start From 485cde556867508970c18ef77bcf045786831b9b Mon Sep 17 00:00:00 2001 From: merith-xyz Date: Thu, 26 Sep 2024 15:16:51 -0700 Subject: [PATCH 09/29] echo, not secho --- entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entrypoint.sh b/entrypoint.sh index ed17b19..60622c4 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -121,7 +121,7 @@ decho "RUNNER_FILE: ${RUNNER_FILE}" sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} if [[ "${SKIP_WAIT}" != "true" ]]; then - secho "Waiting 10s to allow other services to start up..." + echo "Waiting 10s to allow other services to start up..." sleep 10 fi From b165aeab81a35fa17dddd4d404a27ca61175acdd Mon Sep 17 00:00:00 2001 From: merith-xyz Date: Thu, 26 Sep 2024 19:00:54 -0700 Subject: [PATCH 10/29] I guess it works now sorry for the unprofessional commit message, I have been working on this effectively non-stop since the previous commit, and have been fighting docker networking being inconsistent as well as filepermisson issues, end me --- entrypoint.sh | 109 ++++++++++-------- .../compose-forgejo-and-runner.yml | 19 +-- 2 files changed, 74 insertions(+), 54 deletions(-) mode change 100644 => 100755 entrypoint.sh diff --git a/entrypoint.sh b/entrypoint.sh old mode 100644 new mode 100755 index 60622c4..bb72004 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,17 +4,28 @@ set -e run_command() { local cmd="$1" - redacted_cmd=$(echo "$cmd" | sed -E 's/(--secret\s+|--token\s+)[^ ]+/--\1[REDACTED]/g') - decho "Running command: $redacted_cmd" + + # Replace any --token or --secret with [REDACTED] + local safe_cmd=$(echo "$cmd" | sed -E 's/--(token|secret) [^ ]+/--\1 [REDACTED]/g') + + decho "Running command: $safe_cmd" + if [[ "$ISROOT" == true ]]; then decho "Running as forgejo-runner" su -c "$cmd" forgejo-runner else - decho "Running as RUNNER_USER: ${RUNNER_USER}" + decho "Running as $(whoami)" eval "$cmd" fi } +makeUser() { + adduser -u ${RUNNER_USER} -h /data -s /bin/bash -D forgejo-runner +} +makeGroup() { + addgroup -g ${RUNNER_USER} forgejo-runner +} + decho() { if [[ "${DEBUG}" == "true" ]]; then echo "[entrypoint] $@" @@ -33,27 +44,37 @@ if [[ $(id -u) -eq 0 ]]; then fi if [[ "$ISROOT" == true ]]; then - # Check if the forgejo-runner user exists - if id "forgejo-runner" &>/dev/null; then - echo "forgejo-runner user exists." - - # Change the user ID if needed - CURRENT_UID=$(id -u forgejo-runner) - decho "CURRENT_UID: ${CURRENT_UID}" - if [[ "${CURRENT_UID}" -ne "${RUNNER_USER}" ]]; then - echo "Changing UID of forgejo-runner to ${RUNNER_USER}" - sed -i "s/^forgejo-runner:[^:]*:[^:]*:/forgejo-runner:x:${RUNNER_USER}:/" /etc/passwd - fi + # Check if the forgejo-runner user exists, if not, create it + if ! id -u forgejo-runner >/dev/null 2>&1; then + decho "Creating user forgejo-runner with UID ${RUNNER_USER}" + makeUser else - echo "Creating user forgejo-runner with UID ${RUNNER_USER}" - adduser --uid "${RUNNER_USER}" --home /home/forgejo-runner --disabled-password --gecos "" forgejo-runner + CURRENT_UID=$(id -u forgejo-runner) + if [[ "${CURRENT_UID}" -ne "${RUNNER_USER}" ]]; then + decho "Changing UID of forgejo-runner from ${CURRENT_UID} to ${RUNNER_USER}" + deluser forgejo-runner + makeUser + fi + fi + + # Check if the forgejo-runner group exists, if not, create it + if ! getent group forgejo-runner >/dev/null 2>&1; then + decho "Creating group forgejo-runner with GID ${RUNNER_USER}" + makeGroup + else + CURRENT_GID=$(getent group forgejo-runner | cut -d: -f3) + if [[ "${CURRENT_GID}" -ne "${RUNNER_USER}" ]]; then + decho "Changing GID of forgejo-runner from ${CURRENT_GID} to ${RUNNER_USER}" + delgroup forgejo-runner + makeGroup + fi fi # Ensure /data is owned by the runner user - if [[ $(stat -c "%u" /data) != "${RUNNER_USER}" ]]; then - decho "Changing ownership of /data to ${RUNNER_USER}" - chown -R forgejo-runner:forgejo-runner /data - fi + # yes this can slow things down but is 100% nessecary for the runner to function + # when running as a root user, because for some reason the runner create files as + # root and then cant access them + chown -R forgejo-runner:forgejo-runner /data fi # Handle and alter the config file @@ -65,33 +86,33 @@ CONFIG_ARG="--config ${CONFIG_FILE}" decho "CONFIG: ${CONFIG_ARG}" DOCKER_HOST=${DOCKER_HOST:-docker} -DOCKER_TLS_CERTDIR=${DOCKER_TLS_CERTDIR:-"/certs/client"} +DOCKER_CERT_PATH=${DOCKER_CERT_PATH:-"/certs/client"} DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-0} decho "DOCKER_HOST: ${DOCKER_HOST}" -decho "DOCKER_TLS_CERTDIR: ${DOCKER_TLS_CERTDIR}" +decho "DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" if [[ ! -f "${CONFIG_FILE}" ]]; then echo "Creating ${CONFIG_FILE}" - run_command "forgejo-runner generate-config > ${CONFIG_FILE}" forgejo-runner + run_command "forgejo-runner generate-config > ${CONFIG_FILE}" # Remove test environment variables if they exist in the config file sed -i "/^ A_TEST_ENV_NAME_1:/d" ${CONFIG_FILE} sed -i "/^ A_TEST_ENV_NAME_2:/d" ${CONFIG_FILE} # Apply default values for docker - sed -i "/^ labels:/c\ \"labels\": [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} + sed -i "/^ labels:/c\ labels: [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} if [[ "${DOCKER_TLS_VERIFY}" -ne 1 ]]; then decho "Docker TLS diabled" - sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2375" ${CONFIG_FILE} + sed -i "/^ docker_host:/c\ docker_host: ${DOCKER_HOST}" ${CONFIG_FILE} else decho "Docker TLS enabled" - sed -i "/^ docker_host:/c\ docker_host: tcp://${DOCKER_HOST}:2376" ${CONFIG_FILE} - sed -i "/^ valid_volumes:/c\ valid_volumes:\n - ${DOCKER_TLS_CERTDIR}" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v ${DOCKER_TLS_CERTDIR}:${DOCKER_TLS_CERTDIR}" ${CONFIG_FILE} + sed -i "/^ docker_host:/c\ docker_host: ${DOCKER_HOST}" ${CONFIG_FILE} + sed -i "/^ valid_volumes:/c\ valid_volumes:\n - ${DOCKER_CERT_PATH}" ${CONFIG_FILE} + sed -i "/^ options:/c\ options: -v ${DOCKER_CERT_PATH}:${DOCKER_CERT_PATH}" ${CONFIG_FILE} fi fi @@ -104,7 +125,7 @@ if [[ ! -f "${ENV_FILE}" ]]; then touch ${ENV_FILE} echo "DOCKER_HOST=${DOCKER_HOST}" >> ${ENV_FILE} echo "DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY}" >> ${ENV_FILE} - echo "DOCKER_TLS_CERTDIR=${DOCKER_TLS_CERTDIR}" >> ${ENV_FILE} + echo "DOCKER_CERT_PATH=${DOCKER_CERT_PATH}" >> ${ENV_FILE} fi EXTRA_ARGS="" @@ -131,30 +152,28 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then success=0 decho "try: ${try}, success: ${success}" - if [[ ! -z "${FORGEJO_SECRET}" ]]; then - EXTRA_ARGS="${EXTRA_ARGS} --secret ${FORGEJO_SECRET}" - echo "Registering with SECRET" - else - if [[ -z "${RUNNER_TOKEN}" ]]; then - echo "RUNNER_TOKEN is not set" - exit 1 - fi - EXTRA_ARGS="${EXTRA_ARGS} --token ${RUNNER_TOKEN}" - echo "Registering with TOKEN" - fi - decho "EXTRA_ARGS after secret/token: ${EXTRA_ARGS}" - # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, # for the forgejo-runner to wait a moment for gitea to become available before erroring out. Within # the context of a single docker-compose, something similar could be done via healthchecks, but # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do + if [[ ! -z "${FORGEJO_SECRET}" ]]; then run_command "forgejo-runner create-runner-file --connect \ --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ --name \"${RUNNER_NAME:-$(hostname)}\" \ - ${CONFIG_ARG} ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" - - cat /tmp/reg.log | grep 'connection successful' >/dev/null + --secret \"${FORGEJO_SECRET}\" \ + ${CONFIG_ARG}\ + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" + else + run_command "forgejo-runner register \ + --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ + --name \"${RUNNER_NAME:-$(hostname)}\" \ + --token \"${RUNNER_TOKEN}\" \ + --no-interactive \ + ${CONFIG_ARG}\ + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" + fi + cat /tmp/reg.log | grep -E 'connection successful|registered successfully' >/dev/null if [[ $? -eq 0 ]]; then echo "SUCCESS" success=1 diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index e644a4f..a2d1fa5 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -23,13 +23,13 @@ volumes: services: docker-in-docker: image: code.forgejo.org/oci/docker:dind - # container_name: docker # Must set container_name to docker for both internal DNS and TLS to work - hostname: docker + hostname: docker # Must set hostname for both internal DNS and TLS to work as certs are only valid for docker and localhost privileged: true networks: - forgejo environment: DOCKER_TLS_CERTDIR: "/certs" # set to "" to disable the use of TLS, also manually update existing runner configs to use port 2375 + DOCKER_HOST: "docker" # remove aswell to disable TLS volumes: - docker_certs:/certs @@ -39,7 +39,7 @@ services: networks: - forgejo volumes: - - ./forgejo:/data + - /srv/forgejo-data:/data ports: - 8080:3000 command: >- @@ -54,15 +54,16 @@ services: # all values that have defaults listed are optional # only FORGEJO_SECRET or RUNNER_TOKEN is required # FORGEJO_URL is required if forgejo is in this compose file or docker network - forgejo-runner: + runner-daemon: ## TODO: Update image to the the release ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 # image: code.forgejo.org/forgejo/runner:3.4.1 build: ../../ # user: "1000" # set to run rootless, overrides RUNNER_USER and disables automatic file ownership + restart: unless-stopped # needed for fixing file ownership on restart volumes: - - ./forgejo-runner:/data + - /srv/runner-data:/data - docker_certs:/certs networks: - forgejo @@ -72,16 +73,16 @@ services: environment: CONFIG_FILE: config.yml # defaults to /data/config.yml - DOCKER_HOST: "docker" # defaults to docker - DOCKER_TLS_CERTDIR: "/certs/client" # defaults to /certs/client + DOCKER_HOST: "tcp://docker:2376" # defaults to tcp://docker:2376 + DOCKER_CERT_PATH: "/certs/client" # defaults to /certs/client DOCKER_TLS_VERIFY: "1" # defaults to 0, set to 1 to enable TLS FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN RUNNER_FILE: .runner # defaults to /data/runner.json - RUNNER_NAME: forgejo-runner # defaults to forgejo-runner, used for registration - RUNNER_TOKEN: "${RUNNER_TOKEN}" + RUNNER_NAME: runner-daemon # defaults to forgejo-runner, used for registration + RUNNER_TOKEN: ${RUNNER_TOKEN} # token obtained from Forgejo web interface RUNNER_USER: 1000 # defaults to 1000, allows for automatic file ownership DEBUG: "true" # defaults to false, set to true to enable debug logging From 27bbc83fed40fe1885be9eec29f70349b015f8d5 Mon Sep 17 00:00:00 2001 From: Merith Date: Fri, 27 Sep 2024 10:38:59 -0700 Subject: [PATCH 11/29] dont use root-user by default --- .forgejo/workflows/example-docker-compose.yml | 2 +- Dockerfile | 2 + entrypoint.sh | 89 +++---------------- examples/docker-compose/.gitignore | 3 +- .../compose-forgejo-and-runner.yml | 19 ++-- 5 files changed, 26 insertions(+), 89 deletions(-) diff --git a/.forgejo/workflows/example-docker-compose.yml b/.forgejo/workflows/example-docker-compose.yml index c45fddb..6e017db 100644 --- a/.forgejo/workflows/example-docker-compose.yml +++ b/.forgejo/workflows/example-docker-compose.yml @@ -64,4 +64,4 @@ jobs: if: always() run: | cd examples/docker-compose - docker compose -f compose-forgejo-and-runner.yml -f compose-demo-workflow.yml logs \ No newline at end of file + docker compose -f compose-forgejo-and-runner.yml -f compose-demo-workflow.yml logs diff --git a/Dockerfile b/Dockerfile index d371bdf..c43c34e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,6 +38,8 @@ LABEL maintainer="contact@forgejo.org" \ ENV HOME=/data +USER 1000:1000 + COPY --chmod=555 entrypoint.sh /entrypoint.sh WORKDIR /data diff --git a/entrypoint.sh b/entrypoint.sh index bb72004..64ec4f7 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,28 +2,13 @@ set -e +# Technically not nessecary but it cleans up the logs from having token/secret values run_command() { local cmd="$1" - # Replace any --token or --secret with [REDACTED] local safe_cmd=$(echo "$cmd" | sed -E 's/--(token|secret) [^ ]+/--\1 [REDACTED]/g') - decho "Running command: $safe_cmd" - - if [[ "$ISROOT" == true ]]; then - decho "Running as forgejo-runner" - su -c "$cmd" forgejo-runner - else - decho "Running as $(whoami)" - eval "$cmd" - fi -} - -makeUser() { - adduser -u ${RUNNER_USER} -h /data -s /bin/bash -D forgejo-runner -} -makeGroup() { - addgroup -g ${RUNNER_USER} forgejo-runner + eval "$cmd" } decho() { @@ -32,49 +17,10 @@ decho() { fi } -# Initial setup -cd /data - -decho "RUNNER_USER: ${RUNNER_USER}" -RUNNER_USER="${RUNNER_USER:-1000}" # Check if the script is running as root if [[ $(id -u) -eq 0 ]]; then ISROOT=true - decho "Running as root" -fi - -if [[ "$ISROOT" == true ]]; then - # Check if the forgejo-runner user exists, if not, create it - if ! id -u forgejo-runner >/dev/null 2>&1; then - decho "Creating user forgejo-runner with UID ${RUNNER_USER}" - makeUser - else - CURRENT_UID=$(id -u forgejo-runner) - if [[ "${CURRENT_UID}" -ne "${RUNNER_USER}" ]]; then - decho "Changing UID of forgejo-runner from ${CURRENT_UID} to ${RUNNER_USER}" - deluser forgejo-runner - makeUser - fi - fi - - # Check if the forgejo-runner group exists, if not, create it - if ! getent group forgejo-runner >/dev/null 2>&1; then - decho "Creating group forgejo-runner with GID ${RUNNER_USER}" - makeGroup - else - CURRENT_GID=$(getent group forgejo-runner | cut -d: -f3) - if [[ "${CURRENT_GID}" -ne "${RUNNER_USER}" ]]; then - decho "Changing GID of forgejo-runner from ${CURRENT_GID} to ${RUNNER_USER}" - delgroup forgejo-runner - makeGroup - fi - fi - - # Ensure /data is owned by the runner user - # yes this can slow things down but is 100% nessecary for the runner to function - # when running as a root user, because for some reason the runner create files as - # root and then cant access them - chown -R forgejo-runner:forgejo-runner /data + decho "[WARNING] Running as root user" fi # Handle and alter the config file @@ -85,9 +31,9 @@ fi CONFIG_ARG="--config ${CONFIG_FILE}" decho "CONFIG: ${CONFIG_ARG}" -DOCKER_HOST=${DOCKER_HOST:-docker} +DOCKER_HOST=${DOCKER_HOST:-"tcp://docker:2367"} DOCKER_CERT_PATH=${DOCKER_CERT_PATH:-"/certs/client"} -DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-0} +DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-1} decho "DOCKER_HOST: ${DOCKER_HOST}" decho "DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" @@ -102,18 +48,7 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then # Apply default values for docker sed -i "/^ labels:/c\ labels: [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} - sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} - - if [[ "${DOCKER_TLS_VERIFY}" -ne 1 ]]; then - decho "Docker TLS diabled" - sed -i "/^ docker_host:/c\ docker_host: ${DOCKER_HOST}" ${CONFIG_FILE} - else - decho "Docker TLS enabled" - sed -i "/^ docker_host:/c\ docker_host: ${DOCKER_HOST}" ${CONFIG_FILE} - sed -i "/^ valid_volumes:/c\ valid_volumes:\n - ${DOCKER_CERT_PATH}" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v ${DOCKER_CERT_PATH}:${DOCKER_CERT_PATH}" ${CONFIG_FILE} - fi fi ENV_FILE=${ENV_FILE:-"/data/.env"} @@ -135,9 +70,7 @@ fi decho "EXTRA_ARGS: ${EXTRA_ARGS}" # Set the runner file -if [[ -z "${RUNNER_FILE}" ]]; then - RUNNER_FILE="runner.json" # use json so editors know how to highlight -fi +RUNNER_FILE=${RUNNER_FILE:-"runner.json"} # use json so editors know how to highlight decho "RUNNER_FILE: ${RUNNER_FILE}" sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} @@ -157,22 +90,22 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then # the context of a single docker-compose, something similar could be done via healthchecks, but # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do - if [[ ! -z "${FORGEJO_SECRET}" ]]; then - run_command "forgejo-runner create-runner-file --connect \ + if [[ ! -z "${FORGEJO_SECRET}" ]]; then + run_command "forgejo-runner create-runner-file --connect \ --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ --name \"${RUNNER_NAME:-$(hostname)}\" \ --secret \"${FORGEJO_SECRET}\" \ ${CONFIG_ARG}\ ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" - else - run_command "forgejo-runner register \ + else + run_command "forgejo-runner register \ --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ --name \"${RUNNER_NAME:-$(hostname)}\" \ --token \"${RUNNER_TOKEN}\" \ --no-interactive \ ${CONFIG_ARG}\ ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" - fi + fi cat /tmp/reg.log | grep -E 'connection successful|registered successfully' >/dev/null if [[ $? -eq 0 ]]; then echo "SUCCESS" diff --git a/examples/docker-compose/.gitignore b/examples/docker-compose/.gitignore index 294fcad..94bf3ec 100644 --- a/examples/docker-compose/.gitignore +++ b/examples/docker-compose/.gitignore @@ -1,2 +1 @@ -forgejo/ -forgejo-runner/ +srv diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index a2d1fa5..6431893 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -13,7 +13,8 @@ # # Replace ${RUNNER_TOKEN} with the token obtained from the Forgejo web interface. # - +# Replace ROOT_PASSWORD with a secure password. +# networks: forgejo: @@ -24,12 +25,13 @@ services: docker-in-docker: image: code.forgejo.org/oci/docker:dind hostname: docker # Must set hostname for both internal DNS and TLS to work as certs are only valid for docker and localhost + restart: unless-stopped privileged: true networks: - forgejo environment: DOCKER_TLS_CERTDIR: "/certs" # set to "" to disable the use of TLS, also manually update existing runner configs to use port 2375 - DOCKER_HOST: "docker" # remove aswell to disable TLS + DOCKER_HOST: "docker" # remove aswell to disable TLS volumes: - docker_certs:/certs @@ -42,25 +44,27 @@ services: - /srv/forgejo-data:/data ports: - 8080:3000 + environment: + FORGEJO__security__INSTALL_LOCK: "true" # remove in production command: >- bash -c ' /bin/s6-svscan /etc/s6 & sleep 10 ; - su -c "forgejo admin user create --admin --username root --password examplepassword --email root@example.com" git ; + su -c "forgejo admin user create --admin --username root --password ROOT_PASSWORD --email root@example.com" git ; su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; sleep infinity ' # all values that have defaults listed are optional - # only FORGEJO_SECRET or RUNNER_TOKEN is required - # FORGEJO_URL is required if forgejo is in this compose file or docker network + # only FORGEJO_SECRET or RUNNER_TOKEN is required, the secret will be prioritized + # FORGEJO_URL is required if forgejo is not in this compose file or docker network runner-daemon: ## TODO: Update image to the the release ## made from this PR: https://code.forgejo.org/forgejo/runner/pulls/283 # image: code.forgejo.org/forgejo/runner:3.4.1 build: ../../ - # user: "1000" # set to run rootless, overrides RUNNER_USER and disables automatic file ownership + user: "1000" # defaults to 1000, restart: unless-stopped # needed for fixing file ownership on restart volumes: - /srv/runner-data:/data @@ -75,7 +79,7 @@ services: DOCKER_HOST: "tcp://docker:2376" # defaults to tcp://docker:2376 DOCKER_CERT_PATH: "/certs/client" # defaults to /certs/client - DOCKER_TLS_VERIFY: "1" # defaults to 0, set to 1 to enable TLS + DOCKER_TLS_VERIFY: "1" # defaults to 1 FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN @@ -83,7 +87,6 @@ services: RUNNER_FILE: .runner # defaults to /data/runner.json RUNNER_NAME: runner-daemon # defaults to forgejo-runner, used for registration RUNNER_TOKEN: ${RUNNER_TOKEN} # token obtained from Forgejo web interface - RUNNER_USER: 1000 # defaults to 1000, allows for automatic file ownership DEBUG: "true" # defaults to false, set to true to enable debug logging SKIP_WAIT: "false" # defaults to false, set to true to skip the 10 second wait to allow for forgejo and docker-in-docker to start From 38a43e67ed26798ff2b68f46ce576fc02fa4b1c6 Mon Sep 17 00:00:00 2001 From: Merith Date: Fri, 27 Sep 2024 10:46:35 -0700 Subject: [PATCH 12/29] pass tests, allow drop in replacement restore original variables update to include privileged variable treat `command` as a command and not an argument to entrypoint --- .forgejo/workflows/example-docker-compose.yml | 2 +- entrypoint.sh | 39 ++++++++++++------- .../compose-forgejo-and-runner.yml | 22 +++++------ 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/.forgejo/workflows/example-docker-compose.yml b/.forgejo/workflows/example-docker-compose.yml index 6e017db..9ab3a6a 100644 --- a/.forgejo/workflows/example-docker-compose.yml +++ b/.forgejo/workflows/example-docker-compose.yml @@ -35,7 +35,7 @@ jobs: # # Launch Forgejo & the runner # - $cli up -d + $cli up -d --remove-orphans for delay in $(seq 60) ; do test -f /srv/runner-data/.runner && break ; sleep 30 ; done test -f /srv/runner-data/.runner # diff --git a/entrypoint.sh b/entrypoint.sh index 64ec4f7..82119a6 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,11 +4,11 @@ set -e # Technically not nessecary but it cleans up the logs from having token/secret values run_command() { - local cmd="$1" + local cmd="$@" # Replace any --token or --secret with [REDACTED] local safe_cmd=$(echo "$cmd" | sed -E 's/--(token|secret) [^ ]+/--\1 [REDACTED]/g') decho "Running command: $safe_cmd" - eval "$cmd" + eval $cmd } decho() { @@ -16,6 +16,7 @@ decho() { echo "[entrypoint] $@" fi } +decho $PWD # Check if the script is running as root if [[ $(id -u) -eq 0 ]]; then @@ -23,6 +24,12 @@ if [[ $(id -u) -eq 0 ]]; then decho "[WARNING] Running as root user" fi +# Handle if `command` is passed, as command appends arguments to the entrypoint +if [ "$#" -gt 0 ]; then + run_command $@ + exit +fi + # Handle and alter the config file if [[ -z "${CONFIG_FILE}" ]]; then echo "CONFIG_FILE is not set" @@ -49,6 +56,12 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then sed -i "/^ labels:/c\ labels: [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} + if [[ "${DOCKER_PRIVILEGED}" == "true" ]]; then + sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} + sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} + sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} + fi + fi ENV_FILE=${ENV_FILE:-"/data/.env"} @@ -91,20 +104,20 @@ if [[ ! -s "${RUNNER_FILE}" ]]; then # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do if [[ ! -z "${FORGEJO_SECRET}" ]]; then - run_command "forgejo-runner create-runner-file --connect \ - --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ - --name \"${RUNNER_NAME:-$(hostname)}\" \ - --secret \"${FORGEJO_SECRET}\" \ + run_command forgejo-runner create-runner-file --connect \ + --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + --secret "${FORGEJO_SECRET}" \ ${CONFIG_ARG}\ - ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log else - run_command "forgejo-runner register \ - --instance \"${FORGEJO_URL:-http://forgejo:3000}\" \ - --name \"${RUNNER_NAME:-$(hostname)}\" \ - --token \"${RUNNER_TOKEN}\" \ + run_command forgejo-runner register \ + --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + --token "${RUNNER_TOKEN}" \ --no-interactive \ ${CONFIG_ARG}\ - ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log" + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log fi cat /tmp/reg.log | grep -E 'connection successful|registered successfully' >/dev/null if [[ $? -eq 0 ]]; then @@ -122,4 +135,4 @@ fi unset RUNNER_TOKEN unset FORGEJO_SECRET -run_command "forgejo-runner daemon ${CONFIG_ARG}" +run_command forgejo-runner daemon ${CONFIG_ARG} diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 6431893..018d956 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -13,11 +13,8 @@ # # Replace ${RUNNER_TOKEN} with the token obtained from the Forgejo web interface. # -# Replace ROOT_PASSWORD with a secure password. +# Replace {ROOT_PASSWORD} with a secure password. # -networks: - forgejo: - volumes: docker_certs: @@ -27,8 +24,6 @@ services: hostname: docker # Must set hostname for both internal DNS and TLS to work as certs are only valid for docker and localhost restart: unless-stopped privileged: true - networks: - - forgejo environment: DOCKER_TLS_CERTDIR: "/certs" # set to "" to disable the use of TLS, also manually update existing runner configs to use port 2375 DOCKER_HOST: "docker" # remove aswell to disable TLS @@ -38,19 +33,22 @@ services: forgejo: image: codeberg.org/forgejo/forgejo:1.21 hostname: forgejo - networks: - - forgejo volumes: - /srv/forgejo-data:/data ports: - 8080:3000 environment: FORGEJO__security__INSTALL_LOCK: "true" # remove in production + FORGEJO__log__LEVEL: "debug" # remove in production + FORGEJO__repository__ENABLE_PUSH_CREATE_USER: "true" # enables the ability to create a repo when pushing + FORGEJO__repository__DEFAULT_PUSH_CREATE_PRIVATE: "false" # defaults above to public + FORGEJO__repository__DEFAULT_REPO_UNITS: "repo.code,repo.actions" + # `command` is not neecessary, but can be used to create an admin user as shown below when combined with INSTALL_LOCK command: >- bash -c ' /bin/s6-svscan /etc/s6 & sleep 10 ; - su -c "forgejo admin user create --admin --username root --password ROOT_PASSWORD --email root@example.com" git ; + su -c "forgejo admin user create --admin --username root --password {ROOT_PASSWORD} --email root@example.com" git ; su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; sleep infinity ' @@ -69,17 +67,19 @@ services: volumes: - /srv/runner-data:/data - docker_certs:/certs - networks: - - forgejo depends_on: - docker-in-docker - forgejo + links: + - forgejo + - docker-in-docker environment: CONFIG_FILE: config.yml # defaults to /data/config.yml DOCKER_HOST: "tcp://docker:2376" # defaults to tcp://docker:2376 DOCKER_CERT_PATH: "/certs/client" # defaults to /certs/client DOCKER_TLS_VERIFY: "1" # defaults to 1 + DOCKER_PRIVILEGED: "true" # defaults to false for security reasons FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN From c6401d519723047176ba800d01b06b182191404f Mon Sep 17 00:00:00 2001 From: merith-xyz Date: Sat, 28 Sep 2024 09:28:52 -0700 Subject: [PATCH 13/29] force perms on /srv/runner-data --- .forgejo/workflows/example-docker-compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.forgejo/workflows/example-docker-compose.yml b/.forgejo/workflows/example-docker-compose.yml index 9ab3a6a..aeff9fc 100644 --- a/.forgejo/workflows/example-docker-compose.yml +++ b/.forgejo/workflows/example-docker-compose.yml @@ -28,6 +28,8 @@ jobs: - name: run the example run: | set -x + mkdir -p /srv/runner-data + chown 1000:1000 /srv/runner-data cd examples/docker-compose secret=$(openssl rand -hex 20) sed -i -e "s/{SHARED_SECRET}/$secret/" compose-forgejo-and-runner.yml From 7d611fc32a86471ab8ee07c61bbb94e29e23b1e3 Mon Sep 17 00:00:00 2001 From: Merith Date: Tue, 1 Oct 2024 13:28:51 -0700 Subject: [PATCH 14/29] work around env file not loaded --- entrypoint.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 82119a6..68cc3d2 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -58,8 +58,10 @@ if [[ ! -f "${CONFIG_FILE}" ]]; then if [[ "${DOCKER_PRIVILEGED}" == "true" ]]; then sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v /certs/client:/certs/client" ${CONFIG_FILE} + sed -i "/^ options:/c\ options: -v /certs/client:/certs/client:ro" ${CONFIG_FILE} sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} + + sed -i "/^ envs:/c\ envs:\n DOCKER_HOST: ${DOCKER_HOST}\n DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}\n DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" ${CONFIG_FILE} fi fi @@ -68,14 +70,6 @@ ENV_FILE=${ENV_FILE:-"/data/.env"} decho "ENV_FILE: ${ENV_FILE}" sed -i "/^ env_file:/c\ env_file: ${ENV_FILE}" ${CONFIG_FILE} -if [[ ! -f "${ENV_FILE}" ]]; then - echo "Creating ${ENV_FILE}" - touch ${ENV_FILE} - echo "DOCKER_HOST=${DOCKER_HOST}" >> ${ENV_FILE} - echo "DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY}" >> ${ENV_FILE} - echo "DOCKER_CERT_PATH=${DOCKER_CERT_PATH}" >> ${ENV_FILE} -fi - EXTRA_ARGS="" if [[ ! -z "${RUNNER_LABELS}" ]]; then EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" From 676f16b16a9be157eb4e269236f55649bb79a2be Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Wed, 25 Dec 2024 22:58:57 +0000 Subject: [PATCH 15/29] commit current env2var work --- internal/pkg/config/config-env.go | 138 ++++++++++++++++++++++++++++++ internal/pkg/config/config.go | 3 + 2 files changed, 141 insertions(+) create mode 100644 internal/pkg/config/config-env.go diff --git a/internal/pkg/config/config-env.go b/internal/pkg/config/config-env.go new file mode 100644 index 0000000..063b7c9 --- /dev/null +++ b/internal/pkg/config/config-env.go @@ -0,0 +1,138 @@ +package config + +import ( + "os" + "strconv" + "strings" + "time" + + log "github.com/sirupsen/logrus" +) + +var ( + envPrefix = "RUNNER__" +) + +// loadEnvVars loads configuration settings from environment variables +// prefixed with "RUNNER__" and updates the provided Config struct accordingly. +func loadEnvVars(config *Config) { + // There probably is a better way to do this, but I'm not sure how to do it. + // This implementation causes env-vars to override config file settings, + // without writing to the config file. + + // Log + loadEnvStr(config, envPrefix+"LOG__LEVEL", &config.Log.Level) + loadEnvStr(config, envPrefix+"LOG__JOB_LEVEL", &config.Log.JobLevel) + + // Runner + loadEnvStr(config, envPrefix+"RUNNER__FILE", &config.Runner.File) + loadEnvInt(config, envPrefix+"RUNNER__CAPACITY", &config.Runner.Capacity) + loadEnvTable(config, envPrefix+"RUNNER__ENVS", &config.Runner.Envs) + loadEnvStr(config, envPrefix+"RUNNER__ENV_FILE", &config.Runner.EnvFile) + loadEnvDuration(config, envPrefix+"RUNNER__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) + loadEnvBool(config, envPrefix+"RUNNER__INSECURE", &config.Runner.Insecure) + loadEnvDuration(config, envPrefix+"RUNNER__FETCH_TIMEOUT", &config.Runner.FetchTimeout) + loadEnvDuration(config, envPrefix+"RUNNER__FETCH_INTERVAL", &config.Runner.FetchInterval) + loadEnvDuration(config, envPrefix+"RUNNER__REPORT_INTERVAL", &config.Runner.ReportInterval) + loadEnvList(config, envPrefix+"RUNNER__LABELS", &config.Runner.Labels) + + // Cache + loadEnvBool(config, envPrefix+"CACHE__ENABLED", config.Cache.Enabled) + loadEnvStr(config, envPrefix+"CACHE__DIR", &config.Cache.Dir) + loadEnvStr(config, envPrefix+"CACHE__HOST", &config.Cache.Host) + loadEnvUInt16(config, envPrefix+"CACHE__PORT", &config.Cache.Port) + loadEnvStr(config, envPrefix+"CACHE__EXTERNAL_SERVER", &config.Cache.ExternalServer) + + // Container + loadEnvStr(config, envPrefix+"CONTAINER__NETWORK", &config.Container.Network) + loadEnvStr(config, envPrefix+"CONTAINER__NETWORK_MODE", &config.Container.NetworkMode) + loadEnvBool(config, envPrefix+"CONTAINER__ENABLE_IPV6", &config.Container.EnableIPv6) + loadEnvBool(config, envPrefix+"CONTAINER__PRIVILEGED", &config.Container.Privileged) + loadEnvStr(config, envPrefix+"CONTAINER__OPTIONS", &config.Container.Options) + loadEnvStr(config, envPrefix+"CONTAINER__WORKDIR_PARENT", &config.Container.WorkdirParent) + loadEnvList(config, envPrefix+"CONTAINER__VALID_VOLUMES", &config.Container.ValidVolumes) + loadEnvStr(config, envPrefix+"CONTAINER__DOCKER_HOST", &config.Container.DockerHost) + loadEnvBool(config, envPrefix+"CONTAINER__FORCE_PULL", &config.Container.ForcePull) + + // Host + loadEnvStr(config, envPrefix+"HOST__WORKDIR_PARENT", &config.Host.WorkdirParent) +} + +// loadEnvStr loads an environment variable into the provided string pointer if it exists. +func loadEnvStr(config *Config, key string, dest *string) { + // Example: RUNNER__LOG__LEVEL = "info" + if v := os.Getenv(key); v != "" { + *dest = v + } +} + +// loadEnvInt loads an environment variable into the provided int pointer if it exists. +func loadEnvInt(config *Config, key string, dest *int) { + // Example: RUNNER__RUNNER__CAPACITY = "1" + if v := os.Getenv(key); v != "" { + if intValue, err := strconv.Atoi(v); err == nil { + *dest = intValue + } + } +} + +// loadEnvUInt16 loads an environment variable into the provided uint16 pointer if it exists. +func loadEnvUInt16(config *Config, key string, dest *uint16) { + // Example: RUNNER__CACHE__PORT = "8080" + if v := os.Getenv(key); v != "" { + if uint16Value, err := strconv.ParseUint(v, 10, 16); err == nil { + *dest = uint16(uint16Value) + } + } +} + +// loadEnvDuration loads an environment variable into the provided time.Duration pointer if it exists. +func loadEnvDuration(config *Config, key string, dest *time.Duration) { + // Example: RUNNER__RUNNER__SHUTDOWN_TIMEOUT = "3h" + if v := os.Getenv(key); v != "" { + if durationValue, err := time.ParseDuration(v); err == nil { + *dest = durationValue + } + } +} + +// loadEnvBool loads an environment variable into the provided bool pointer if it exists. +func loadEnvBool(config *Config, key string, dest *bool) { + // Example: RUNNER__RUNNER__INSECURE = "false" + if v := os.Getenv(key); v != "" { + if boolValue, err := strconv.ParseBool(v); err == nil { + *dest = boolValue + } + } +} + +// loadEnvTable loads an environment variable into the provided map[string]string pointer if it exists. +func loadEnvTable(config *Config, key string, dest *map[string]string) { + // This is a placeholder function. + // This function is not yet implemented. + // This function is meant to be replaced by those more competent than me. + log.Warn("Loading Tables from env is not yet implemented: ", key) +} + +// loadEnvList loads an environment variable into the provided []string pointer if it exists. +func loadEnvList(config *Config, key string, dest *[]string) { + // Example: RUNNER__RUNNER__LABELS = "label1, label2, label3" + if v := os.Getenv(key); v != "" { + *dest = splitAndTrim(v) + } +} + +func splitAndTrim(s string) []string { + lines := strings.Split(s, "\n") + var result []string + for _, line := range lines { + items := strings.Split(line, ",") + for _, item := range items { + trimmed := strings.TrimSpace(item) + if trimmed != "" { + result = append(result, trimmed) + } + } + } + return result +} diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 60be651..0a4b548 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -170,5 +170,8 @@ func LoadDefault(file string) (*Config, error) { } } + // Load environment variables at the end to allow for overriding the default values. + loadEnvVars(cfg) + return cfg, nil } From e9634ef5fb3c392e1308c4e87435a88d0c5f9654 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Wed, 25 Dec 2024 23:46:40 +0000 Subject: [PATCH 16/29] Env-to-config works --- entrypoint.sh | 107 ++++++++++++------------------ internal/pkg/config/config-env.go | 79 +++++++++++----------- 2 files changed, 86 insertions(+), 100 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 68cc3d2..8e9d5fe 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,7 +2,7 @@ set -e -# Technically not nessecary but it cleans up the logs from having token/secret values +# Technically not necessary, but it cleans up the logs from having token/secret values run_command() { local cmd="$@" # Replace any --token or --secret with [REDACTED] @@ -26,92 +26,73 @@ fi # Handle if `command` is passed, as command appends arguments to the entrypoint if [ "$#" -gt 0 ]; then - run_command $@ - exit + run_command $@ + exit fi -# Handle and alter the config file -if [[ -z "${CONFIG_FILE}" ]]; then - echo "CONFIG_FILE is not set" - CONFIG_FILE="/data/config.yml" -fi -CONFIG_ARG="--config ${CONFIG_FILE}" +# Use environment variables directly, with fallback defaults if not set +RUNNER__CONFIG_FILE="${RUNNER__CONFIG_FILE:-/data/config.yml}" +ENV_FILE="${ENV_FILE:-/data/.env}" +RUNNER__RUNNER__FILE="${RUNNER__RUNNER__FILE:-/data/runner.json}" + +# Set config arguments +CONFIG_ARG="--config ${RUNNER__CONFIG_FILE}" + +# Container-specific environment variables +RUNNER__CONTAINER__NETWORK="${RUNNER__CONTAINER__NETWORK:-host}" +RUNNER__CONTAINER__ENABLE_IPV6="${RUNNER__CONTAINER__ENABLE_IPV6:-false}" +RUNNER__CONTAINER__PRIVILEGED="${RUNNER__CONTAINER__PRIVILEGED:-false}" +RUNNER__CONTAINER__LABELS="${RUNNER__CONTAINER__LABELS:-}" +RUNNER__CONTAINER__VALID_VOLUMES="${RUNNER__CONTAINER__VALID_VOLUMES:-}" + +# Show config variables decho "CONFIG: ${CONFIG_ARG}" -DOCKER_HOST=${DOCKER_HOST:-"tcp://docker:2367"} -DOCKER_CERT_PATH=${DOCKER_CERT_PATH:-"/certs/client"} -DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-1} -decho "DOCKER_HOST: ${DOCKER_HOST}" -decho "DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" -decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" -if [[ ! -f "${CONFIG_FILE}" ]]; then - echo "Creating ${CONFIG_FILE}" - run_command "forgejo-runner generate-config > ${CONFIG_FILE}" - - # Remove test environment variables if they exist in the config file - sed -i "/^ A_TEST_ENV_NAME_1:/d" ${CONFIG_FILE} - sed -i "/^ A_TEST_ENV_NAME_2:/d" ${CONFIG_FILE} - - # Apply default values for docker - sed -i "/^ labels:/c\ labels: [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} - sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} - - if [[ "${DOCKER_PRIVILEGED}" == "true" ]]; then - sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v /certs/client:/certs/client:ro" ${CONFIG_FILE} - sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} - - sed -i "/^ envs:/c\ envs:\n DOCKER_HOST: ${DOCKER_HOST}\n DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}\n DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" ${CONFIG_FILE} - fi - +# Generate config if not found +if [[ ! -f "${RUNNER__CONFIG_FILE}" ]]; then + echo "Creating ${RUNNER__CONFIG_FILE}" + run_command "forgejo-runner generate-config > ${RUNNER__CONFIG_FILE}" fi -ENV_FILE=${ENV_FILE:-"/data/.env"} -decho "ENV_FILE: ${ENV_FILE}" -sed -i "/^ env_file:/c\ env_file: ${ENV_FILE}" ${CONFIG_FILE} +# Use environment variables directly in the config, no need for sed edits +decho "Using config from: ${RUNNER__CONFIG_FILE}" +decho "Using environment file: ${ENV_FILE}" +# Set extra arguments from environment variables EXTRA_ARGS="" -if [[ ! -z "${RUNNER_LABELS}" ]]; then - EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" +if [[ -n "${RUNNER__CONTAINER__LABELS}" ]]; then + EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER__CONTAINER__LABELS}" fi decho "EXTRA_ARGS: ${EXTRA_ARGS}" -# Set the runner file -RUNNER_FILE=${RUNNER_FILE:-"runner.json"} # use json so editors know how to highlight -decho "RUNNER_FILE: ${RUNNER_FILE}" -sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} - if [[ "${SKIP_WAIT}" != "true" ]]; then echo "Waiting 10s to allow other services to start up..." sleep 10 fi -if [[ ! -s "${RUNNER_FILE}" ]]; then - touch ${RUNNER_FILE} +# Try to register the runner +if [[ ! -s "${RUNNER__RUNNER__FILE}" ]]; then + touch ${RUNNER__RUNNER__FILE} try=$((try + 1)) success=0 decho "try: ${try}, success: ${success}" - # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, - # for the forgejo-runner to wait a moment for gitea to become available before erroring out. Within - # the context of a single docker-compose, something similar could be done via healthchecks, but - # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do - if [[ ! -z "${FORGEJO_SECRET}" ]]; then + if [[ -n "${FORGEJO_SECRET}" ]]; then run_command forgejo-runner create-runner-file --connect \ - --instance "${FORGEJO_URL:-http://forgejo:3000}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ - --secret "${FORGEJO_SECRET}" \ - ${CONFIG_ARG}\ - ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log + --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + --secret "${FORGEJO_SECRET}" \ + ${CONFIG_ARG} \ + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log else run_command forgejo-runner register \ - --instance "${FORGEJO_URL:-http://forgejo:3000}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ - --token "${RUNNER_TOKEN}" \ - --no-interactive \ - ${CONFIG_ARG}\ - ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log + --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + --token "${RUNNER_TOKEN}" \ + --no-interactive \ + ${CONFIG_ARG} \ + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log fi cat /tmp/reg.log | grep -E 'connection successful|registered successfully' >/dev/null if [[ $? -eq 0 ]]; then diff --git a/internal/pkg/config/config-env.go b/internal/pkg/config/config-env.go index 063b7c9..0664df2 100644 --- a/internal/pkg/config/config-env.go +++ b/internal/pkg/config/config-env.go @@ -5,12 +5,6 @@ import ( "strconv" "strings" "time" - - log "github.com/sirupsen/logrus" -) - -var ( - envPrefix = "RUNNER__" ) // loadEnvVars loads configuration settings from environment variables @@ -20,42 +14,47 @@ func loadEnvVars(config *Config) { // This implementation causes env-vars to override config file settings, // without writing to the config file. + // SkipEnv if variable is set + if _, ok := os.LookupEnv("RUNNER__SKIP_ENV"); ok { + return + } + // Log - loadEnvStr(config, envPrefix+"LOG__LEVEL", &config.Log.Level) - loadEnvStr(config, envPrefix+"LOG__JOB_LEVEL", &config.Log.JobLevel) + loadEnvStr(config, "RUNNER__LOG__LEVEL", &config.Log.Level) + loadEnvStr(config, "RUNNER__LOG__JOB_LEVEL", &config.Log.JobLevel) // Runner - loadEnvStr(config, envPrefix+"RUNNER__FILE", &config.Runner.File) - loadEnvInt(config, envPrefix+"RUNNER__CAPACITY", &config.Runner.Capacity) - loadEnvTable(config, envPrefix+"RUNNER__ENVS", &config.Runner.Envs) - loadEnvStr(config, envPrefix+"RUNNER__ENV_FILE", &config.Runner.EnvFile) - loadEnvDuration(config, envPrefix+"RUNNER__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) - loadEnvBool(config, envPrefix+"RUNNER__INSECURE", &config.Runner.Insecure) - loadEnvDuration(config, envPrefix+"RUNNER__FETCH_TIMEOUT", &config.Runner.FetchTimeout) - loadEnvDuration(config, envPrefix+"RUNNER__FETCH_INTERVAL", &config.Runner.FetchInterval) - loadEnvDuration(config, envPrefix+"RUNNER__REPORT_INTERVAL", &config.Runner.ReportInterval) - loadEnvList(config, envPrefix+"RUNNER__LABELS", &config.Runner.Labels) + loadEnvStr(config, "RUNNER__RUNNER__FILE", &config.Runner.File) + loadEnvInt(config, "RUNNER__RUNNER__CAPACITY", &config.Runner.Capacity) + loadEnvTable(config, "RUNNER__RUNNER__ENVS", &config.Runner.Envs) + loadEnvStr(config, "RUNNER__RUNNER__ENV_FILE", &config.Runner.EnvFile) + loadEnvDuration(config, "RUNNER__RUNNER__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) + loadEnvBool(config, "RUNNER__RUNNER__INSECURE", &config.Runner.Insecure) + loadEnvDuration(config, "RUNNER__RUNNER__FETCH_TIMEOUT", &config.Runner.FetchTimeout) + loadEnvDuration(config, "RUNNER__RUNNER__FETCH_INTERVAL", &config.Runner.FetchInterval) + loadEnvDuration(config, "RUNNER__RUNNER__REPORT_INTERVAL", &config.Runner.ReportInterval) + loadEnvList(config, "RUNNER__RUNNER__LABELS", &config.Runner.Labels) // Cache - loadEnvBool(config, envPrefix+"CACHE__ENABLED", config.Cache.Enabled) - loadEnvStr(config, envPrefix+"CACHE__DIR", &config.Cache.Dir) - loadEnvStr(config, envPrefix+"CACHE__HOST", &config.Cache.Host) - loadEnvUInt16(config, envPrefix+"CACHE__PORT", &config.Cache.Port) - loadEnvStr(config, envPrefix+"CACHE__EXTERNAL_SERVER", &config.Cache.ExternalServer) + loadEnvBool(config, "RUNNER__CACHE__ENABLED", config.Cache.Enabled) + loadEnvStr(config, "RUNNER__CACHE__DIR", &config.Cache.Dir) + loadEnvStr(config, "RUNNER__CACHE__HOST", &config.Cache.Host) + loadEnvUInt16(config, "RUNNER__CACHE__PORT", &config.Cache.Port) + loadEnvStr(config, "RUNNER__CACHE__EXTERNAL_SERVER", &config.Cache.ExternalServer) // Container - loadEnvStr(config, envPrefix+"CONTAINER__NETWORK", &config.Container.Network) - loadEnvStr(config, envPrefix+"CONTAINER__NETWORK_MODE", &config.Container.NetworkMode) - loadEnvBool(config, envPrefix+"CONTAINER__ENABLE_IPV6", &config.Container.EnableIPv6) - loadEnvBool(config, envPrefix+"CONTAINER__PRIVILEGED", &config.Container.Privileged) - loadEnvStr(config, envPrefix+"CONTAINER__OPTIONS", &config.Container.Options) - loadEnvStr(config, envPrefix+"CONTAINER__WORKDIR_PARENT", &config.Container.WorkdirParent) - loadEnvList(config, envPrefix+"CONTAINER__VALID_VOLUMES", &config.Container.ValidVolumes) - loadEnvStr(config, envPrefix+"CONTAINER__DOCKER_HOST", &config.Container.DockerHost) - loadEnvBool(config, envPrefix+"CONTAINER__FORCE_PULL", &config.Container.ForcePull) + loadEnvStr(config, "RUNNER__CONTAINER__NETWORK", &config.Container.Network) + loadEnvStr(config, "RUNNER__CONTAINER__NETWORK_MODE", &config.Container.NetworkMode) + loadEnvBool(config, "RUNNER__CONTAINER__ENABLE_IPV6", &config.Container.EnableIPv6) + loadEnvBool(config, "RUNNER__CONTAINER__PRIVILEGED", &config.Container.Privileged) + loadEnvStr(config, "RUNNER__CONTAINER__OPTIONS", &config.Container.Options) + loadEnvStr(config, "RUNNER__CONTAINER__WORKDIR_PARENT", &config.Container.WorkdirParent) + loadEnvList(config, "RUNNER__CONTAINER__VALID_VOLUMES", &config.Container.ValidVolumes) + loadEnvStr(config, "RUNNER__CONTAINER__DOCKER_HOST", &config.Container.DockerHost) + loadEnvBool(config, "RUNNER__CONTAINER__FORCE_PULL", &config.Container.ForcePull) // Host - loadEnvStr(config, envPrefix+"HOST__WORKDIR_PARENT", &config.Host.WorkdirParent) + loadEnvStr(config, "RUNNER__HOST__WORKDIR_PARENT", &config.Host.WorkdirParent) } // loadEnvStr loads an environment variable into the provided string pointer if it exists. @@ -108,10 +107,16 @@ func loadEnvBool(config *Config, key string, dest *bool) { // loadEnvTable loads an environment variable into the provided map[string]string pointer if it exists. func loadEnvTable(config *Config, key string, dest *map[string]string) { - // This is a placeholder function. - // This function is not yet implemented. - // This function is meant to be replaced by those more competent than me. - log.Warn("Loading Tables from env is not yet implemented: ", key) + // Example: RUNNER__RUNNER__ENVS = "key1=value1, key2=value2, key3=value3" + if v := os.Getenv(key); v != "" { + *dest = make(map[string]string) + for _, pair := range splitAndTrim(v) { + kv := strings.SplitN(pair, "=", 2) + if len(kv) == 2 { + (*dest)[kv[0]] = kv[1] + } + } + } } // loadEnvList loads an environment variable into the provided []string pointer if it exists. From 1e466136c99c9baacaf07a22a843e89a99193b79 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Thu, 26 Dec 2024 00:01:20 +0000 Subject: [PATCH 17/29] update tests --- entrypoint.sh | 4 ++-- .../compose-forgejo-and-runner.yml | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 8e9d5fe..492ce47 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -81,14 +81,14 @@ if [[ ! -s "${RUNNER__RUNNER__FILE}" ]]; then if [[ -n "${FORGEJO_SECRET}" ]]; then run_command forgejo-runner create-runner-file --connect \ --instance "${FORGEJO_URL:-http://forgejo:3000}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ + --name "${RUNNER__NAME:-$(hostname)}" \ --secret "${FORGEJO_SECRET}" \ ${CONFIG_ARG} \ ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log else run_command forgejo-runner register \ --instance "${FORGEJO_URL:-http://forgejo:3000}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ + --name "${RUNNER__NAME:-$(hostname)}" \ --token "${RUNNER_TOKEN}" \ --no-interactive \ ${CONFIG_ARG} \ diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 018d956..21347cc 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -74,19 +74,19 @@ services: - forgejo - docker-in-docker environment: - CONFIG_FILE: config.yml # defaults to /data/config.yml - - DOCKER_HOST: "tcp://docker:2376" # defaults to tcp://docker:2376 - DOCKER_CERT_PATH: "/certs/client" # defaults to /certs/client - DOCKER_TLS_VERIFY: "1" # defaults to 1 - DOCKER_PRIVILEGED: "true" # defaults to false for security reasons - FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN - - RUNNER_FILE: .runner # defaults to /data/runner.json - RUNNER_NAME: runner-daemon # defaults to forgejo-runner, used for registration RUNNER_TOKEN: ${RUNNER_TOKEN} # token obtained from Forgejo web interface + RUNNER__CONFIG_FILE: config.yml # defaults to /data/config.yml + RUNNER__NAME: forgejo-runner # defaults to forgejo-runner + RUNNER__RUNNER__FILE: .runner # defaults to /data/runner.json + + RUNNER__CONTAINER__PRIVILEGED: "true" # defaults to false for security reasons + RUNNER__RUNNER__ENVS: | + DOCKER_HOST=tcp://docker:2376 + DOCKER_TLS_VERIFY=1 + DOCKER_CERT_PATH=/certs/client # defaults to empty + DEBUG: "true" # defaults to false, set to true to enable debug logging SKIP_WAIT: "false" # defaults to false, set to true to skip the 10 second wait to allow for forgejo and docker-in-docker to start From 709e1518d69caaef05b27bc6b965f6db3e778819 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Thu, 26 Dec 2024 00:26:24 +0000 Subject: [PATCH 18/29] update tests --- examples/docker-compose/compose-demo-workflow.yml | 2 +- examples/docker-compose/compose-forgejo-and-runner.yml | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/docker-compose/compose-demo-workflow.yml b/examples/docker-compose/compose-demo-workflow.yml index 90e7d52..da419bf 100644 --- a/examples/docker-compose/compose-demo-workflow.yml +++ b/examples/docker-compose/compose-demo-workflow.yml @@ -21,7 +21,7 @@ services: git config user.name username ; git commit -m demo ; while : ; do - git push --set-upstream --force http://root:{ROOT_PASSWORD}@forgejo:3000/root/test main && break ; + git push --set-upstream --force http://root:ROOT_PASSWORD@forgejo:3000/root/test main && break ; sleep 5 ; done ; sha=`git rev-parse HEAD` ; diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 21347cc..194fb5c 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -13,7 +13,7 @@ # # Replace ${RUNNER_TOKEN} with the token obtained from the Forgejo web interface. # -# Replace {ROOT_PASSWORD} with a secure password. +# Replace ROOT_PASSWORD with a secure password. # volumes: docker_certs: @@ -48,7 +48,7 @@ services: bash -c ' /bin/s6-svscan /etc/s6 & sleep 10 ; - su -c "forgejo admin user create --admin --username root --password {ROOT_PASSWORD} --email root@example.com" git ; + su -c "forgejo admin user create --admin --username root --password ROOT_PASSWORD --email root@example.com" git ; su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; sleep infinity ' @@ -87,6 +87,8 @@ services: DOCKER_HOST=tcp://docker:2376 DOCKER_TLS_VERIFY=1 DOCKER_CERT_PATH=/certs/client # defaults to empty + RUNNER__RUNNER__LABELS: | + "docker:docker://code.forgejo.org/oci/node:20-bookworm" - DEBUG: "true" # defaults to false, set to true to enable debug logging + DEBUG: "true" # defaults to false, set to true to enable debug logging in the entrypoint SKIP_WAIT: "false" # defaults to false, set to true to skip the 10 second wait to allow for forgejo and docker-in-docker to start From 8fa6e368c45b123aff15fcd685a56e00ed509d1d Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Thu, 26 Dec 2024 00:43:39 +0000 Subject: [PATCH 19/29] tweak tests --- examples/docker-compose/compose-forgejo-and-runner.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 194fb5c..8ec9129 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -83,6 +83,7 @@ services: RUNNER__RUNNER__FILE: .runner # defaults to /data/runner.json RUNNER__CONTAINER__PRIVILEGED: "true" # defaults to false for security reasons + RUNNER__CONTAINER_OPTIONS: -v /certs/client:/certs/client:ro # needed for TLS RUNNER__RUNNER__ENVS: | DOCKER_HOST=tcp://docker:2376 DOCKER_TLS_VERIFY=1 From c7098ae0f6edb7868417856aa3609d4bf3b5477c Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Thu, 26 Dec 2024 01:00:01 +0000 Subject: [PATCH 20/29] getting there... --- examples/docker-compose/compose-forgejo-and-runner.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 8ec9129..7ae268d 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -6,7 +6,7 @@ # # openssl rand -hex 20 # -# Replace all occurences of {SHARED_SECRET} below with the output. +# Replace all occurences of 02f8e8ed1bd08d55338026d04b5513684ff23c1f below with the output. # # NOTE: a token obtained from the Forgejo web interface cannot be used # as a shared secret. @@ -49,7 +49,7 @@ services: /bin/s6-svscan /etc/s6 & sleep 10 ; su -c "forgejo admin user create --admin --username root --password ROOT_PASSWORD --email root@example.com" git ; - su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; + su -c "forgejo forgejo-cli actions register --secret 02f8e8ed1bd08d55338026d04b5513684ff23c1f" git ; sleep infinity ' @@ -75,7 +75,7 @@ services: - docker-in-docker environment: FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 - FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN + FORGEJO_SECRET: "02f8e8ed1bd08d55338026d04b5513684ff23c1f" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN RUNNER_TOKEN: ${RUNNER_TOKEN} # token obtained from Forgejo web interface RUNNER__CONFIG_FILE: config.yml # defaults to /data/config.yml @@ -84,6 +84,8 @@ services: RUNNER__CONTAINER__PRIVILEGED: "true" # defaults to false for security reasons RUNNER__CONTAINER_OPTIONS: -v /certs/client:/certs/client:ro # needed for TLS + RUNNER__CONTAINER__DOCKER_HOST: "tcp://docker:2376" # defaults to "-", an available docker host will automatically be found + RUNNER__RUNNER__INSECURE: false RUNNER__RUNNER__ENVS: | DOCKER_HOST=tcp://docker:2376 DOCKER_TLS_VERIFY=1 From 048450dee98b250e9a9a4f7fa9b406f1002b602f Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Thu, 26 Dec 2024 18:15:54 +0000 Subject: [PATCH 21/29] current state: Not Working... at all I was tweaking the entrypoint and now its like it just randomly drops env-vars or fails to read them *no reason* despite them being confirmed to exist via other methods (manual running of commands within container, sanity checking in the entrypoint) --- entrypoint.sh | 49 ++++++++---- .../compose-forgejo-and-runner.yml | 29 +++---- internal/pkg/config/config-env.go | 75 +++++++++++-------- internal/pkg/config/config.go | 10 +++ 4 files changed, 101 insertions(+), 62 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 492ce47..4a3425f 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -30,21 +30,42 @@ if [ "$#" -gt 0 ]; then exit fi +# Set default values (if needed) +DEFAULT_DOCKER_HOST="tcp://docker:2376" +DEFAULT_DOCKER_TLS_VERIFY="1" +DEFAULT_DOCKER_CERT_PATH="/certs/client" + +# Ensure the variables are not empty by using explicit checks +DOCKER_HOST="${RUNNER__DOCKER_HOST:-${DOCKER_HOST:-${DEFAULT_DOCKER_HOST}}}" +DOCKER_TLS_VERIFY="${RUNNER__DOCKER_TLS_VERIFY:-${DOCKER_TLS_VERIFY:-${DEFAULT_DOCKER_TLS_VERIFY}}}" +DOCKER_CERT_PATH="${DOCKER_CERT_PATH:-${DEFAULT_DOCKER_CERT_PATH}}" + +RUNNER__container__DOCKER_HOST="${RUNNER__DOCKER_HOST:-${DOCKER_HOST:-${DEFAULT_DOCKER_HOST}}}" +RUNNER__runner__INSECURE="${RUNNER__DOCKER_TLS_VERIFY:-${DOCKER_TLS_VERIFY:-${DEFAULT_DOCKER_TLS_VERIFY}}}" + +RUNNER__container__NETWORK="${RUNNER__container__NETWORK:-host}" +RUNNER__container__OPTIONS="${RUNNER__container__OPTIONS:-} -v ${DOCKER_CERT_PATH}:${DOCKER_CERT_PATH}:ro" +RUNNER__container__VALID_VOLUMES="${RUNNER__container__VALID_VOLUMES:-} ${DOCKER_CERT_PATH}" +RUNNER__container__PRIVILEGED="${RUNNER__container__PRIVILEGED:-true}" + +RUNNER__runner__FILE="${RUNNER__runner__FILE:-/data/runner.json}" + +decho "DOCKER_HOST: ${DOCKER_HOST}" +decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" +decho "DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" +decho "RUNNER__container__DOCKER_HOST: ${RUNNER__container__DOCKER_HOST}" +decho "RUNNER__runner__INSECURE: ${RUNNER__runner__INSECURE}" +decho "RUNNER__container__NETWORK: ${RUNNER__container__NETWORK}" +decho "RUNNER__container__OPTIONS: ${RUNNER__container__OPTIONS}" +decho "RUNNER__container__VALID_VOLUMES: ${RUNNER__container__VALID_VOLUMES}" +decho "RUNNER__container__PRIVILEGED: ${RUNNER__container__PRIVILEGED}" +decho "RUNNER__runner__FILE: ${RUNNER__runner__FILE}" + # Use environment variables directly, with fallback defaults if not set RUNNER__CONFIG_FILE="${RUNNER__CONFIG_FILE:-/data/config.yml}" ENV_FILE="${ENV_FILE:-/data/.env}" -RUNNER__RUNNER__FILE="${RUNNER__RUNNER__FILE:-/data/runner.json}" - # Set config arguments CONFIG_ARG="--config ${RUNNER__CONFIG_FILE}" - -# Container-specific environment variables -RUNNER__CONTAINER__NETWORK="${RUNNER__CONTAINER__NETWORK:-host}" -RUNNER__CONTAINER__ENABLE_IPV6="${RUNNER__CONTAINER__ENABLE_IPV6:-false}" -RUNNER__CONTAINER__PRIVILEGED="${RUNNER__CONTAINER__PRIVILEGED:-false}" -RUNNER__CONTAINER__LABELS="${RUNNER__CONTAINER__LABELS:-}" -RUNNER__CONTAINER__VALID_VOLUMES="${RUNNER__CONTAINER__VALID_VOLUMES:-}" - # Show config variables decho "CONFIG: ${CONFIG_ARG}" @@ -60,8 +81,8 @@ decho "Using environment file: ${ENV_FILE}" # Set extra arguments from environment variables EXTRA_ARGS="" -if [[ -n "${RUNNER__CONTAINER__LABELS}" ]]; then - EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER__CONTAINER__LABELS}" +if [[ -n "${RUNNER__container__LABELS}" ]]; then + EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER__container__LABELS}" fi decho "EXTRA_ARGS: ${EXTRA_ARGS}" @@ -71,8 +92,8 @@ if [[ "${SKIP_WAIT}" != "true" ]]; then fi # Try to register the runner -if [[ ! -s "${RUNNER__RUNNER__FILE}" ]]; then - touch ${RUNNER__RUNNER__FILE} +if [[ ! -s "${RUNNER__runner__FILE}" ]]; then + touch ${RUNNER__runner__FILE} try=$((try + 1)) success=0 decho "try: ${try}, success: ${success}" diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 7ae268d..00a2c2f 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -78,20 +78,15 @@ services: FORGEJO_SECRET: "02f8e8ed1bd08d55338026d04b5513684ff23c1f" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN RUNNER_TOKEN: ${RUNNER_TOKEN} # token obtained from Forgejo web interface - RUNNER__CONFIG_FILE: config.yml # defaults to /data/config.yml - RUNNER__NAME: forgejo-runner # defaults to forgejo-runner - RUNNER__RUNNER__FILE: .runner # defaults to /data/runner.json - - RUNNER__CONTAINER__PRIVILEGED: "true" # defaults to false for security reasons - RUNNER__CONTAINER_OPTIONS: -v /certs/client:/certs/client:ro # needed for TLS - RUNNER__CONTAINER__DOCKER_HOST: "tcp://docker:2376" # defaults to "-", an available docker host will automatically be found - RUNNER__RUNNER__INSECURE: false - RUNNER__RUNNER__ENVS: | - DOCKER_HOST=tcp://docker:2376 - DOCKER_TLS_VERIFY=1 - DOCKER_CERT_PATH=/certs/client # defaults to empty - RUNNER__RUNNER__LABELS: | - "docker:docker://code.forgejo.org/oci/node:20-bookworm" - - DEBUG: "true" # defaults to false, set to true to enable debug logging in the entrypoint - SKIP_WAIT: "false" # defaults to false, set to true to skip the 10 second wait to allow for forgejo and docker-in-docker to start + DOCKER_HOST: tcp://docker:2376 + DOCKER_TLS_VERIFY: 1 + DOCKER_CERT_PATH: /certs/client + + RUNNER__log__LEVEL: "debug" + RUNNER__container__PRIVILEGED: "true" + RUNNER__runner__LABELS: | + docker:docker://code.forgejo.org/oci/node:20-bookworm + + DEBUG: "true" + SKIP_WAIT: "false" + SLEEP_DEBUG: "false" # toggles wether to sleep indefinitely after starting the runner diff --git a/internal/pkg/config/config-env.go b/internal/pkg/config/config-env.go index 0664df2..3937a62 100644 --- a/internal/pkg/config/config-env.go +++ b/internal/pkg/config/config-env.go @@ -5,6 +5,8 @@ import ( "strconv" "strings" "time" + + log "github.com/sirupsen/logrus" ) // loadEnvVars loads configuration settings from environment variables @@ -14,53 +16,59 @@ func loadEnvVars(config *Config) { // This implementation causes env-vars to override config file settings, // without writing to the config file. - // SkipEnv if variable is set - if _, ok := os.LookupEnv("RUNNER__SKIP_ENV"); ok { - return + if debug, ok := os.LookupEnv("DEBUG"); ok && debug == "true" { + log.SetLevel(log.DebugLevel) + log.Debug("Debug logging enabled") } // Log - loadEnvStr(config, "RUNNER__LOG__LEVEL", &config.Log.Level) - loadEnvStr(config, "RUNNER__LOG__JOB_LEVEL", &config.Log.JobLevel) + loadEnvStr(config, "RUNNER__log__LEVEL", &config.Log.Level) + loadEnvStr(config, "RUNNER__log__JOB_LEVEL", &config.Log.JobLevel) // Runner - loadEnvStr(config, "RUNNER__RUNNER__FILE", &config.Runner.File) - loadEnvInt(config, "RUNNER__RUNNER__CAPACITY", &config.Runner.Capacity) - loadEnvTable(config, "RUNNER__RUNNER__ENVS", &config.Runner.Envs) - loadEnvStr(config, "RUNNER__RUNNER__ENV_FILE", &config.Runner.EnvFile) - loadEnvDuration(config, "RUNNER__RUNNER__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) - loadEnvBool(config, "RUNNER__RUNNER__INSECURE", &config.Runner.Insecure) - loadEnvDuration(config, "RUNNER__RUNNER__FETCH_TIMEOUT", &config.Runner.FetchTimeout) - loadEnvDuration(config, "RUNNER__RUNNER__FETCH_INTERVAL", &config.Runner.FetchInterval) - loadEnvDuration(config, "RUNNER__RUNNER__REPORT_INTERVAL", &config.Runner.ReportInterval) - loadEnvList(config, "RUNNER__RUNNER__LABELS", &config.Runner.Labels) + loadEnvStr(config, "RUNNER__runner__FILE", &config.Runner.File) + loadEnvInt(config, "RUNNER__runner__CAPACITY", &config.Runner.Capacity) + loadEnvTable(config, "RUNNER__runner__ENVS", &config.Runner.Envs) + loadEnvStr(config, "RUNNER__runner__ENV_FILE", &config.Runner.EnvFile) + loadEnvDuration(config, "RUNNER__runner__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) + loadEnvBool(config, "RUNNER__runner__INSECURE", &config.Runner.Insecure) + loadEnvDuration(config, "RUNNER__runner__FETCH_TIMEOUT", &config.Runner.FetchTimeout) + loadEnvDuration(config, "RUNNER__runner__FETCH_INTERVAL", &config.Runner.FetchInterval) + loadEnvDuration(config, "RUNNER__runner__REPORT_INTERVAL", &config.Runner.ReportInterval) + loadEnvList(config, "RUNNER__runner__LABELS", &config.Runner.Labels) // Cache - loadEnvBool(config, "RUNNER__CACHE__ENABLED", config.Cache.Enabled) - loadEnvStr(config, "RUNNER__CACHE__DIR", &config.Cache.Dir) - loadEnvStr(config, "RUNNER__CACHE__HOST", &config.Cache.Host) - loadEnvUInt16(config, "RUNNER__CACHE__PORT", &config.Cache.Port) - loadEnvStr(config, "RUNNER__CACHE__EXTERNAL_SERVER", &config.Cache.ExternalServer) + loadEnvBool(config, "RUNNER__cache__ENABLED", config.Cache.Enabled) + loadEnvStr(config, "RUNNER__cache__DIR", &config.Cache.Dir) + loadEnvStr(config, "RUNNER__cache__HOST", &config.Cache.Host) + loadEnvUInt16(config, "RUNNER__cache__PORT", &config.Cache.Port) + loadEnvStr(config, "RUNNER__cache__EXTERNAL_SERVER", &config.Cache.ExternalServer) // Container - loadEnvStr(config, "RUNNER__CONTAINER__NETWORK", &config.Container.Network) - loadEnvStr(config, "RUNNER__CONTAINER__NETWORK_MODE", &config.Container.NetworkMode) - loadEnvBool(config, "RUNNER__CONTAINER__ENABLE_IPV6", &config.Container.EnableIPv6) - loadEnvBool(config, "RUNNER__CONTAINER__PRIVILEGED", &config.Container.Privileged) - loadEnvStr(config, "RUNNER__CONTAINER__OPTIONS", &config.Container.Options) - loadEnvStr(config, "RUNNER__CONTAINER__WORKDIR_PARENT", &config.Container.WorkdirParent) - loadEnvList(config, "RUNNER__CONTAINER__VALID_VOLUMES", &config.Container.ValidVolumes) - loadEnvStr(config, "RUNNER__CONTAINER__DOCKER_HOST", &config.Container.DockerHost) - loadEnvBool(config, "RUNNER__CONTAINER__FORCE_PULL", &config.Container.ForcePull) + loadEnvStr(config, "RUNNER__container__NETWORK", &config.Container.Network) + loadEnvStr(config, "RUNNER__container__NETWORK_MODE", &config.Container.NetworkMode) + loadEnvBool(config, "RUNNER__container__ENABLE_IPV6", &config.Container.EnableIPv6) + loadEnvBool(config, "RUNNER__container__PRIVILEGED", &config.Container.Privileged) + loadEnvStr(config, "RUNNER__container__OPTIONS", &config.Container.Options) + loadEnvStr(config, "RUNNER__container__WORKDIR_PARENT", &config.Container.WorkdirParent) + loadEnvList(config, "RUNNER__container__VALID_VOLUMES", &config.Container.ValidVolumes) + loadEnvStr(config, "RUNNER__container__DOCKER_HOST", &config.Container.DockerHost) + loadEnvBool(config, "RUNNER__container__FORCE_PULL", &config.Container.ForcePull) // Host - loadEnvStr(config, "RUNNER__HOST__WORKDIR_PARENT", &config.Host.WorkdirParent) + loadEnvStr(config, "RUNNER__host__WORKDIR_PARENT", &config.Host.WorkdirParent) } -// loadEnvStr loads an environment variable into the provided string pointer if it exists. +// General Coverage Docs for below: +// loadEnvType, where Type is the type of the variable being loaded, loads an environment variable into the provided pointer if the environment variable exists and is not empty. +// The key parameter is the environment variable key to look for. +// The dest parameter is a pointer to the variable to load the environment variable into. +// Config is present but unused, it remains for future use to prevent the need to redo the above functions. + func loadEnvStr(config *Config, key string, dest *string) { // Example: RUNNER__LOG__LEVEL = "info" if v := os.Getenv(key); v != "" { + log.Debug("Loading env var: ", key, "=", v) *dest = v } } @@ -70,6 +78,7 @@ func loadEnvInt(config *Config, key string, dest *int) { // Example: RUNNER__RUNNER__CAPACITY = "1" if v := os.Getenv(key); v != "" { if intValue, err := strconv.Atoi(v); err == nil { + log.Debug("Loading env var: ", key, "=", v) *dest = intValue } } @@ -80,6 +89,7 @@ func loadEnvUInt16(config *Config, key string, dest *uint16) { // Example: RUNNER__CACHE__PORT = "8080" if v := os.Getenv(key); v != "" { if uint16Value, err := strconv.ParseUint(v, 10, 16); err == nil { + log.Debug("Loading env var: ", key, "=", v) *dest = uint16(uint16Value) } } @@ -90,6 +100,7 @@ func loadEnvDuration(config *Config, key string, dest *time.Duration) { // Example: RUNNER__RUNNER__SHUTDOWN_TIMEOUT = "3h" if v := os.Getenv(key); v != "" { if durationValue, err := time.ParseDuration(v); err == nil { + log.Debug("Loading env var: ", key, "=", v) *dest = durationValue } } @@ -100,6 +111,7 @@ func loadEnvBool(config *Config, key string, dest *bool) { // Example: RUNNER__RUNNER__INSECURE = "false" if v := os.Getenv(key); v != "" { if boolValue, err := strconv.ParseBool(v); err == nil { + log.Debug("Loading env var: ", key, "=", v) *dest = boolValue } } @@ -123,6 +135,7 @@ func loadEnvTable(config *Config, key string, dest *map[string]string) { func loadEnvList(config *Config, key string, dest *[]string) { // Example: RUNNER__RUNNER__LABELS = "label1, label2, label3" if v := os.Getenv(key); v != "" { + log.Debug("Loading env var: ", key, "=", v) *dest = splitAndTrim(v) } } diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 0a4b548..80508de 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -173,5 +173,15 @@ func LoadDefault(file string) (*Config, error) { // Load environment variables at the end to allow for overriding the default values. loadEnvVars(cfg) + // Write the state of the config, including default values, to a debug file. + debugFile := file + ".debug.yml" + content, err := yaml.Marshal(cfg) + if err != nil { + return nil, fmt.Errorf("marshal config to debug file %q: %w", debugFile, err) + } + if err := os.WriteFile(debugFile, content, 0644); err != nil { + return nil, fmt.Errorf("write debug config file %q: %w", debugFile, err) + } + return cfg, nil } From f49abe6713e9534c3d23d073545300201e4f2579 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Fri, 27 Dec 2024 01:54:36 +0000 Subject: [PATCH 22/29] finally working? I just nuked the env-init... --- .dockerignore | 1 + entrypoint.sh | 31 +------------------ .../compose-forgejo-and-runner.yml | 9 +++--- 3 files changed, 7 insertions(+), 34 deletions(-) diff --git a/.dockerignore b/.dockerignore index 7b6d2b2..6df0bc1 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ Dockerfile forgejo-runner +/examples/docker-compose/srv/ \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh index 4a3425f..b96da5c 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -31,38 +31,9 @@ if [ "$#" -gt 0 ]; then fi # Set default values (if needed) -DEFAULT_DOCKER_HOST="tcp://docker:2376" -DEFAULT_DOCKER_TLS_VERIFY="1" -DEFAULT_DOCKER_CERT_PATH="/certs/client" - -# Ensure the variables are not empty by using explicit checks -DOCKER_HOST="${RUNNER__DOCKER_HOST:-${DOCKER_HOST:-${DEFAULT_DOCKER_HOST}}}" -DOCKER_TLS_VERIFY="${RUNNER__DOCKER_TLS_VERIFY:-${DOCKER_TLS_VERIFY:-${DEFAULT_DOCKER_TLS_VERIFY}}}" -DOCKER_CERT_PATH="${DOCKER_CERT_PATH:-${DEFAULT_DOCKER_CERT_PATH}}" - -RUNNER__container__DOCKER_HOST="${RUNNER__DOCKER_HOST:-${DOCKER_HOST:-${DEFAULT_DOCKER_HOST}}}" -RUNNER__runner__INSECURE="${RUNNER__DOCKER_TLS_VERIFY:-${DOCKER_TLS_VERIFY:-${DEFAULT_DOCKER_TLS_VERIFY}}}" - -RUNNER__container__NETWORK="${RUNNER__container__NETWORK:-host}" -RUNNER__container__OPTIONS="${RUNNER__container__OPTIONS:-} -v ${DOCKER_CERT_PATH}:${DOCKER_CERT_PATH}:ro" -RUNNER__container__VALID_VOLUMES="${RUNNER__container__VALID_VOLUMES:-} ${DOCKER_CERT_PATH}" -RUNNER__container__PRIVILEGED="${RUNNER__container__PRIVILEGED:-true}" - RUNNER__runner__FILE="${RUNNER__runner__FILE:-/data/runner.json}" +RUNNER__CONFIG_FILE="${RUNNER__CONFIG_FILE:-/data/runner.yml}" -decho "DOCKER_HOST: ${DOCKER_HOST}" -decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" -decho "DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" -decho "RUNNER__container__DOCKER_HOST: ${RUNNER__container__DOCKER_HOST}" -decho "RUNNER__runner__INSECURE: ${RUNNER__runner__INSECURE}" -decho "RUNNER__container__NETWORK: ${RUNNER__container__NETWORK}" -decho "RUNNER__container__OPTIONS: ${RUNNER__container__OPTIONS}" -decho "RUNNER__container__VALID_VOLUMES: ${RUNNER__container__VALID_VOLUMES}" -decho "RUNNER__container__PRIVILEGED: ${RUNNER__container__PRIVILEGED}" -decho "RUNNER__runner__FILE: ${RUNNER__runner__FILE}" - -# Use environment variables directly, with fallback defaults if not set -RUNNER__CONFIG_FILE="${RUNNER__CONFIG_FILE:-/data/config.yml}" ENV_FILE="${ENV_FILE:-/data/.env}" # Set config arguments CONFIG_ARG="--config ${RUNNER__CONFIG_FILE}" diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 00a2c2f..20f38a5 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -6,7 +6,7 @@ # # openssl rand -hex 20 # -# Replace all occurences of 02f8e8ed1bd08d55338026d04b5513684ff23c1f below with the output. +# Replace all occurences of {SHARED_SECRET} below with the output. # # NOTE: a token obtained from the Forgejo web interface cannot be used # as a shared secret. @@ -49,7 +49,7 @@ services: /bin/s6-svscan /etc/s6 & sleep 10 ; su -c "forgejo admin user create --admin --username root --password ROOT_PASSWORD --email root@example.com" git ; - su -c "forgejo forgejo-cli actions register --secret 02f8e8ed1bd08d55338026d04b5513684ff23c1f" git ; + su -c "forgejo forgejo-cli actions register --secret {SHARED_SECRET}" git ; sleep infinity ' @@ -75,13 +75,15 @@ services: - docker-in-docker environment: FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 - FORGEJO_SECRET: "02f8e8ed1bd08d55338026d04b5513684ff23c1f" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN + FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN RUNNER_TOKEN: ${RUNNER_TOKEN} # token obtained from Forgejo web interface + # Docker Daemon Configs, needed for docker-in-docker DOCKER_HOST: tcp://docker:2376 DOCKER_TLS_VERIFY: 1 DOCKER_CERT_PATH: /certs/client + # Runner Configs RUNNER__log__LEVEL: "debug" RUNNER__container__PRIVILEGED: "true" RUNNER__runner__LABELS: | @@ -89,4 +91,3 @@ services: DEBUG: "true" SKIP_WAIT: "false" - SLEEP_DEBUG: "false" # toggles wether to sleep indefinitely after starting the runner From fb8d824fd89ed59a633cdb1828f5fcead8defc80 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Fri, 27 Dec 2024 02:06:50 +0000 Subject: [PATCH 23/29] BEGONE: LINKS --- examples/docker-compose/compose-forgejo-and-runner.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 20f38a5..0b8ccfb 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -70,9 +70,6 @@ services: depends_on: - docker-in-docker - forgejo - links: - - forgejo - - docker-in-docker environment: FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN From 6d10f57eaa71217f7e091efc2f5e8d71b994a3bd Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Fri, 27 Dec 2024 13:07:42 +0100 Subject: [PATCH 24/29] chore(docs): 6.0.0 release notes --- RELEASE-NOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index e7f7ae4..b28f9ad 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,9 @@ # Release Notes +## 6.0.0 + +* Security: the container options a job is allowed to specify are limited to a [predefined allow list](https://forgejo.org/docs/next/user/actions/#jobsjob_idcontaineroptions). + ## 5.0.4 * Define FORGEJO_TOKEN as an alias to GITHUB_TOKEN From ac39fa200687beca530474558ceb90ca1f0a60f9 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Fri, 27 Dec 2024 23:20:38 +0000 Subject: [PATCH 25/29] hailmary commit --- entrypoint.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index b96da5c..7eea913 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -62,6 +62,8 @@ if [[ "${SKIP_WAIT}" != "true" ]]; then sleep 10 fi +FORGEJO_URL="${FORGEJO_URL:-http://forgejo:3000}" + # Try to register the runner if [[ ! -s "${RUNNER__runner__FILE}" ]]; then touch ${RUNNER__runner__FILE} @@ -72,14 +74,14 @@ if [[ ! -s "${RUNNER__runner__FILE}" ]]; then while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do if [[ -n "${FORGEJO_SECRET}" ]]; then run_command forgejo-runner create-runner-file --connect \ - --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --instance "${FORGEJO_URL}" \ --name "${RUNNER__NAME:-$(hostname)}" \ --secret "${FORGEJO_SECRET}" \ ${CONFIG_ARG} \ ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log else run_command forgejo-runner register \ - --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --instance "${FORGEJO_URL}" \ --name "${RUNNER__NAME:-$(hostname)}" \ --token "${RUNNER_TOKEN}" \ --no-interactive \ From 80ad55ad5652e72d8178b2b7b75826b8636a14f4 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Fri, 27 Dec 2024 23:32:31 +0000 Subject: [PATCH 26/29] docker networking, force local network --- examples/docker-compose/compose-forgejo-and-runner.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 0b8ccfb..0eb9b44 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -18,12 +18,17 @@ volumes: docker_certs: +networks: + forgejo: + services: docker-in-docker: image: code.forgejo.org/oci/docker:dind hostname: docker # Must set hostname for both internal DNS and TLS to work as certs are only valid for docker and localhost restart: unless-stopped privileged: true + networks: + - forgejo environment: DOCKER_TLS_CERTDIR: "/certs" # set to "" to disable the use of TLS, also manually update existing runner configs to use port 2375 DOCKER_HOST: "docker" # remove aswell to disable TLS @@ -33,6 +38,8 @@ services: forgejo: image: codeberg.org/forgejo/forgejo:1.21 hostname: forgejo + networks: + - forgejo volumes: - /srv/forgejo-data:/data ports: @@ -64,6 +71,8 @@ services: build: ../../ user: "1000" # defaults to 1000, restart: unless-stopped # needed for fixing file ownership on restart + networks: + - forgejo volumes: - /srv/runner-data:/data - docker_certs:/certs From 93beacdfe6ce32964fd1ebcf6e6b7f54e0c9b4a1 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Fri, 27 Dec 2024 23:42:08 +0000 Subject: [PATCH 27/29] Revert "docker networking, force local network" This reverts commit 80ad55ad5652e72d8178b2b7b75826b8636a14f4. --- examples/docker-compose/compose-forgejo-and-runner.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 0eb9b44..0b8ccfb 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -18,17 +18,12 @@ volumes: docker_certs: -networks: - forgejo: - services: docker-in-docker: image: code.forgejo.org/oci/docker:dind hostname: docker # Must set hostname for both internal DNS and TLS to work as certs are only valid for docker and localhost restart: unless-stopped privileged: true - networks: - - forgejo environment: DOCKER_TLS_CERTDIR: "/certs" # set to "" to disable the use of TLS, also manually update existing runner configs to use port 2375 DOCKER_HOST: "docker" # remove aswell to disable TLS @@ -38,8 +33,6 @@ services: forgejo: image: codeberg.org/forgejo/forgejo:1.21 hostname: forgejo - networks: - - forgejo volumes: - /srv/forgejo-data:/data ports: @@ -71,8 +64,6 @@ services: build: ../../ user: "1000" # defaults to 1000, restart: unless-stopped # needed for fixing file ownership on restart - networks: - - forgejo volumes: - /srv/runner-data:/data - docker_certs:/certs From 28568735d3da8b3bc14339209b64ff23e3ac8e06 Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Sat, 28 Dec 2024 00:28:17 +0000 Subject: [PATCH 28/29] restore links, set `ubuntu-22.04` runner label --- examples/docker-compose/compose-forgejo-and-runner.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/docker-compose/compose-forgejo-and-runner.yml b/examples/docker-compose/compose-forgejo-and-runner.yml index 0b8ccfb..3c3ae0d 100644 --- a/examples/docker-compose/compose-forgejo-and-runner.yml +++ b/examples/docker-compose/compose-forgejo-and-runner.yml @@ -70,6 +70,9 @@ services: depends_on: - docker-in-docker - forgejo + links: + - docker-in-docker + - forgejo environment: FORGEJO_URL: ${FORGEJO_URL} # defaults to http://forgejo:3000 FORGEJO_SECRET: "{SHARED_SECRET}" # shared secret, must match Forgejo's, overrides RUNNER_TOKEN @@ -85,6 +88,6 @@ services: RUNNER__container__PRIVILEGED: "true" RUNNER__runner__LABELS: | docker:docker://code.forgejo.org/oci/node:20-bookworm - + ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04 DEBUG: "true" SKIP_WAIT: "false" From 8f9e81272e0b48f579ce3f6f1a13b4d8b0a0f4cb Mon Sep 17 00:00:00 2001 From: Merith-TK Date: Sat, 28 Dec 2024 00:41:22 +0000 Subject: [PATCH 29/29] add some names to the demo workflow --- examples/docker-compose/compose-demo-workflow.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/docker-compose/compose-demo-workflow.yml b/examples/docker-compose/compose-demo-workflow.yml index da419bf..844dbdc 100644 --- a/examples/docker-compose/compose-demo-workflow.yml +++ b/examples/docker-compose/compose-demo-workflow.yml @@ -7,6 +7,8 @@ services: image: code.forgejo.org/oci/alpine:3.19 links: - forgejo + depends_on: + - runner-daemon command: >- sh -ec ' apk add --quiet git curl jq ; @@ -14,8 +16,8 @@ services: cd /srv/demo ; git init --initial-branch=main ; mkdir -p .forgejo/workflows ; - echo "{ on: [push], jobs: { test: { runs-on: docker, steps: [ {uses: actions/checkout@v4}, { run: echo All Good } ] } } }" > .forgejo/workflows/demo.yml ; - echo "{ on: [push], jobs: { test_docker: { runs-on: ubuntu-22.04, steps: [ { run: docker info } ] } } }" > .forgejo/workflows/demo_docker.yml ; + echo "{ name: \"Demo All Good\", on: [push], jobs: { test: { runs-on: docker, steps: [ {uses: actions/checkout@v4}, { run: echo All Good } ] } } }" > .forgejo/workflows/demo.yml ; + echo "{ name: \"Demo Docker\", on: [push], jobs: { test_docker: { runs-on: ubuntu-22.04, steps: [ { run: docker info } ] } } }" > .forgejo/workflows/demo_docker.yml ; git add . ; git config user.email root@example.com ; git config user.name username ;