Years ago I moved most of my private code to a self-hosted Gitea instance. I liked it, but I always found it odd that the project itself does not use Gitea for its development but GitHub. Fast-forward a few years and a fork of Gitea Forgejo was born, and they do use their own product for development. Forgejo is developed by a non-profit whereas Gitea is not, and I really like their aproach to running an open source product. So a month ago I finally got around to migrate to Forgejo.
Forgejo-runner Do Not Show Up In Forgejo#
With Gitea I used DroneCI for CICD because when I set it up that was the only viable option. Forgejo and Gitea now have its own CICD system that works much like GitHubs CICD system. So, I wanted to use that and installed the Forgejo-runner from the TrueNAS appstore. But, the runner would not show up in Forgejo. It took a while for me to figure out why. The reason it does not show up in Forgejo is because it is not on the same docker network. In order to get it on the same network a setting in the Forgejo-runner config.yml has to be changed. But, there in lies the problem. The TrueNAS app is not setup to use the config file.
Make It Use The Config#
So, I had to install it via Docker compose.
Luckly, this is very easy as TrueNAS has the option to convert an existing app to docker compose via the Edit/Convert to custom app
option on the app.
Now we just have to tell Forgejo-runner to use the config.yml by changing forgejo-runner daemon
to forgejo-runner -c config.yml daemon
The full Docker compose is at the end.
Make a copy of the config.yml from https://forgejo.org/docs/latest/admin/actions/runner-installation/ and put it in the data directory or run forgejo-runner generate-config > config.yml
from within the dockercontainer.
Open the config.yml and find the setting
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, create a network automatically.
network: ""
Here add host to network network: "host"
then save and restart the app.
The Forgejo-runner should show up in Forgejo now.
Happy coding!
The Docker Compose#
configs:
entrypoint:
content: |
if [ ! -f /data/.runner ]; then
echo "Registering the runner"
forgejo-runner register \
--no-interactive \
--name runner \
--instance <URL> \
--token <TOKEN> || { echo "Runner failed to register"; exit 1; }
echo "Runner registered successfully"
else
echo "Runner register file [/data/.runner] already exists"
echo "Skipping registration"
echo "If you want to re-register the runner, please delete the file /data/.runner"
fi
echo "\n\n"
echo "Starting the runner"
forgejo-runner -c config.yml daemon
exit 0
services:
forgejo-runner:
image: data.forgejo.org/forgejo/runner:11
cap_drop:
- ALL
configs:
- mode: 493
source: entrypoint
target: /ix-entrypoint.sh
deploy:
resources:
limits:
cpus: '2'
memory: 4096M
entrypoint:
- /bin/sh
- '-c'
- /ix-entrypoint.sh
environment:
GID: '568'
GROUP_ID: '568'
NVIDIA_VISIBLE_DEVICES: void
PGID: '568'
PUID: '568'
TZ: Europe/Copenhagen
UID: '568'
UMASK: '002'
UMASK_SET: '002'
USER_ID: '568'
dns: 192.168.2.200
extra_hosts:
host.docker.internal: host-gateway
group_add:
- 568
- 999
healthcheck:
interval: 30s
retries: 5
start_interval: 2s
start_period: 15s
test: pgrep forgejo-runner
timeout: 5s
network_mode: host
platform: linux/amd64
privileged: False
restart: unless-stopped
security_opt:
- no-new-privileges=true
stdin_open: False
tty: False
user: '568:568'
volumes:
- bind:
create_host_path: False
propagation: rprivate
read_only: False
source: /mnt/dockerdata/forgejorunner/data
target: /data
type: bind
- bind:
create_host_path: False
propagation: rprivate
read_only: False
source: /var/run/docker.sock
target: /var/run/docker.sock
type: bind
volumes: {}
x-notes: >+
# Forgejo Runner
## Bug Reports and Feature Requests
If you find a bug in this app or have an idea for a new feature, please file
an issue at
https://github.com/truenas/apps
x-portals: []
The Config#
# Example configuration file, it's safe to copy this as the default config file without any modification.
# You don't have to copy this file to your instance,
# just run `forgejo-runner generate-config > config.yaml` to generate a config file.
#
# The value of level or job_level can be trace, debug, info, warn, error or fatal
#
log:
#
# What is displayed in the output of the runner process but not sent
# to the Forgejo instance.
#
level: info
#
# What is sent to the Forgejo instance and therefore
# visible in the web UI for a given job.
#
job_level: info
runner:
# Where to store the registration result.
file: .runner
# Execute how many tasks concurrently at the same time.
capacity: 1
# Extra environment variables to run jobs.
envs:
A_TEST_ENV_NAME_1: a_test_env_value_1
A_TEST_ENV_NAME_2: a_test_env_value_2
# 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: .env
# The timeout for a job to be finished.
# Please note that the Forgejo instance also has a timeout (3h by default) for the job.
# So the job could be stopped by the Forgejo instance if it's timeout is shorter than this.
timeout: 3h
# The timeout for the runner to wait for running jobs to finish when
# shutting down because a TERM or INT signal has been received. Any
# running jobs that haven't finished after this timeout will be
# cancelled.
# If unset or zero the jobs will be cancelled immediately.
shutdown_timeout: 3h
# Whether skip verifying the TLS certificate of the instance.
insecure: false
# The timeout for fetching the job from the Forgejo instance.
fetch_timeout: 5s
# The interval for fetching the job from the Forgejo instance.
fetch_interval: 2s
# The interval for reporting the job status and logs to the Forgejo instance.
report_interval: 1s
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
# Like: ["macos-arm64:host", "ubuntu-latest:docker://node:20-bookworm", "ubuntu-22.04:docker://node:20-bookworm"]
# If it's empty when registering, it will ask for inputting labels.
# If it's empty when executing the `daemon`, it will use labels in the `.runner` file.
labels: []
cache:
#
# When enabled, workflows will be given the ACTIONS_CACHE_URL environment variable
# used by the https://code.forgejo.org/actions/cache action. The server at this
# URL must implement a compliant REST API and it must also be reachable from
# the container or host running the workflows.
#
# See also https://forgejo.org/docs/next/user/actions/advanced-features/#cache
#
# When it is not enabled, none of the following options apply.
#
# It works as follows:
#
# - the workflow is given a one time use ACTIONS_CACHE_URL
# - a cache proxy listens to ACTIONS_CACHE_URL
# - the cache proxy securely communicates with the cache server using
# a shared secret
#
enabled: true
#
#######################################################################
#
# Only used for the internal cache server.
#
# If external_server is not set, the Forgejo runner will spawn a
# cache server that will be used by the cache proxy.
#
#######################################################################
#
# The port bound by the internal cache server.
# 0 means to use a random available port.
#
port: 0
#
# The directory to store the cache data.
#
# If empty, the cache data will be stored in $HOME/.cache/actcache.
#
dir: ""
#
#######################################################################
#
# Only used for the external cache server.
#
# If external_server is set, the internal cache server is not
# spawned.
#
#######################################################################
#
# The URL of the cache server. The URL should generally end with
# "/". The cache proxy will forward requests to the external
# server. The requests are authenticated with the "secret" that is
# shared with the external server.
#
external_server: ""
#
# The shared cache secret used to secure the communications between
# the cache proxy and the cache server.
#
# If empty, it will be generated to a new secret automatically when
# the server starts and it will stay the same until it restarts.
#
secret: ""
#
#######################################################################
#
# Common to the internal and external cache server
#
#######################################################################
#
# The IP or hostname (195.84.20.30 or example.com) to use when constructing
# ACTIONS_CACHE_URL which is the URL of the cache proxy.
#
# If empty it will be detected automatically.
#
# If the containers or host running the workflows reside on a
# different network than the Forgejo runner (for instance when the
# docker server used to create containers is not running on the same
# host as the Forgejo runner), it may be impossible to figure that
# out automatically. In that case you can specifify which IP or
# hostname to use to reach the internal cache server created by the
# Forgejo runner.
#
host: ""
#
# The port bound by the internal cache proxy.
# 0 means to use a random available port.
#
proxy_port: 0
#
# Overrides the ACTIONS_CACHE_URL variable passed to workflow
# containers. The URL should generally not end with "/". This should only
# be used if the runner host is not reachable from the workflow containers,
# and requires further setup.
#
actions_cache_url_override: ""
container:
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, create a network automatically.
network: "host"
# Whether to create networks with IPv6 enabled. Requires the Docker daemon to be set up accordingly.
# Only takes effect if "network" is set to "".
enable_ipv6: false
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
privileged: false
# And other options to be used when the container is started (eg, --volume /etc/ssl/certs:/etc/ssl/certs:ro).
options:
# The parent directory of a job's working directory.
# If it's empty, /workspace will be used.
workdir_parent:
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
# valid_volumes:
# - data
# - /etc/ssl/certs
# If you want to allow any volume, please use the following configuration:
# valid_volumes:
# - '**'
valid_volumes: []
# overrides the docker client host with the specified one.
# If "-" or "", an available docker host will automatically be found.
# If "automount", an available docker host will automatically be found and mounted in the job container (e.g. /var/run/docker.sock).
# Otherwise the specified docker host will be used and an error will be returned if it doesn't work.
docker_host: "-"
# Pull docker image(s) even if already present
force_pull: false
# Rebuild local docker image(s) even if already present
force_rebuild: false
host:
# The parent directory of a job's working directory.
# If it's empty, $HOME/.cache/act/ will be used.
workdir_parent: