diff --git a/README.md b/README.md index 5b6391f..52b8882 100644 --- a/README.md +++ b/README.md @@ -41,19 +41,53 @@ services: TZ: "Europe/Berlin" # config parameters for initial runner registration: GITEA_INSTANCE_URL: 'https://gitea.example.com' # required - GITEA_INSTANCE_INSECURE: '0' # optional, default is 0 - GITEA_RUNNER_REGISTRATION_TOKEN_FILE: 'path/to/file' # only required on first container start + GITEA_RUNNER_REGISTRATION_TOKEN_FILE: 'path/to/file' # one-time registration token, only required on first container start # or: GITEA_RUNNER_REGISTRATION_TOKEN: '' - GITEA_RUNNER_NAME: 'my-act-runner.example.com' # optional, defaults to the container's hostname - GITEA_RUNNER_LABELS: '' # optional - GITEA_RUNNER_UID: 1200 # optional, default is 1000 - GITEA_RUNNER_GID: 1200 # optional, default is 1000 deploy: restart_policy: condition: on-failure delay: 5s ``` +### Additional environment variables + +The following environment variables can be specified to further configure the service. + +#### Runner registration: +Name|Default Value|Description +----|-------------|----------- +GITEA_INSTANCE_INSECURE|`false`|It `true` don't verify the TLS certificate of the Gitea instance +GITEA_RUNNER_NAME|``|If not specified the container's hostname is used +GITEA_RUNNER_LABELS|``|Comma-separated list of labels (e.g. `ubuntu-20.04:docker://node:16-bullseye,ubuntu-18.04:docker://node:16-buster,linux_arm:host`) If not specified default labels are used. +GITEA_RUNNER_REGISTRATION_FILE|`/data/.runner`|The JSON file that holds the result from the runner registration with the Gitea instance. +GITEA_RUNNER_REGISTRATION_TIMEOUT|`30`|In case of failure, registration is retried until this timeout in seconds is reached. +GITEA_RUNNER_REGISTRATION_RETRY_INTERVAL|`5`|Wait period in seconds between registration retries. + +#### Runner runtime config: + +Name|Default Value|Description +----|-------------|----------- +GITEA_RUNNER_CONFIG_TEMPLATE_FILE|`/opt/config.template.yaml`|Template to derive the effective config file from, see [image/config.template.yaml](image/config.template.yaml) +GITEA_RUNNER_UID|`1000`|The UID of the Gitea runner process +GITEA_RUNNER_GID|`1000`|The GID of the Gitea runner process +GITEA_RUNNER_LOG_LEVEL|`info`|The level of logging, can be trace, debug, info, warn, error, fatal +GITEA_RUNNER_ENV_FILE|`/data/.env`|Extra environment variables to run jobs from a file. +GITEA_RUNNER_FETCH_TIMEOUT|`5s`|The timeout for fetching the job from the Gitea instance. +GITEA_RUNNER_FETCH_INTERVAL|`2s`|The interval for fetching the job from the Gitea instance. +GITEA_RUNNER_MAX_PARALLEL_JOBS|`1`|Maximum number of concurrently executed jobs +GITEA_RUNNER_JOB_NETWORK|`bridge`|Docker network to use with job containers. Can be `bridge`, `host`, `none`, or the name of a custom network. +GITEA_RUNNER_JOB_TIMEOUT|`3h`|The maximum time a job can run before it is cancelled. +GITEA_RUNNER_ENV_VAR_**N**_NAME|`none`|Name of the **N**-th extra environment variable to be passed to Job containers, e.g. `GITEA_RUNNER_ENV_VAR_1_NAME=MY_AUTH_TOKEN` +GITEA_RUNNER_ENV_VAR_**N**_VALUE|``|Value of the **N**-th extra environment variable to be passed to Job containers, e.g. `GITEA_RUNNER_ENV_VAR_1_VALUE=SGVsbG8gbXkgZnJpZW5kIQ==` +GITEA_RUNNER_ACTION_CACHE_DIR|`/data/cache/actions`|Path to cache cloned actions. + +#### Embedded cache server: +Name|Default Value|Description +----|-------------|----------- +ACT_CACHE_SERVER_ENABLED|`true`| Enable the embedded cache service to use `actions/cache` in jobs. +ACT_CACHE_SERVER_DIR|`/data/cache/server`| The directory to store the cache data. +ACT_CACHE_SERVER_HOST|``| The IP address or hostname via which the job containers can reach the cache server. Leave empty for automatic detection. +ACT_CACHE_SERVER_PORT|`0`|The TCP port of the cache server. `0` means to use a random, available port. ## License diff --git a/image/Dockerfile b/image/Dockerfile index 2f90d56..6f3a0b5 100644 --- a/image/Dockerfile +++ b/image/Dockerfile @@ -127,11 +127,33 @@ LABEL \ ENV \ INIT_SH_FILE='' \ # + GITEA_RUNNER_CONFIG_TEMPLATE_FILE='/opt/config.template.yaml' \ + # GITEA_RUNNER_NAME='' \ GITEA_RUNNER_LABELS='' \ - GITEA_INSTANCE_INSECURE=0 \ GITEA_RUNNER_UID=1000 \ - GITEA_RUNNER_GID=1000 + GITEA_RUNNER_GID=1000 \ + # + GITEA_RUNNER_REGISTRATION_FILE='/data/.runner' \ + GITEA_RUNNER_REGISTRATION_TIMEOUT=30\ + GITEA_RUNNER_REGISTRATION_RETRY_INTERVAL=5s \ + # + GITEA_RUNNER_LOG_LEVEL='info' \ + GITEA_RUNNER_MAX_PARALLEL_JOBS=1 \ + GITEA_RUNNER_JOB_TIMEOUT='3h' \ + GITEA_RUNNER_ENV_FILE='/data/.env' \ + GITEA_RUNNER_FETCH_TIMEOUT='5s' \ + GITEA_RUNNER_FETCH_INTERVAL='2s' \ + # + GITEA_INSTANCE_INSECURE='false' \ + # + GITEA_RUNNER_JOB_NETWORK='bridge' \ + GITEA_RUNNER_ACTION_CACHE_DIR='/data/cache/actions' \ + # + ACT_CACHE_SERVER_ENABLED='true' \ + ACT_CACHE_SERVER_DIR='/data/cache/server' \ + ACT_CACHE_SERVER_HOST='' \ + ACT_CACHE_SERVER_PORT=0 RUN </opt/build_info EOF COPY image/*.sh /opt/ +COPY image/config.template.yaml /opt/ COPY .shared/lib/bash-init.sh /opt/bash-init.sh USER act diff --git a/image/config.template.yaml b/image/config.template.yaml new file mode 100644 index 0000000..1ccab90 --- /dev/null +++ b/image/config.template.yaml @@ -0,0 +1,50 @@ +log: + level: ${GITEA_RUNNER_LOG_LEVEL:-info} # The level of logging, can be trace, debug, info, warn, error, fatal + +runner: + # Where to store the registration result. + file: '${GITEA_RUNNER_REGISTRATION_FILE:-/data/.runner}' + # Execute how many tasks concurrently at the same time. + capacity: ${GITEA_RUNNER_MAX_PARALLEL_JOBS:-1} + # Extra environment variables to run jobs. + envs: + ${GITEA_RUNNER_ENV_VAR_1_NAME:-GITEA_RUNNER_ENV_VAR_1}: '${GITEA_RUNNER_ENV_VAR_1_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_2_NAME:-GITEA_RUNNER_ENV_VAR_2}: '${GITEA_RUNNER_ENV_VAR_2_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_3_NAME:-GITEA_RUNNER_ENV_VAR_3}: '${GITEA_RUNNER_ENV_VAR_3_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_4_NAME:-GITEA_RUNNER_ENV_VAR_4}: '${GITEA_RUNNER_ENV_VAR_4_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_5_NAME:-GITEA_RUNNER_ENV_VAR_5}: '${GITEA_RUNNER_ENV_VAR_5_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_6_NAME:-GITEA_RUNNER_ENV_VAR_6}: '${GITEA_RUNNER_ENV_VAR_6_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_7_NAME:-GITEA_RUNNER_ENV_VAR_7}: '${GITEA_RUNNER_ENV_VAR_7_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_8_NAME:-GITEA_RUNNER_ENV_VAR_8}: '${GITEA_RUNNER_ENV_VAR_8_VALUE:-}' + ${GITEA_RUNNER_ENV_VAR_9_NAME:-GITEA_RUNNER_ENV_VAR_9}: '${GITEA_RUNNER_ENV_VAR_9_VALUE:-}' + # Extra environment variables to run jobs from a file. + # It will be ignored if it's empty or the file doesn't exist. + env_file: '${GITEA_RUNNER_ENV_FILE:-/data/.env}' + # The timeout for a job to be finished. + # Please note that the Gitea instance also has a timeout (3h by default) for the job. + # So the job could be stopped by the Gitea instance if it's timeout is shorter than this. + timeout: '${GITEA_JOB_TIMEOUT:-3h}' + # Whether skip verifying the TLS certificate of the Gitea instance. + insecure: ${GITEA_INSTANCE_INSECURE:-false} + # The timeout for fetching the job from the Gitea instance. + fetch_timeout: '${GITEA_RUNNER_FETCH_TIMEOUT:-5s}' + # The interval for fetching the job from the Gitea instance. + fetch_interval: '${GITEA_RUNNER_FETCH_INTERVAL:-2s}' + +cache: + # Enable cache server to use actions/cache. + enabled: ${ACT_CACHE_SERVER_ENABLED:-true} + # The directory to store the cache data. + # If it's empty, the cache data will be stored in $HOME/.cache/actcache. + dir: '${ACT_CACHE_SERVER_DIR:-/data/cache/server}' + # The host of the cache server. + # It's not for the address to listen, but the address to connect from job containers. + # So 0.0.0.0 is a bad choice, leave it empty to detect automatically. + host: '${ACT_CACHE_SERVER_HOST:-}' + # The port of the cache server. + # 0 means to use a random available port. + port: ${ACT_CACHE_SERVER_PORT:-0} + +container: + # Which network to use for the job containers. Could be bridge, host, none, or the name of a custom network. + network_mode: ${GITEA_RUNNER_JOB_NETWORK:-bridge} diff --git a/image/run_runner.sh b/image/run_runner.sh index f6d8b6e..72de76b 100644 --- a/image/run_runner.sh +++ b/image/run_runner.sh @@ -14,33 +14,78 @@ cd /data ################################################# # load custom init script if specified ################################################# -if [[ -f $INIT_SH_FILE ]]; then +if [[ -f "$INIT_SH_FILE" ]]; then log INFO "Loading [$INIT_SH_FILE]..." source "$INIT_SH_FILE" fi +################################################# +# set cache config +################################################# +# workaround for actions cache dir not being fully configurable +# https://gitea.com/gitea/act/src/commit/62abf4fe116865f6edf85d6bce822050dd01ac78/pkg/runner/run_context.go#L360-L371 +mkdir -p $GITEA_RUNNER_ACTION_CACHE_DIR +mkdir -p /tmp/.cache +ln -s $GITEA_RUNNER_ACTION_CACHE_DIR /tmp/.cache/act +export XDG_CACHE_HOME=/tmp/.cache + + +################################################# +# render config file +################################################# +effective_config_file=/tmp/gitae_act_runner_config.yml +rm -f "$effective_config_file" +if [[ ${GITEA_RUNNER_LOG_EFFECTIVE_CONFIG:-false} == "true" ]]; then + log INFO "Effective runner config [$effective_config_file]:" + while IFS= read -r line; do + line=${line//\"/\\\"} # escape double quotes + eval "echo \"$line\"" | tee -a "$effective_config_file" + done < $GITEA_RUNNER_CONFIG_TEMPLATE_FILE + echo +else + while IFS= read -r line; do + line=${line//\"/\\\"} # escape double quotes + eval "echo \"$line\"" >> "$effective_config_file" + done < $GITEA_RUNNER_CONFIG_TEMPLATE_FILE +fi + + ################################################# # register act runner if required ################################################# if [[ ! -s .runner ]]; then - if [[ ${GITEA_INSTANCE_INSECURE:-} == '1' ]]; then - insecure_flag=--insecure - fi if [[ -z ${GITEA_RUNNER_REGISTRATION_TOKEN:-} ]]; then read -r GITEA_RUNNER_REGISTRATION_TOKEN < "$GITEA_RUNNER_REGISTRATION_TOKEN_FILE" fi - act_runner register \ - --instance "${GITEA_INSTANCE_URL}" \ - --token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \ - --name "${GITEA_RUNNER_NAME}" \ - --labels "${GITEA_RUNNER_LABELS}" \ - $( [[ ${GITEA_INSTANCE_INSECURE:-} == '1' ]] && echo "--insecure" || true) \ - --no-interactive + + wait_until=$(( $(date +%s) + $GITEA_RUNNER_REGISTRATION_TIMEOUT )) + while true; do + if act_runner register \ + --instance "$GITEA_INSTANCE_URL" \ + --token "$GITEA_RUNNER_REGISTRATION_TOKEN" \ + --name "$GITEA_RUNNER_NAME" \ + --labels "$GITEA_RUNNER_LABELS" \ + --config "$effective_config_file" \ + --no-interactive; then + break; + fi + if [ "$(date +%s)" -ge $wait_until ]; then + log ERROR "Runner registration failed." + exit 1 + fi + sleep "$GITEA_RUNNER_REGISTRATION_RETRY_INTERVAL" + done fi +################################################# +# unset all variables named GITEA_... to prevent deprecation warning +################################################# +unset $(env | grep "^GITEA_" | cut -d= -f1) + + ################################################# # run the act runner ################################################# -exec act_runner daemon +exec act_runner daemon --config "$effective_config_file"