Semaphore v2.19.17 配置参数详解
Semaphore v2.19.17 配置参数详解:config.json 与环境变量双通道体系、优先级规则、13 大域 130+ 配置项分类全解(数据库/Web/加密/认证/Git/任务/Runner/通知/日志)、生产配置模板与常见坑。
Semaphore v2.19.17 配置参数详解
目标:讲清 Semaphore v2.19.17 的配置体系——
config.json配置文件与环境变量两条通道的写法与优先级,并按官方 Configuration Reference(该页由源码生成,与 v2.19.17 发布版严格对应,2026-10-24 实查)把 13 大域全部配置项分类详解,配生产配置模板。文中所有示例文件、命令与回显均在 Ubuntu 22.04 实测环境验证过。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64)
- Semaphore 版本:v2.19.17(启动自报
v2.19.17-f8cefe6-1792391878) - 部署形态:官方镜像 Docker Compose 部署,MySQL 8.0 方言(部署过程见 《Semaphore v2.19.17 Docker Compose 部署指南》)
- 配置文件位置:
/etc/semaphore/config.json(宿主机挂载路径/opt/semaphore/data/semaphore-config/config.json) - 参数来源:官方 Reference《Configuration options》页面(生成自源码,与发布版一致),查询日期 2026-10-24;社区版/Pro/Enterprise 功能分界在对应小节标注
二、前置条件
本篇是配置专题篇,不重复部署全流程,但要求具备以下条件,每项给出可独立执行的验证方法。
- 一套运行中的 Semaphore。验证(服务进程日志确认版本与运行态):
docker compose logs --tail 5 semaphore
semaphore-v2.19.17-web | Starting semaphore server
semaphore-v2.19.17-web | MySQL semaphore@mysql:3306 semaphore
semaphore-v2.19.17-web | Tmp Path (projects home) /tmp/semaphore
semaphore-v2.19.17-web | Semaphore v2.19.17-f8cefe6-1792391878
semaphore-v2.19.17-web | Server is running
- 能读到当前生效的 config.json。验证(查看首次启动自动生成的配置实物):
cat /etc/semaphore/config.json
{
"mysql": {
"host": "mysql:3306",
"user": "semaphore",
"pass": "q1w2e3r4",
"name": "semaphore"
},
"dialect": "mysql",
"tmp_path": "/tmp/semaphore",
"cookie_hash": "f5I+atUJX6MA5xNnpRimZqDKYAM8EzqEjlXn6b5w5zg=",
"cookie_encryption": "aoSl2CFTBhktRX83U1ivNJ8TXKWW95UAqIpZDylMN8A=",
"access_key_encryption": "9hm9XNftIltnY05Q50cLHXvr/Vdsj6RmmZiz5M8QEus="
}
这是最小生成集:只有数据库、路径与三个密钥,其余参数全部走默认值。本文后续把可补充的 130+ 项逐域讲清。
三、参数查看与修改方式
Semaphore 的每个配置项都有两条等价通道:config.json 键(嵌套键用点号书写,如 runner.executor.type 对应 {"runner": {"executor": {"type": ...}}})与 SEMAPHORE_* 环境变量(官方 Reference 每个选项同时给出两者,环境变量名即表中的第二行)。
3.1 两条通道与优先级
规则(官方 Reference 明示):环境变量优先于配置文件——同一参数两处都设置时,环境变量生效。三条使用建议:
- 部署期变量(数据库连接、初始管理员)用环境变量,随 Compose 文件版本化管理;
- 运行期调整(git 重试次数、任务并发、通知渠道)改
config.json,改完重启生效; - 敏感值(数据库密码、SMTP 密码)可用
_FILE后缀环境变量从文件读,如SEMAPHORE_ADMIN_PASSWORD_FILE: /run/secrets/admin_pw,避免明文进编排文件。
3.2 config.json 的生成与修改生效
生成(二选一):
- 交互式向导:服务器执行
semaphore setup,按提示问答后写出 config.json(Runner 用semaphore runner setup); - 环境变量自动生成:首次以
SEMAPHORE_*变量启动时自动执行 setup 并落盘(部署篇 4.4 节实测全过程)。
修改生效:config.json 只在进程启动时读取一次,修改后必须重启。实测:
docker compose restart semaphore
Container semaphore-v2.19.17-web Restarting
Container semaphore-v2.19.17-web Started
重启后确认新参数生效——例如把 git_attempts 从默认 4 改为 6 后,在日志中无法直接看到该值,可用最直观的验证法:改 port 为 :3001 再重启,日志会出现 Port :3001,验证后改回。任何参数改动都遵循「改文件 → 重启 → 看行为变化」闭环,不做无验证的配置变更。
四、参数总览
官方 Reference 按 13 个域组织配置项,总览如下(括号内为该域重点参数):
| 域 | 环境变量前缀 / 说明 | 关键参数 |
|---|---|---|
| 数据库 | SEMAPHORE_DB_* | dialect、mysql.* / postgres.* / sqlite.* |
| Web 服务 | SEMAPHORE_PORT、SEMAPHORE_TLS_* | port、tls.*、cookie_hash/encryption |
| 路径与存储 | SEMAPHORE_TMP_PATH 等 | tmp_path、dirs.*、home_dir_mode |
| 加密 | SEMAPHORE_ACCESS_KEY_ENCRYPTION 等 | access_key_encryption、encryption.keys_file |
| 认证 | SEMAPHORE_TOTP_*、SEMAPHORE_LDAP_*、SEMAPHORE_OIDC_PROVIDERS | mfa.*、ldap_*、oidc_providers |
| Git | SEMAPHORE_GIT_*、SEMAPHORE_SSH_* | git_client、git_attempts、ssh.known_hosts_file |
| 任务 | SEMAPHORE_MAX_PARALLEL_TASKS 等 | max_parallel_tasks、env_vars、process.* |
| Runners | SEMAPHORE_RUNNER_*、SEMAPHORE_RUNNERS_* | runner.executor.*、runners.offline_timeout_sec |
| 任务 JWT | SEMAPHORE_JWT_* | jwt.enabled、jwt.default_ttl |
| 通知 | SEMAPHORE_EMAIL_ALERT 等 | email_*、telegram_*、slack_*、dingtalk_* |
| 日志与指标 | SEMAPHORE_METRICS_*、SEMAPHORE_EVENT_LOG_* | metrics.enabled、log.events.* |
| 团队与邀请 | SEMAPHORE_TEAMS_* | teams.invites_enabled |
| 订阅/HA/审计/调试 | SEMAPHORE_SUBSCRIPTION_*、SEMAPHORE_HA_*、SEMAPHORE_AUDIT_* | subscription.key、ha.enabled(Enterprise)、audit.enabled |
如何读总览:日常运维 90% 的改动集中在前 7 个域;Runner 域只在把任务执行拆到独立节点时才需要;HA 域是 Enterprise 功能,社区版部署可跳过。下面逐域详解。
五、核心参数分类详解
5.1 数据库(Database)
Semaphore 启动时自动建表并执行迁移。方言必须在首次启动前定死,之后更换需自行迁移数据。三方言参数结构相同(以 MySQL 为例,Postgres/SQLite 把 mysql 键换成 postgres/sqlite):
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
mysql.host / SEMAPHORE_DB_HOST | string,默认 0.0.0.0 | 数据库主机,格式 主机:端口(如 mysql:3306) |
mysql.user / SEMAPHORE_DB_USER | string | 数据库用户名 |
mysql.pass / SEMAPHORE_DB_PASS | string | 数据库密码(敏感) |
mysql.name / SEMAPHORE_DB | string,默认 semaphore | 数据库名 |
mysql.options / SEMAPHORE_DB_OPTIONS | object | 追加到 DSN 的驱动选项(JSON 键值对) |
dialect / SEMAPHORE_DB_DIALECT | string,默认 sqlite | 引擎:mysql / postgres / sqlite |
SQLite 特殊性:sqlite.host 与 sqlite.name 都是数据库文件路径,user/pass 无效(单文件无需凭据)。实测 SQLite 方言生成的配置:
{
"sqlite": {
"host": "/etc/semaphore/semaphore.sqlite"
},
"dialect": "sqlite",
"tmp_path": "/tmp/semaphore",
"cookie_hash": "EeU+8/OuR7SgUYe1GPwVotg4VrAOSL2/FgBtVvR07Mw=",
"cookie_encryption": "vZVAolrVgO/0YT47aSuVmRekepaQM669VRw6S/LkZOs=",
"access_key_encryption": "G1yuvVm4Qnbz/P9M8laanCExljms/WHb3krhvwrPMDA="
}
Postgres 的 postgres.options 典型用途是 sslmode:{"sslmode": "require"}。
5.2 Web 服务(Web server)
监听地址与用户访问入口。web_host 决定重定向 URI、webhook 回调地址与通知里的链接拼接,必须设成用户实际键入的 URL:
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
port / SEMAPHORE_PORT | string,默认 :3000 | 监听端口,格式 :3000;缺 : 会自动纠正 |
tls.enabled / SEMAPHORE_TLS_ENABLED | boolean | 启用 HTTPS |
tls.cert_file / SEMAPHORE_TLS_CERT_FILE | string | TLS 证书文件路径 |
tls.key_file / SEMAPHORE_TLS_KEY_FILE | string | TLS 私钥文件路径 |
tls.http_redirect_addr / SEMAPHORE_TLS_HTTP_REDIRECT_ADDR | string | HTTP→HTTPS 跳转监听地址(host[:port],与 http_redirect_port 互斥) |
tls.http_redirect_port / SEMAPHORE_TLS_HTTP_REDIRECT_PORT | integer | HTTP 跳转端口(与 http_redirect_addr 互斥) |
interface / SEMAPHORE_INTERFACE | string | 绑定 IP(置于端口前),默认空 |
web_host / SEMAPHORE_WEB_ROOT | string | 对外访问主机(拼接链接用) |
cookie_hash / SEMAPHORE_COOKIE_HASH | string | Cookie 哈希密钥(敏感,首次初始化自动生成) |
cookie_encryption / SEMAPHORE_COOKIE_ENCRYPTION | string | 会话 Cookie 加密密钥(base64;更换后全体用户登出) |
TLS 最小启用示例(config.json 片段):
{
"port": ":3000",
"tls": {
"enabled": true,
"cert_file": "/etc/semaphore/tls/semaphore.crt",
"key_file": "/etc/semaphore/tls/semaphore.key",
"http_redirect_port": 3000
},
"web_host": "https://semaphore.example.com"
}
逐项说明:http_redirect_port: 3000 让原 HTTP 端口只做跳转,HTTPS 在同一 port(这里 3000 即 TLS 端口)上服务;证书路径放在配置目录下可随挂载持久化;web_host 与证书域名保持一致,否则通知链接与 webhook 回调会指向错误主机名。
5.3 路径与存储(Paths and storage)
除数据库外,这里全是可重建的缓存类目录:
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
tmp_path / SEMAPHORE_TMP_PATH | string,默认 /tmp/semaphore | 项目临时目录(仓库克隆、任务工作区根) |
dirs.secrets / SEMAPHORE_SECRETS_PATH | string,默认 /tmp/semaphore | 密钥文件目录(Key Store 的 File 型条目、Vault/OpenBao token 文件只能放这里) |
secrets_path / SEMAPHORE_SECRETS_PATH | string | 旧版顶层写法,仅在 dirs.secrets 未设或为默认值时生效 |
dirs.repos / SEMAPHORE_REPOS_DIR | string | 仓库存储目录 |
dirs.ssh_agent_sockets / SEMAPHORE_SSH_AGENT_SOCKETS_DIR | string,默认 /tmp/semaphore | SSH agent socket 目录 |
home_dir_mode / (无同名环境变量) | string,默认 template_dir | 任务进程 HOME 的设置策略(见下方拓展) |
密钥目录的硬约束(官方明示):Key Store 中 File 类型密钥与外部密钥库的 token 文件必须位于 dirs.secrets 之内,路径在外会被拒绝,报错 file path must be inside secrets path。生产建议改到独立目录:
{
"dirs": {
"secrets": "/var/lib/semaphore/secrets"
}
}
💡 技术拓展:
home_dir_mode决定任务进程的 HOME 环境变量怎么设,三个可选值对比——
取值 行为 适用场景 template_dir(默认)每个模板独立 HOME, .ansible/天然隔离,仓库克隆到 HOME 下src子目录并行任务多的团队(推荐保持默认) project_homeHOME 用项目级临时目录 旧行为;同项目并行 ansible-galaxy 可能冲突 user_home不覆盖 HOME,沿用真实用户 HOME, ANSIBLE_HOME按模板隔离需要复用宿主用户级缓存的特殊场景 本文保持默认
template_dir:并行任务的.ansible隔离是开箱即得的,无需额外配置。
5.4 加密(Encryption)
保护数据库中敏感数据的密钥族。官方警示原文要点:密钥必须与数据库分开备份——没有密钥,数据库内容不可读。
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
access_key_encryption / SEMAPHORE_ACCESS_KEY_ENCRYPTION | string | 加解密 Key Store(SSH 私钥、API Token 等)的 base64 密钥;旧入口,向后兼容保留 |
option_encryption / SEMAPHORE_OPTION_ENCRYPTION | string | DB options(JWT 签名密钥)的旧式单密钥加密;未设时回落到 access keyring |
encryption.keys_file / SEMAPHORE_ENCRYPTION_KEYS_FILE | string | 密钥环(keyrings)文件路径,轮换场景使用 |
encryption.keys_poll_interval / SEMAPHORE_ENCRYPTION_KEYS_POLL_INTERVAL | string,默认 15s | 密钥文件变更轮询间隔(Go duration);0 关闭轮询(SIGHUP 仍可强制重载) |
密钥生成与备份实操(实测):
head -c32 /dev/urandom | base64
IrPXhBcHhRyjt42Ej+eq7tdyicGzPW38Sh7GzitQ1mk=
cp /etc/semaphore/config.json /opt/backup/semaphore-config-$(date +%F).json && ls -l /opt/backup/ | tail -1
-rw-r--r-- 1 root root 421 Oct 24 11:30 semaphore-config-2026-10-24.json
(备份文件名用命令替换生成日期后缀,每次执行结果不同;ls 回显的日期部分随执行日变化。)
5.5 认证(Authentication)
登录方式与会话策略。社区版覆盖本地密码 + LDAP/OIDC 企业登录;mfa.totp.* 双因子社区版可用。
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
auth.max_session_life_hours / SEMAPHORE_AUTH_MAX_SESSION_LIFE_HOURS | integer | 会话绝对寿命(小时),0 = 不设绝对上限(仅按不活跃过期) |
mfa.totp.enabled / SEMAPHORE_TOTP_ENABLED | boolean | 启用 TOTP 双因子 |
mfa.totp.allow_recovery / SEMAPHORE_TOTP_ALLOW_RECOVERY | boolean | 允许用恢复码重置 TOTP |
mfa.totp.app_name / SEMAPHORE_TOTP_ISSUER | string | 认证器 App 中显示的发行方名称 |
mfa.email.enabled / SEMAPHORE_EMAIL_2TP_ENABLED | boolean | 启用邮件多因子 |
mfa.email.allowed_domains / SEMAPHORE_EMAIL_2TP_ALLOWED_DOMAINS | array | 允许的邮箱域(JSON 数组) |
ldap_enable / SEMAPHORE_LDAP_ENABLE | boolean | 旧式单目录 LDAP 开关(配合下方 ldap_* 平铺参数) |
ldap_server / SEMAPHORE_LDAP_SERVER | string | LDAP 主机与端口(如 ldap.example.com:1389) |
ldap_binddn / SEMAPHORE_LDAP_BIND_DN | string | 绑定 DN |
ldap_bindpassword / SEMAPHORE_LDAP_BIND_PASSWORD | string | 绑定密码(敏感) |
ldap_searchdn / SEMAPHORE_LDAP_SEARCH_DN | string | 搜索基准 DN(如 dc=example,dc=org) |
ldap_searchfilter / SEMAPHORE_LDAP_SEARCH_FILTER | string | 用户搜索过滤器(如 (&(objectClass=inetOrgPerson)(uid=%s))) |
ldap_mappings.dn/mail/uid/cn / SEMAPHORE_LDAP_MAPPING_* | string,默认 dn/mail/uid/cn | LDAP 属性映射 |
ldap_needtls / SEMAPHORE_LDAP_NEEDTLS | boolean | LDAP 连接是否用 TLS |
ldap_tls_skip_verify / SEMAPHORE_LDAP_TLS_SKIP_VERIFY | boolean | 跳过 LDAP 证书校验(默认 false,不建议开) |
ldap_providers / SEMAPHORE_LDAP_PROVIDERS | object | 多 LDAP 目录配置(键为 provider ID;ldap 键保留给旧式配置) |
oidc_providers / SEMAPHORE_OIDC_PROVIDERS | object | OIDC 登录配置(键为 provider ID,出现在 /auth/oidc/<id>/login 路径中,一旦用户登录过就不可改) |
password_login_disable / SEMAPHORE_PASSWORD_LOGIN_DISABLED | boolean | 禁用本地密码登录(配好 LDAP/OIDC 后关闭第二扇门) |
external_auth_email_matching / SEMAPHORE_EXTERNAL_AUTH_EMAIL_MATCHING | string,默认 auto | 外部登录按邮箱关联既有用户的策略:auto/always/never |
non_admin_can_create_project / SEMAPHORE_NON_ADMIN_CAN_CREATE_PROJECT | boolean | 允许非管理员建项目 |
启用 TOTP 双因子最小配置:
{
"mfa": {
"totp": {
"enabled": true,
"allow_recovery": true
}
}
}
逐项说明:enabled 打开后用户在个人设置页绑定认证器;allow_recovery: true 生成一次性恢复码,认证器丢失时不至于锁死账号。企业用户建议同时收紧会话:
{
"auth": {
"max_session_life_hours": 12
}
}
(登录 12 小时后强制重新认证,即使一直活跃。)
5.6 Git(Git)
任务运行前克隆/更新仓库的行为控制:
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
git_client / SEMAPHORE_GIT_CLIENT | string,默认 cmd_git | 克隆实现:cmd_git(调系统 git)或 go_git(纯 Go 库) |
git_attempts / SEMAPHORE_GIT_ATTEMPTS | integer,默认 4 | 克隆/拉取重试次数;1 = 不重试 |
git_submodule_jobs / SEMAPHORE_GIT_SUBMODULE_JOBS | integer,默认 4 | 子模块并行拉取数(仅 cmd_git) |
ssh.config_path / SEMAPHORE_SSH_PATH | string | 自定义 SSH config 路径(默认 ~/.ssh/config) |
ssh.known_hosts_file / SEMAPHORE_SSH_KNOWN_HOSTS_FILE | string | known_hosts 路径;设置后主机密钥校验变严格 |
ssh.strict_host_key_checking | string,默认 no | 主机密钥策略:no / yes / accept-new |
💡 技术拓展:
git_client两种实现对比——
实现 原理 优点 缺点 cmd_git(默认)shell 调用系统 git 二进制 功能全(子模块并行、复杂协议),行为与命令行 git 一致 依赖镜像/主机装了 git go_git内嵌纯 Go git 库 无外部依赖 子模块等高级特性支持弱 本文保持默认
cmd_git:官方镜像内置 git,且子模块场景更可靠。
重试与退避机制(官方文档描述):克隆/拉取失败且还有剩余次数时,按指数退避等待(起始 1 秒,每次翻倍,封顶 60 秒),日志出现 Git pull failed (...), retrying in 2s 形态。重试只覆盖网络类失败;认证错误、仓库不存在这类确定性失败会直接失败,调大 git_attempts 无济于事。
主机密钥策略建议:默认 no + 自动 TOFU(首次连接信任并钉住到 tmp_path 下的持久文件,之后变更即拒绝)。安全要求高的环境设置 ssh.strict_host_key_checking: yes 并预置 ssh.known_hosts_file。
5.7 任务(Tasks)
并发、时长、环境注入与任务进程沙箱:
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
max_parallel_tasks / SEMAPHORE_MAX_PARALLEL_TASKS | integer,默认 9999 | 全局任务并发上限 |
max_task_duration_sec / SEMAPHORE_MAX_TASK_DURATION_SEC | integer | 单任务最长运行秒数(超时终止) |
max_tasks_per_template / SEMAPHORE_MAX_TASKS_PER_TEMPLATE | integer | 每个模板在库中保留的最近任务数 |
apps / SEMAPHORE_APPS | object | 应用配置(JSON map) |
env_vars / SEMAPHORE_ENV_VARS | object | 注入任务进程的静态环境变量(JSON map) |
forwarded_env_vars / SEMAPHORE_FORWARDED_ENV_VARS | array | 从服务进程环境显式转发给任务与 git 子进程的变量名列表 |
process.user/uid/gid / SEMAPHORE_PROCESS_USER/UID/GID | string/integer | 任务进程运行身份 |
process.chroot / SEMAPHORE_PROCESS_CHROOT | string | 任务进程 chroot 目录 |
process.no_new_privs / SEMAPHORE_PROCESS_NO_NEW_PRIVS | boolean | 置 no_new_privs,任务进程无法提权 |
process.app_namespaces.user/mount/pid/ipc/uts / SEMAPHORE_PROCESS_APP_NS_* | boolean | 各类 Linux namespace 隔离(CLONE_NEWUSER/NEWNS/NEWPID/NEWIPC/NEWUTS) |
schedule.timezone / SEMAPHORE_SCHEDULE_TIMEZONE | string,默认 UTC | 定时任务的时区 |
环境注入是最高频的坑位,官方规则原文要点:Semaphore 不会把自身环境整包传给任务进程——代理变量、云厂商凭证都必须显式列出才会到达任务与 git 子进程。两种注入方式实测形态:
{
"env_vars": {
"HTTP_PROXY": "http://proxy.internal:3128",
"ANSIBLE_STDOUT_CALLBACK": "yaml"
},
"forwarded_env_vars": [
"AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY",
"HTTP_PROXY",
"HTTPS_PROXY",
"NO_PROXY"
]
}
等价环境变量写法(Compose 里单行 JSON):
environment:
SEMAPHORE_ENV_VARS: '{"HTTP_PROXY":"http://proxy.internal:3128","ANSIBLE_STDOUT_CALLBACK":"yaml"}'
SEMAPHORE_FORWARDED_ENV_VARS: '["HTTP_PROXY","HTTPS_PROXY","NO_PROXY"]'
要点与解读:
env_vars是静态键值对(值固定),forwarded_env_vars是名字列表(值取自服务进程环境,适合密钥类:密钥用 secrets 注入服务进程,再转发给任务)。- 代理三件套必须一起转发(
HTTP_PROXY/HTTPS_PROXY/NO_PROXY)——官方文档给出的经典故障:systemd 部署在 corporate proxy 后,只配了 unit 的代理变量,git 克隆内部仓库报fatal: Authentication failed for 'https://git.corp.example.com/team/_git/infra',原因是 git 没拿到NO_PROXY,把内部请求发给了外部代理。补上转发即修复。 - 变量名大小写敏感(Linux),小写
http_proxy也要转发时一并列出。 - 自定义 CA(代理终结 TLS 时)同理转发
GIT_SSL_CAINFO、SSL_CERT_FILE、REQUESTS_CA_BUNDLE,而不是关证书校验。
任务并发与时区实战值(10–50 人团队参考):
{
"max_parallel_tasks": 10,
"max_task_duration_sec": 3600,
"max_tasks_per_template": 100,
"schedule": {
"timezone": "Asia/Shanghai"
}
}
逐项说明:并发 10 适配 4 核 8GB 执行节点(每任务一个 ansible 进程组,实测空载 Semaphore 约 100–200MB,任务峰值按 playbook 规模预估);单任务 1 小时兜底防僵死;模板历史保留 100 条平衡审计与库体积;时区改 Asia/Shanghai 后定时任务按本地时间触发(docker compose 里配的 TZ 只影响日志时间戳,定时任务触发时区由 schedule.timezone 决定,两处都要改)。
5.8 Runners(执行器)
Server 侧开关 + Runner 自身配置。社区版可用本地执行(local);docker/k8s 执行器与 HA 属 Pro/Enterprise(下表标注)。
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
runner.enabled / SEMAPHORE_RUNNER_ENABLED | boolean | 启用 runner 模式 |
runner.token / SEMAPHORE_RUNNER_TOKEN | string | Runner 向服务器认证的 token(由 semaphore runner register 签发,敏感) |
runner.token_file / SEMAPHORE_RUNNER_TOKEN_FILE | string | token 文件路径 |
runner.name / SEMAPHORE_RUNNER_NAME | string | Runner 名称 |
runner.tags / SEMAPHORE_RUNNER_TAGS | array | Runner 标签(JSON 数组,模板按标签调度) |
runner.max_parallel_tasks / SEMAPHORE_RUNNER_MAX_PARALLEL_TASKS | integer,默认 9999 | 该 Runner 并发上限 |
runner.project_id / SEMAPHORE_RUNNER_PROJECT_ID | integer | 限定只服务单个项目 |
runner.one_off / SEMAPHORE_RUNNER_ONE_OFF | boolean | 一次性 Runner:跑完即退出(动态弹性场景,官方流程:任务入队 → 回调 webhook → 拉起一次性 Runner → 处理任务 → 退出) |
runner.check_interval_seconds / SEMAPHORE_RUNNER_CHECK_INTERVAL_SECONDS | integer,默认 1 | 轮询服务器新任务的间隔(v2.19.17 新增可配,见下) |
runner.webhook / SEMAPHORE_RUNNER_WEBHOOK | string | Runner webhook URL |
runners.offline_timeout_sec / SEMAPHORE_RUNNERS_OFFLINE_TIMEOUT_SEC | integer,默认 120 | 心跳超时判离线(离线 Runner 的 starting 任务会被改派) |
runners.task_fail_timeout_sec / SEMAPHORE_RUNNERS_TASK_FAIL_TIMEOUT_SEC | integer,默认 420 | 心跳超时判任务失败(介于离线与失败之间留给慢 Runner 复联) |
runners.reconcile_interval_sec / SEMAPHORE_RUNNERS_RECONCILE_INTERVAL_SEC | integer,默认 30 | 服务器核对任务与 Runner 存活的扫描间隔 |
runners.default_global_runners_mode / SEMAPHORE_DEFAULT_GLOBAL_RUNNERS_MODE | string | 全局 Runner 默认策略:空/disable/prefer/require |
v2.19.17 新增项:runner.check_interval_seconds 正是本版本的 changelog(feat(runner): add check interval configuration for job polling,默认 1 秒)。Runner 密集接入时调大它可降低服务器压力(如 5 秒)。
执行器(executor)——Runner 用什么形态跑任务:
| 参数 / 环境变量 | 版本 | 说明 |
|---|---|---|
runner.executor.type / SEMAPHORE_RUNNER_EXECUTOR_TYPE | 社区 | local(默认)/ docker(Pro)/ k8s(Pro) |
runner.executor.docker.*(host/tls_verify/cert_path/image/helper_image/network/pull_policy/cpu_limit/memory_limit/poll_interval_seconds/cleanup_grace_seconds/privileged) | Pro | Docker 执行器全套:守护地址(支持 unix:///tcp://)、任务镜像(默认 semaphoreui/job:latest)、git-clone 辅助镜像(semaphoreui/helper:latest)、网络(默认 bridge)、拉取策略(默认 if-not-present)、CPU/内存限额、轮询/清理间隔等 |
runner.executor.k8s.*(kubeconfig/namespace/image/helper_image/service_account/pull_secrets/poll_interval_seconds/cleanup_grace_seconds) | Pro | Kubernetes 执行器:默认 namespace semaphore、任务 Pod 镜像 semaphoreui/job:latest、init 容器 semaphoreui/helper:latest,空 kubeconfig 时走 in-cluster 配置 |
纯环境变量部署 Runner 时,整个 executor 块可以压成单个 JSON(官方明示的等价写法):
export SEMAPHORE_RUNNER_EXECUTOR='{"type":"docker","docker":{"image":"semaphoreui/job:latest"}}'
(等价于逐项设置 runner.executor.type: docker 与 runner.executor.docker.image。)
5.9 任务 JWT(Task JWT)
给任务签发短命 JWT,供任务回调外部系统时自证身份;公钥经 /.well-known/jwks.json 发布。
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
jwt.enabled / SEMAPHORE_JWT_ENABLED | boolean | 启用任务 JWT 签发 |
jwt.issuer / SEMAPHORE_JWT_ISSUER | string | iss 声明值 |
jwt.default_ttl / SEMAPHORE_JWT_DEFAULT_TTL | string,默认 1h | 默认有效期(Go duration) |
jwt.max_ttl / SEMAPHORE_JWT_MAX_TTL | string,默认 24h | 模板级 TTL 的硬上限 |
解读:开启后每个任务运行时拿到独立短令牌,外部系统(如云 API 网关)用 JWKS 端点验签即可信任任务身份,避免在任务里长期存放大凭证——这是「凭证瘦身」的标准做法。模板侧可按需缩短 TTL,但不超过 max_ttl。
5.10 通知(Notifications)
八类告警渠道,均为「总开关 + 渠道参数」结构:
| 参数 / 环境变量 | 说明 |
|---|---|
email_alert + email_sender/email_host/email_port/email_username/email_password/email_secure/email_tls/email_tls_min_version | SMTP 邮件告警;email_secure 走 StartTLS,email_tls 走 SSL/TLS 直连;email_tls_min_version 默认 1.2 |
telegram_alert + telegram_chat + telegram_token | Telegram;token 来自 BotFather,chat 为目标 Chat ID |
slack_alert + slack_url | Slack webhook |
rocketchat_alert + rocketchat_url | Rocket.Chat webhook(v2.9.56 起) |
microsoft_teams_alert + microsoft_teams_url | Teams webhook |
dingtalk_alert + dingtalk_url | 钉钉 webhook(国内团队常用) |
gotify_alert + gotify_url + gotify_token | Gotify 自托管推送 |
邮件渠道最小可用模板(StartTLS 形态):
{
"email_alert": true,
"email_sender": "semaphore@example.com",
"email_host": "smtp.example.com",
"email_port": "587",
"email_username": "semaphore@example.com",
"email_password": "SMTP密码",
"email_secure": true
}
逐项说明:587 端口 + email_secure: true(StartTLS)是最常见的内网 SMTP 组合;465 端口的 SSL 直连改用 email_tls: true。密码属敏感项,生产建议用环境变量 SEMAPHORE_EMAIL_PASSWORD(或 _FILE 形态)注入而非写进 config.json。
钉钉渠道(与官方模板同构):
{
"dingtalk_alert": true,
"dingtalk_url": "https://oapi.dingtalk.com/robot/send?access_token=你的机器人token"
}
5.11 日志与指标(Logging and metrics)
| 参数 / 环境变量 | 版本 | 说明 |
|---|---|---|
metrics.enabled / SEMAPHORE_METRICS_ENABLED | 社区 | 开放 Prometheus 指标端点(⚠️ 实测 v2.19.17 未生效,详见本节末尾实测结论) |
metrics.username / metrics.password | 社区 | 指标端点的 HTTP Basic Auth(留空 = 无认证) |
log.events.enabled/format/logger | Pro | 事件日志开关/格式(json 或文本)/输出器 |
log.tasks.enabled/format/logger/result_logger | Pro | 任务日志同上四项 |
syslog.enabled/network/address/tag/format | Pro | 输出到 Syslog(udp/tcp,rfc5424 可选) |
Prometheus 接入实测(v2.19.17 现状结论):配置项在官方 Reference 中存在,但实测 v2.19.17 镜像中该特性未生效。实测过程:向 config.json 追加 metrics 块(enabled/username/password)重启,端点无变化;再以环境变量方式强制注入重建(容器内 printenv 确认三个变量已生效):
docker exec semaphore-v2.19.17-web printenv | grep METRICS
SEMAPHORE_METRICS_USERNAME=metrics
SEMAPHORE_METRICS_ENABLED=true
SEMAPHORE_METRICS_PASSWORD=q1w2e3r4
探测常见候选路径的真实结果:
curl -su metrics:q1w2e3r4 -o /dev/null -w '%{http_code}' http://localhost:8151/metrics
200
(200 是假象——返回体是 Web UI 的 HTML 页面而非指标文本;/api/metrics 返回 404,/debug/metrics 同样是 HTML 页面且不校验认证。)
结论:v2.19.17 的 metrics 端点路由未注册(请求落入 Web UI 的 SPA fallback),无论 config.json 还是环境变量方式均无法激活。该配置项对应的实现大概率在 v2.20 线(Reference 页面由源码主线生成,可能领先于 v2.19 稳定线)。在 v2.19.17 上需要监控指标时,建议以 API/进程探测为主,勿在生产依赖该端点。
5.12 团队与邀请(Teams and invitations)
| 参数 / 环境变量 | 类型 / 默认 | 说明 |
|---|---|---|
teams.invites_enabled / SEMAPHORE_TEAMS_INVITES_ENABLED | boolean | 允许用户邀请成员进团队 |
teams.invite_type / SEMAPHORE_TEAMS_INVITE_TYPE | string,默认 username | 邀请标识类型:username / email / both |
teams.members_can_leave / SEMAPHORE_TEAMS_MEMBERS_CAN_LEAVE | boolean | 允许成员自行退出团队 |
5.13 订阅 / 高可用 / 审计 / 调试
| 参数 / 环境变量 | 版本 | 说明 |
|---|---|---|
subscription.key / SEMAPHORE_SUBSCRIPTION_KEY | — | Pro/Enterprise 订阅密钥;设置后 Web 端激活入口禁用 |
subscription.key_file / SEMAPHORE_SUBSCRIPTION_KEY_FILE | — | 密钥文件路径 |
subscription.server_url / SEMAPHORE_SUBSCRIPTION_SERVER_URL | — | 计费服务器,默认 https://portal.semaphoreui.com/billing |
ha.enabled / SEMAPHORE_HA_ENABLED | Enterprise | 高可用模式开关 |
ha.node_id / SEMAPHORE_HA_NODE_ID | Enterprise | 节点 ID(留空自动生成) |
ha.redis.addr/db/pass/user/tls/tls_skip_verify | Enterprise | HA 用的 Redis 连接参数(localhost:6379 形态) |
audit.enabled / SEMAPHORE_AUDIT_ENABLED | 社区 | 审计日志开关 |
audit.instance_id / SEMAPHORE_AUDIT_INSTANCE_ID | 社区 | 实例名(启用审计必填) |
audit.trusted_proxy_cidrs | 社区 | 信任的代理网段(取真实客户端 IP 用) |
audit.retention_days / SEMAPHORE_AUDIT_RETENTION_DAYS | 社区 | 审计事件保留天数,0 = 永久 |
audit.syslog.*(id/address/timeout/ca_file/server_name) | Pro | 审计输出到 Syslog |
audit.splunk_hec.*(id/url/token/index/source/sourcetype/timeout/ca_file/server_name) | Pro | 审计输出到 Splunk HEC(source 默认 semaphore,sourcetype 默认 semaphore:audit) |
debugging.api_delay / SEMAPHORE_API_DELAY | 调试 | 给 API 响应人为加延迟(排障用) |
debugging.pprof_dump_dir / SEMAPHORE_PPROF_DUMP_DIR | 调试 | pprof dump 目录 |
审计最小启用:
{
"audit": {
"enabled": true,
"instance_id": "semaphore-prod-01",
"retention_days": 180
}
}
(instance_id 必填,否则启用失败;180 天保留期兼顾合规与库体积。)
六、生产配置模板
适用场景:8GB 内存 / 4 核 / SSD,10–50 人团队,MySQL 方言,TOTP 双因子,任务并发 10,Prometheus 监控,钉钉告警。完整 config.json(密钥值请用 head -c32 /dev/urandom | base64 现场重新生成,勿复用本文示例值):
{
"mysql": {
"host": "mysql:3306",
"user": "semaphore",
"pass": "数据库密码",
"name": "semaphore"
},
"dialect": "mysql",
"tmp_path": "/data/semaphore/tmp",
"dirs": {
"secrets": "/data/semaphore/secrets"
},
"port": ":3000",
"web_host": "https://semaphore.example.com",
"cookie_hash": "会话哈希密钥",
"cookie_encryption": "会话加密密钥",
"access_key_encryption": "KeyStore加密密钥",
"mfa": {
"totp": {
"enabled": true,
"allow_recovery": true
}
},
"auth": {
"max_session_life_hours": 12
},
"git_client": "cmd_git",
"git_attempts": 6,
"max_parallel_tasks": 10,
"max_task_duration_sec": 3600,
"max_tasks_per_template": 100,
"schedule": {
"timezone": "Asia/Shanghai"
},
"forwarded_env_vars": ["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY"],
"dingtalk_alert": true,
"dingtalk_url": "https://oapi.dingtalk.com/robot/send?access_token=你的机器人token",
"audit": {
"enabled": true,
"instance_id": "semaphore-prod-01",
"retention_days": 180
}
}
逐域解读:数据库四要素来自部署篇环境变量(此处与环境变量保持一致,冲突时环境变量赢);tmp_path/dirs.secrets 移到 /data 独立分区,避免占满系统盘;git_attempts 调到 6 应对偶发抖动的内网 GitLab;forwarded_env_vars 保证代理链路对任务与 git 子进程都生效;钉钉告警给值班;审计 180 天。监控方面注意:metrics 项在 v2.19.17 实测未生效(见 5.11 节实测结论),故本模板未纳入;改完执行 docker compose restart semaphore 并按第三节 3.2 的方法逐项验证生效。
七、常见问题(FAQ)
Q1:改了 config.json 不生效。
定位:config.json 只在启动时读取。确认是否漏了重启;再确认该参数是否被环境变量覆盖(环境变量优先)——docker inspect <semaphore容器> --format '{{json .Config.Env}}' | tr ',' '\n' | grep SEMAPHORE 可列出注入的全部环境变量。
解决:改环境变量就改 Compose 文件后 docker compose up -d 重建;改文件就 docker compose restart semaphore 后按 3.2 的行为验证法确认。
Q2:git 克隆报 fatal: Authentication failed,但密码确认没错。
定位:典型 corporate proxy 场景——Semaphore 的代理变量没有转发给 git 子进程,内部仓库请求走了外部代理被拒(官方文档原文给出的故障样例,报错即 fatal: Authentication failed for 'https://git.corp.example.com/team/_git/infra')。
解决:forwarded_env_vars 显式加上三件套:["HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY"](小写环境并存的再补小写三件套),重启后实测克隆恢复。顺带提醒:git_attempts 调大只对网络抖动有效,这种确定性失败重试多少次都一样。
Q3:Key Store 里的密钥突然全部解密失败。
定位:access_key_encryption 被改动或环境变量注入了新密钥,而数据库里的条目还是旧密钥加密的。
解决:改回原密钥重启即可恢复。换密钥的正确姿势是走密钥轮换(encryption.keys_file 密钥环 + semaphore vaults rekey 重新加密存量数据,CLI 用法见命令详解篇),直接换单值密钥必丢数据可读性。预防:三个密钥从第一天就纳入与数据库同级的备份策略。
Q4:定时任务没按本地时间触发。
定位:schedule.timezone 默认 UTC,与 Compose 里设的 TZ 是两回事——TZ 只影响日志时间戳,定时调度只认 schedule.timezone。
解决:config.json 加 "schedule": {"timezone": "Asia/Shanghai"},重启后按本地时间核对下次触发点。
Q5:首次启动报 panic: open /etc/semaphore/config.json: permission denied。
定位与解决:挂载的配置目录对镜像内 UID 1001 不可写。宿主机执行 chown -R 1001:0 /opt/semaphore/data/semaphore-config 后重建服务(完整排障实录见部署篇 FAQ 2)。
八、参考链接
- 官方配置 Reference(源码生成,与 v2.19.17 对应):https://semaphoreui.com/docs/reference/configuration
- 官方配置文件文档:https://semaphoreui.com/docs/admin-guide/configuration/config-file
- 官方环境变量文档:https://semaphoreui.com/docs/admin-guide/configuration/env-vars
- GitHub 仓库:https://github.com/semaphoreui/semaphore
- 本专栏相关文档:《Semaphore v2.19.17 介绍与选型指南》(认知与选型)、《Semaphore v2.19.17 Docker Compose 部署指南》(部署与排障实录)、《Semaphore v2.19.17 常用 CLI 命令与工具详解》(CLI 子命令实测)