1
0
Fork 0

feat(forgejo-runner): add docker mode selection and refactor configuration with updated documentation

- Add new `DOCKER_MODE` form field to choose between `dood` and `dind` modes, removing old `PRIVILEGED` mode field and `-dind` variant application
- Update `docker-compose.yml` to conditionally include `dind` service based on mode, and refactor `init.sh` to dynamically set `DOCKER_HOST` environment variable
- Refactor `register.sh` to handle both modes, configure runner accordingly, update default values for registration fields, and define the default job container base image as node:lts
- Update README with detailed security risk warnings for both modes, remove version selection instructions, and add usage examples for custom container images and installing docker client in workflows
This commit is contained in:
pooneyy 2026-02-04 14:38:22 +08:00
parent f669dfd23f
commit 7080624537
No known key found for this signature in database
10 changed files with 200 additions and 254 deletions

View File

@ -1,85 +0,0 @@
additionalProperties:
formFields:
- default: "false"
edit: true
envKey: PRIVILEGED
labelEn: "Privilege Mode: Manually enabled for permission issues"
labelZh: "特权模式: 遇到权限问题时手动启用"
label:
en: Privilege Mode
zh: 特权模式
description:
en: Manually enabled for permission issues
zh: 遇到权限问题时手动启用
required: false
type: select
values:
- label: "启用 Enabled"
value: "true"
- label: "禁用 Disabled"
value: "false"
- default: http://1.2.3.4:3000
edit: true
envKey: FORGEJO_INSTANCE_URL
labelEn: Forgejo Instance
labelZh: Forgejo 实例
required: true
rule: paramExtUrl
type: text
label:
en: Forgejo Instance
ja: Forgejo インスタンス
ms: Instans Forgejo
pt-br: Instância Forgejo
ru: Экземпляр Forgejo
ko: Forgejo 인스턴스
zh-Hant: Forgejo 實例
zh: Forgejo 实例
- default: '<registration_token>'
edit: true
envKey: RUNNER_REGISTRATION_TOKEN
labelEn: Registration Token
labelZh: 注册令牌
required: true
type: text
label:
en: Registration Token
ja: 登録トークン
ms: Token Pendaftaran
pt-br: Token de Registro
ru: Токен регистрации
ko: 등록 토큰
zh-Hant: 註冊令牌
zh: 注册令牌
- default: '<runner_name>'
edit: true
envKey: RUNNER_NAME
labelEn: Runner Name
labelZh: 运行器名称
required: true
type: text
label:
en: Runner Name
ja: ランナー名
ms: Nama Pelari
pt-br: Nome do Runner
ru: Имя бегуна
ko: 러너 이름
zh-Hant: 執行器名稱
zh: 运行器名称
- default: '<runner_labels>'
edit: true
envKey: RUNNER_LABELS
labelEn: Runner Labels
labelZh: 运行器标签
required: true
type: text
label:
en: Runner Labels
ja: ランナータグ
ms: Label Pelari
pt-br: Rótulos do Runner
ru: Метки бегуна
ko: 러너 레이블
zh-Hant: 執行器標籤
zh: 运行器标签

View File

@ -1,43 +0,0 @@
services:
forgejo-runner:
image: code.forgejo.org/forgejo/runner:12.6.3
container_name: ${CONTAINER_NAME}
depends_on:
dind:
condition: service_started
links:
- dind
restart: always
user: 1000:1000
command: /data/scripts/register.sh
volumes:
- ./data/runner-data:/data
- ./scripts/register.sh:/data/scripts/register.sh:ro
environment:
- DOCKER_HOST=tcp://dind:2375
- FORGEJO_INSTANCE_URL=${FORGEJO_INSTANCE_URL}
- RUNNER_REGISTRATION_TOKEN=${RUNNER_REGISTRATION_TOKEN}
- RUNNER_NAME=${RUNNER_NAME}
- RUNNER_LABELS=${RUNNER_LABELS}
networks:
- 1panel-network
labels:
createdBy: Apps
dind:
image: docker:29.2.1-dind
container_name: ${CONTAINER_NAME}-dind
privileged: ${PRIVILEGED}
restart: unless-stopped
command: ['dockerd', '-H', 'tcp://0.0.0.0:2375', '--tls=false']
environment:
DOCKER_TLS_CERTDIR: ""
volumes:
- ./data/dind-data:/var/lib/docker
- ./data/daemon.json:/etc/docker/daemon.json:ro
networks:
- 1panel-network
labels:
createdBy: Apps
networks:
1panel-network:
external: true

View File

@ -1,47 +0,0 @@
#!/bin/bash
set -e
mkdir -p data
cd data
## ----------------------------
## Runner 数据目录及权限设置
## ----------------------------
mkdir -p runner-data
touch runner-data/.runner
touch runner-data/config.yml
mkdir -p runner-data/.cache
# 设置权限为 forgejo-runner 镜像中默认用户UID 1000
chown -R 1000:1000 runner-data
chmod 775 runner-data/.runner
chmod 775 runner-data/.cache
chmod g+s runner-data/.runner
chmod g+s runner-data/.cache
## ----------------------------
## Docker-in-Docker 数据目录
## ----------------------------
mkdir -p dind-data
## ----------------------------
## daemon.json 镜像加速配置
## ----------------------------
if [ -f /etc/docker/daemon.json ]; then
cp /etc/docker/daemon.json ./daemon.json
else
cat > ./daemon.json <<EOF
{
"registry-mirrors": [
"https://docker.1panel.live",
"https://docker.1ms.run"
]
}
EOF
fi
cd ..
chmod +x ./scripts/register.sh

View File

@ -1,24 +0,0 @@
#!/bin/sh
set -e
# 等待 dockerd 可用
echo "⏳ Waiting for Docker daemon on dind..."
until curl -s http://dind:2375/_ping | grep -q "OK"; do
sleep 1
done
echo "✅ Docker daemon is ready."
cd /data
if [ ! -s .runner ]; then
echo ">>> Registering runner..."
forgejo-runner register --no-interactive \
--instance "$FORGEJO_INSTANCE_URL" \
--token "$RUNNER_REGISTRATION_TOKEN" \
--name "$RUNNER_NAME" \
--labels "$RUNNER_LABELS"
forgejo-runner generate-config > config.yml
fi
echo ">>> Starting daemon..."
exec forgejo-runner --config config.yml daemon

View File

@ -1,23 +1,27 @@
additionalProperties:
formFields:
- default: "false"
- default: dood
edit: true
envKey: PRIVILEGED
labelEn: "Privilege Mode: Manually enabled for permission issues"
labelZh: "特权模式: 遇到权限问题时手动启用"
envKey: DOCKER_MODE
labelZh: Docker 守护进程运行模式
labelEn: Docker daemon run mode
label:
en: Privilege Mode
zh: 特权模式
description:
en: Manually enabled for permission issues
zh: 遇到权限问题时手动启用
zh: Docker 守护进程运行模式
zh-Hant: Docker 背景服務執行模式
en: Docker daemon run mode
ja: Docker デーモン実行モード
ko: Docker 데몬 실행 모드
ms: Mod operasi daemon Docker
pt-br: Modo de execução do daemon do Docker
ru: Режим работы демона Docker
tr: Docker arka plan hizmeti çalıştırma modu
required: false
type: select
values:
- label: "启用 Enabled"
value: "true"
- label: "禁用 Disabled"
value: "false"
- label: Docker outside of Docker
value: dood
- label: Docker in Docker
value: dind
- default: http://1.2.3.4:3000
edit: true
envKey: FORGEJO_INSTANCE_URL
@ -35,7 +39,7 @@ additionalProperties:
ko: Forgejo 인스턴스
zh-Hant: Forgejo 實例
zh: Forgejo 实例
- default: '<registration_token>'
- default: ''
edit: true
envKey: RUNNER_REGISTRATION_TOKEN
labelEn: Registration Token
@ -51,12 +55,11 @@ additionalProperties:
ko: 등록 토큰
zh-Hant: 註冊令牌
zh: 注册令牌
- default: '<runner_name>'
- default: ''
edit: true
envKey: RUNNER_NAME
labelEn: Runner Name
labelZh: 运行器名称
required: true
type: text
label:
en: Runner Name
@ -67,12 +70,11 @@ additionalProperties:
ko: 러너 이름
zh-Hant: 執行器名稱
zh: 运行器名称
- default: '<runner_labels>'
- default: ''
edit: true
envKey: RUNNER_LABELS
labelEn: Runner Labels
labelZh: 运行器标签
required: true
type: text
label:
en: Runner Labels

View File

@ -2,16 +2,18 @@ services:
forgejo-runner:
image: code.forgejo.org/forgejo/runner:12.6.3
container_name: ${CONTAINER_NAME}
privileged: ${PRIVILEGED}
restart: always
user: root
depends_on:
dind:
condition: service_started
command: /data/scripts/register.sh
volumes:
- ./data:/data
- ./scripts/register.sh:/data/scripts/register.sh:ro
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
- DOCKER_MODE=${DOCKER_MODE}
- DOCKER_HOST=${DOCKER_HOST}
- FORGEJO_INSTANCE_URL=${FORGEJO_INSTANCE_URL}
- RUNNER_REGISTRATION_TOKEN=${RUNNER_REGISTRATION_TOKEN}
- RUNNER_NAME=${RUNNER_NAME}
@ -20,6 +22,20 @@ services:
- 1panel-network
labels:
createdBy: Apps
dind:
image: docker:29.2.0
container_name: ${CONTAINER_NAME}-dind
privileged: true
restart: unless-stopped
command: ['dockerd', '-H', 'tcp://0.0.0.0:2375', '--tls=false']
environment:
DOCKER_TLS_CERTDIR: ""
volumes:
- ./dind-data:/var/lib/docker
networks:
- 1panel-network
labels:
createdBy: Apps
networks:
1panel-network:
external: true

View File

@ -1,21 +1,9 @@
#!/bin/bash
set -e
# 创建数据目录并设置权限
source .env
mkdir -p data
touch data/.runner
touch data/config.yml
mkdir -p data/.cache
# 设置为 forgejo-runner 镜像中的默认非 root 用户
chown -R 1000:1000 data
chmod 775 data/.runner
chmod 775 data/.cache
chmod g+s data/.runner
chmod g+s data/.cache
chmod +x ./scripts/register.sh
echo "✅ 初始化完成:"
echo " - 已创建 ./data 并配置权限"
echo " - 已创建 ./scripts/register.sh 并配置权限"
if [ "$DOCKER_MODE" = "dood" ]; then
echo "DOCKER_HOST=unix:///var/run/docker.sock" >> .env
elif [ "$DOCKER_MODE" = "dind" ]; then
echo "DOCKER_HOST=tcp://dind:2375" >> .env
fi
chmod +x ./scripts/register.sh

View File

@ -1,17 +1,34 @@
#!/bin/sh
set -e
echo "Waiting for Docker daemon to be ready..."
apk update && apk add --no-cache curl
until curl -s http://dind:2375/_ping | grep -q "OK"; do
sleep 1
done
echo "Docker daemon is ready."
cd /data
if [ -z "$RUNNER_LABELS" ]; then
RUNNER_LABELS="docker"
fi
if [ ! -s .runner ]; then
echo ">>> Registering runner..."
forgejo-runner register --no-interactive \
--instance "$FORGEJO_INSTANCE_URL" \
--token "$RUNNER_REGISTRATION_TOKEN" \
--name "$RUNNER_NAME" \
--labels "$RUNNER_LABELS"
forgejo-runner generate-config > config.yml
--labels "${RUNNER_LABELS}:docker://node:lts"
fi
echo ">>> Create config..."
forgejo-runner generate-config > config.yml
sed -i 's#^ force_pull:.*$# force_pull: true#' config.yml
if [ "$DOCKER_MODE" = "dood" ]; then
sed -i 's#^ network:.*$# network: 1panel-network#' config.yml
sed -i 's#^ docker_host:.*$# docker_host: unix:///var/run/docker.sock#' config.yml
elif [ "$DOCKER_MODE" = "dind" ]; then
sed -i '/envs:/a\ DOCKER_HOST: tcp://dind:2375' config.yml
sed -i 's#^ docker_host:.*$# docker_host: tcp://dind:2375#' config.yml
sed -i 's#^ privileged:.*$# privileged: true#' config.yml
sed -i 's#^ options:.*$# options: --add-host=dind:host-gateway#' config.yml
fi
echo ">>> Starting daemon..."
exec forgejo-runner --config config.yml daemon

View File

@ -10,13 +10,74 @@ Forgejo Runner 是一个守护进程,用于连接到 Forgejo 实例并运行
- **与 Forgejo 深度集成**: 作为 Forgejo 的原生 Actions 运行器,能够无缝集成到 Forgejo 的工作流系统中,用户可以通过 Forgejo 界面配置和管理自动化任务。
## Docker 守护进程运行模式风险提示
### Docker outside of Docker (DooD)
此模式下 Runner 服务容器 (即本应用创建的容器) 及作业容器 (即实际运行工作流的容器) 与宿主机共享 Docker 环境。这可能导致以下风险:
- 任何在宿主机 Docker 中运行的容器都将被作业容器、服务容器和步骤中的容器访问。例如,如果 Forgejo 或 Forgejo Runner 在相同的主机上作为容器运行,那么作业容器将能够执行对这些容器上的 docker kill 、 docker inspect 或 docker exec 等操作。
> ```yaml
> jobs:
> docker-access-demo:
> runs-on: docker
> container:
> image: node:lts
> services:
> postgres:
> image: postgres:latest
> env:
> POSTGRES_PASSWORD: example
> steps:
> - run: docker run -d --name ubuntu ubuntu:latest
> ```
> 上方的示例中node、postgres、ubuntu 三个容器均可访问到宿主机中的其他容器
- 将卷挂载到新创建的容器,可能会危及宿主机上的所有存储。诸如`docker run -v /:/host-mount ubuntu`这样的命令出现在工作流中会使整个主机的存储 (包括磁盘上的任何密钥) 暴露给工作流。
- 工作流创建的工件,例如通过 docker build 构建的镜像,或通过 docker run 创建的容器,都将留在宿主机的 docker 守护进程中。后续在同一运行器上执行的任何工作流都能访问它们,并可能从中提取机密信息。
- 在 Forgejo Runner 服务容器上配置的资源限制对由工作流创建的作业容器没有任何影响。
- 通过 Forgejo Runner 的 container.network 指定的网络配置不会应用于工作流创建的任何容器。工作流可以定义诸如 --network=host 等来访问主机操作系统的原生网络。将本地网络资源暴露给这些容器,会带来新的安全风险。
### Docker in Docker (DinD)
此模式下的作业容器 (即实际运行工作流的容器) 与宿主机的 Docker 环境隔离,具有一定的安全性。但是仍需注意:
- 如果 Forgejo Runner 配置了大于 1 的 runner.capacity 以允许多个并发任务,或者多个 Forgejo Runner 使用相同的 container.docker_host 连接上了同一个 DinD 实例,则作业容器之间可通过 docker 客户端相互查看并交互。这可能允许一个任务容器在运行时窃取另一个正在运行的作业容器的密钥或与其文件交互。
- DinD 容器将拥有自己的存储,在其容器内的自己的 /var/lib/docker 目录中。这会导致:
- 主机上的镜像在容器内拉取之前,不会在 DinD 环境内可用;
- 宿主机上已有的镜像将会在 DinD 环境内额外保存一次;
- 除非将/var/lib/docker 目录持久化,否则在重建 DinD 容器 (例如升级 docker:dind 镜像时) 会清空该目录,若工作流依赖镜像缓存,则会影响之后工作流的效率。
- 如果/var/lib/docker 被映射到持久卷,则必须定期执行诸如 docker system prune 之类的维护操作,以确保镜像和卷不会因过时和无用的内容而无限增长。
- 工作流创建的工件,例如通过 docker build 构建的镜像,或通过 docker run 创建的容器,会留在 DinD 守护进程中。后续在同一运行器上执行的任何工作流都能访问它们,并可能从中提取机密信息。
- 在 Forgejo Runner 服务容器上配置的资源限制对由工作流创建的作业容器没有任何影响,这些资源实际上将受限于所创建的 DinD 容器的配置。
## 配置和使用说明
- **选择版本**: 现提供两种版本,常规版本 (下称 DooD 版本) 与 DinD 版本。
- DooD 版权限更高,与宿主机共享 docker 环境遇到需要在工作流中使用容器的情况DooD 版本可以在宿主机管理 Runner 中的容器;
- DinD 版安全性更强docker 环境与宿主机完全独立,基本没有越权;
- 当 DinD 版本下运行某些 action 权限不足时,请先尝试启用特权模式,若仍报错,再尝试使用 DooD 版。
- **Forgejo 实例 URL**: (例如 `https://git.example.com`)
- **注册令牌**: 从 Create new runner 按钮中获取,仅用于 Runner 实例,需要区别于个人访问令牌 (PAT)
- **运行器名称**: 区分不同 Runner 实例的唯一标识符,同一命名空间 (仓库或组织) 下不允许重复
- **运行器名称**: 建议为每个 Runner 设置具有描述性的唯一名称 (如 ForgejoRunner-机房-用途-编号)
- **运行器标签**: 用于标记 Runner 实例,工作流中可以根据标签选择 Runner 执行任务,同一个标签可以绑定多个 Runner 实例
- 工作流默认将会在基于 `node:lts` 的容器中运行,如何需要使用其他环境,可以在工作流中配置
```yaml
jobs:
test:
runs-on: docker
container:
image: pytorch/pytorch:2.10.0-cuda13.0-cudnn9-runtime
options:
-v /path/to/folder:/path/to/folder
steps:
- run: ls -al /path/to/folder
```
- 工作流默认将会在基于 `node:lts` 的容器中运行,如果需要用到 docker 客户端,需要自行安装
```yaml
on:
workflow_dispatch:
jobs:
test:
runs-on: docker
steps:
- run: |
curl -fsSL https://get.docker.com | bash
docker -v
docker ps
```

View File

@ -8,13 +8,74 @@ Forgejo Runner is a daemon process used to connect to a Forgejo instance and run
- **Multi-Architecture Support**: Officially supports running on Linux kernel-based operating systems, covering `amd64` and `arm64` architectures. Provides binary files and container images. Active development is underway for support of other architectures (such as s390x, powerpc64le, riscv64) and Windows.
- **Deep Integration with Forgejo**: As a native Actions runner for Forgejo, it seamlessly integrates into Forgejo's workflow system, allowing users to configure and manage automated tasks via the Forgejo interface.
## Docker Daemon Running Mode Risk Warning
### Docker outside of Docker (DooD)
In this mode, the Runner service container (i.e., the container created by this application) and the job container (i.e., the container that actually runs workflows) share the Docker environment with the host machine. This may lead to the following risks:
- Any containers executed in Docker will be accessible to the job, service, and step containers. For example, if Forgejo or Forgejo Runner are run as containers on the same host, then job containers will be able to execute actions like docker kill, docker inspect, or docker exec on those containers.
> ```yaml
> jobs:
> docker-access-demo:
> runs-on: docker
> container:
> image: node:lts
> services:
> postgres:
> image: postgres:latest
> env:
> POSTGRES_PASSWORD: example
> steps:
> - run: docker run -d --name ubuntu ubuntu:latest
> ```
> In the example above, the node, postgres, and ubuntu containers can all access other containers on the host
- All storage on the host can be compromised by an Action performing volume mounts to newly created containers. For example, an action step such as docker run -v /:/host-mount ubuntu would make the entire hosts storage available to the container, including any on-disk secrets.
- Artifacts that workflows create, such as new images created by docker build or containers created by docker run, will be left in the hosts docker daemon. Any future workflow execution on the same runner will be able to inspect these artifacts and could extract confidential information from them.
- Resource Constraints configured on Forgejo Runner wont have any impact on containers created from workflow actions.
- Specific network configuration via Forgejo Runners container.network setting will not be applied to any containers created from workflows. Workflows would be able to define settings like --network=host to access the host operating systems native network. This creates new security risks by exposing Local Network Resources to these containers.
### Docker in Docker (DinD)
Job containers in this mode (i.e., the containers that actually run the workflow) are isolated from the host's Docker environment, providing a certain level of security. However, it is still important to note:
- If a Forgejo Runner is configured with runner.capacity greater than 1 to allow multiple concurrent tasks, or multiple Forgejo Runners are configured using the same DIND container.docker_host, then job containers will be able to view and interact with each other through the docker CLI. This could allow one to compromise the secrets of another running job container or interact with its files while it is running.
- The DIND container will have its own storage, in its own /var/lib/docker directory within the container. This means that…
- Images available on the host wont be available on the DIND container until pulled within that container,
- Extra storage may be used holding duplicate copies of images relative to the host,
- The /var/lib/docker directory will be wiped if the DIND container is recreated (for example, for software upgrades to the docker:dind image) unless it is volume-mapped to a persistent volume, potentially impacting the performance of future workflow runs if image caching is relied upon.
- If /var/lib/docker is volume-mapped to a persistent volume, it will need periodic maintenance such as docker system prune to ensure that the images and volumes do not grow indefinitely with out-of-date and irrelevant contents.
- Artifacts that workflows create, such as new images created by docker build or containers created by docker run, will be left in the DIND container. Any future workflow execution on the same runner will be able to inspect these artifacts and could extract confidential information from them.
- Resource Constraints configured on Forgejo Runner wont have any impact on containers created from workflow actions. However, resources will be constrained to those configured on the created DIND container.
## Configuration and Usage Instructions
- **Choose a Version**: Two versions are currently available: the regular version (referred to as the DooD version) and the DinD version.
- The DooD version has higher privileges and shares the Docker environment with the host machine. When workflows require container usage, the DooD version can manage containers within the Runner on the host machine.
- The DinD version offers stronger security, with a Docker environment completely isolated from the host machine, minimizing privilege escalation risks.
- If certain actions encounter insufficient permissions under the DinD version, first try enabling privileged mode. If errors persist, consider switching to the DooD version.
- **Forgejo Instance URL**: (e.g., `https://git.example.com`)
- **Registration Token**: Obtained from the "Create new runner" button. This token is used exclusively for the Runner instance and should differ from a Personal Access Token (PAT).
- **Runner Name**: A unique identifier to distinguish different Runner instances. Duplicate names are not allowed within the same namespace (repository or organization).
- **Runner Name**: It is recommended to set a descriptive, unique name for each Runner (e.g., ForgejoRunner-DataCenter-Purpose-Number).
- **Runner Labels**: Used to tag Runner instances. Workflows can select a Runner based on labels to execute tasks. The same label can be assigned to multiple Runner instances.
- Workflows run by default in a container based on `node:lts`. If other environments are required, they can be configured in the workflow.
```yaml
jobs:
test:
runs-on: docker
container:
image: pytorch/pytorch:2.10.0-cuda13.0-cudnn9-runtime
options:
-v /path/to/folder:/path/to/folder
steps:
- run: ls -al /path/to/folder
```
- Workflows will run in a container based on `node:lts` by default. If the Docker client is required, it needs to be installed manually
```yaml
on:
workflow_dispatch:
jobs:
test:
runs-on: docker
steps:
- run: |
curl -fsSL https://get.docker.com | bash
docker -v
docker ps
```