Semaphore v2.19.17 配置参数详解

Semaphore v2.19.17 配置参数详解:config.json 与环境变量双通道体系、优先级规则、13 大域 130+ 配置项分类全解(数据库/Web/加密/认证/Git/任务/Runner/通知/日志)、生产配置模板与常见坑。

SemaphoreAnsibleDevOps自动化自托管自动化部署2026/10/24

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 功能分界在对应小节标注

二、前置条件

本篇是配置专题篇,不重复部署全流程,但要求具备以下条件,每项给出可独立执行的验证方法。

  1. 一套运行中的 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
  1. 能读到当前生效的 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 明示):环境变量优先于配置文件——同一参数两处都设置时,环境变量生效。三条使用建议:

  1. 部署期变量(数据库连接、初始管理员)用环境变量,随 Compose 文件版本化管理;
  2. 运行期调整(git 重试次数、任务并发、通知渠道)改 config.json,改完重启生效;
  3. 敏感值(数据库密码、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_PROVIDERSmfa.*、ldap_*、oidc_providers
GitSEMAPHORE_GIT_*、SEMAPHORE_SSH_*git_client、git_attempts、ssh.known_hosts_file
任务SEMAPHORE_MAX_PARALLEL_TASKS 等max_parallel_tasks、env_vars、process.*
RunnersSEMAPHORE_RUNNER_*、SEMAPHORE_RUNNERS_*runner.executor.*、runners.offline_timeout_sec
任务 JWTSEMAPHORE_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_HOSTstring,默认 0.0.0.0数据库主机,格式 主机:端口(如 mysql:3306)
mysql.user / SEMAPHORE_DB_USERstring数据库用户名
mysql.pass / SEMAPHORE_DB_PASSstring数据库密码(敏感)
mysql.name / SEMAPHORE_DBstring,默认 semaphore数据库名
mysql.options / SEMAPHORE_DB_OPTIONSobject追加到 DSN 的驱动选项(JSON 键值对)
dialect / SEMAPHORE_DB_DIALECTstring,默认 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_PORTstring,默认 :3000监听端口,格式 :3000;缺 : 会自动纠正
tls.enabled / SEMAPHORE_TLS_ENABLEDboolean启用 HTTPS
tls.cert_file / SEMAPHORE_TLS_CERT_FILEstringTLS 证书文件路径
tls.key_file / SEMAPHORE_TLS_KEY_FILEstringTLS 私钥文件路径
tls.http_redirect_addr / SEMAPHORE_TLS_HTTP_REDIRECT_ADDRstringHTTP→HTTPS 跳转监听地址(host[:port],与 http_redirect_port 互斥)
tls.http_redirect_port / SEMAPHORE_TLS_HTTP_REDIRECT_PORTintegerHTTP 跳转端口(与 http_redirect_addr 互斥)
interface / SEMAPHORE_INTERFACEstring绑定 IP(置于端口前),默认空
web_host / SEMAPHORE_WEB_ROOTstring对外访问主机(拼接链接用)
cookie_hash / SEMAPHORE_COOKIE_HASHstringCookie 哈希密钥(敏感,首次初始化自动生成)
cookie_encryption / SEMAPHORE_COOKIE_ENCRYPTIONstring会话 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_PATHstring,默认 /tmp/semaphore项目临时目录(仓库克隆、任务工作区根)
dirs.secrets / SEMAPHORE_SECRETS_PATHstring,默认 /tmp/semaphore密钥文件目录(Key Store 的 File 型条目、Vault/OpenBao token 文件只能放这里)
secrets_path / SEMAPHORE_SECRETS_PATHstring旧版顶层写法,仅在 dirs.secrets 未设或为默认值时生效
dirs.repos / SEMAPHORE_REPOS_DIRstring仓库存储目录
dirs.ssh_agent_sockets / SEMAPHORE_SSH_AGENT_SOCKETS_DIRstring,默认 /tmp/semaphoreSSH 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_ENCRYPTIONstring加解密 Key Store(SSH 私钥、API Token 等)的 base64 密钥;旧入口,向后兼容保留
option_encryption / SEMAPHORE_OPTION_ENCRYPTIONstringDB options(JWT 签名密钥)的旧式单密钥加密;未设时回落到 access keyring
encryption.keys_file / SEMAPHORE_ENCRYPTION_KEYS_FILEstring密钥环(keyrings)文件路径,轮换场景使用
encryption.keys_poll_interval / SEMAPHORE_ENCRYPTION_KEYS_POLL_INTERVALstring,默认 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_HOURSinteger会话绝对寿命(小时),0 = 不设绝对上限(仅按不活跃过期)
mfa.totp.enabled / SEMAPHORE_TOTP_ENABLEDboolean启用 TOTP 双因子
mfa.totp.allow_recovery / SEMAPHORE_TOTP_ALLOW_RECOVERYboolean允许用恢复码重置 TOTP
mfa.totp.app_name / SEMAPHORE_TOTP_ISSUERstring认证器 App 中显示的发行方名称
mfa.email.enabled / SEMAPHORE_EMAIL_2TP_ENABLEDboolean启用邮件多因子
mfa.email.allowed_domains / SEMAPHORE_EMAIL_2TP_ALLOWED_DOMAINSarray允许的邮箱域(JSON 数组)
ldap_enable / SEMAPHORE_LDAP_ENABLEboolean旧式单目录 LDAP 开关(配合下方 ldap_* 平铺参数)
ldap_server / SEMAPHORE_LDAP_SERVERstringLDAP 主机与端口(如 ldap.example.com:1389)
ldap_binddn / SEMAPHORE_LDAP_BIND_DNstring绑定 DN
ldap_bindpassword / SEMAPHORE_LDAP_BIND_PASSWORDstring绑定密码(敏感)
ldap_searchdn / SEMAPHORE_LDAP_SEARCH_DNstring搜索基准 DN(如 dc=example,dc=org)
ldap_searchfilter / SEMAPHORE_LDAP_SEARCH_FILTERstring用户搜索过滤器(如 (&(objectClass=inetOrgPerson)(uid=%s)))
ldap_mappings.dn/mail/uid/cn / SEMAPHORE_LDAP_MAPPING_*string,默认 dn/mail/uid/cnLDAP 属性映射
ldap_needtls / SEMAPHORE_LDAP_NEEDTLSbooleanLDAP 连接是否用 TLS
ldap_tls_skip_verify / SEMAPHORE_LDAP_TLS_SKIP_VERIFYboolean跳过 LDAP 证书校验(默认 false,不建议开)
ldap_providers / SEMAPHORE_LDAP_PROVIDERSobject多 LDAP 目录配置(键为 provider ID;ldap 键保留给旧式配置)
oidc_providers / SEMAPHORE_OIDC_PROVIDERSobjectOIDC 登录配置(键为 provider ID,出现在 /auth/oidc/<id>/login 路径中,一旦用户登录过就不可改)
password_login_disable / SEMAPHORE_PASSWORD_LOGIN_DISABLEDboolean禁用本地密码登录(配好 LDAP/OIDC 后关闭第二扇门)
external_auth_email_matching / SEMAPHORE_EXTERNAL_AUTH_EMAIL_MATCHINGstring,默认 auto外部登录按邮箱关联既有用户的策略:auto/always/never
non_admin_can_create_project / SEMAPHORE_NON_ADMIN_CAN_CREATE_PROJECTboolean允许非管理员建项目

启用 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_CLIENTstring,默认 cmd_git克隆实现:cmd_git(调系统 git)或 go_git(纯 Go 库)
git_attempts / SEMAPHORE_GIT_ATTEMPTSinteger,默认 4克隆/拉取重试次数;1 = 不重试
git_submodule_jobs / SEMAPHORE_GIT_SUBMODULE_JOBSinteger,默认 4子模块并行拉取数(仅 cmd_git)
ssh.config_path / SEMAPHORE_SSH_PATHstring自定义 SSH config 路径(默认 ~/.ssh/config)
ssh.known_hosts_file / SEMAPHORE_SSH_KNOWN_HOSTS_FILEstringknown_hosts 路径;设置后主机密钥校验变严格
ssh.strict_host_key_checkingstring,默认 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_TASKSinteger,默认 9999全局任务并发上限
max_task_duration_sec / SEMAPHORE_MAX_TASK_DURATION_SECinteger单任务最长运行秒数(超时终止)
max_tasks_per_template / SEMAPHORE_MAX_TASKS_PER_TEMPLATEinteger每个模板在库中保留的最近任务数
apps / SEMAPHORE_APPSobject应用配置(JSON map)
env_vars / SEMAPHORE_ENV_VARSobject注入任务进程的静态环境变量(JSON map)
forwarded_env_vars / SEMAPHORE_FORWARDED_ENV_VARSarray从服务进程环境显式转发给任务与 git 子进程的变量名列表
process.user/uid/gid / SEMAPHORE_PROCESS_USER/UID/GIDstring/integer任务进程运行身份
process.chroot / SEMAPHORE_PROCESS_CHROOTstring任务进程 chroot 目录
process.no_new_privs / SEMAPHORE_PROCESS_NO_NEW_PRIVSboolean置 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_TIMEZONEstring,默认 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"]'

要点与解读:

  1. env_vars 是静态键值对(值固定),forwarded_env_vars 是名字列表(值取自服务进程环境,适合密钥类:密钥用 secrets 注入服务进程,再转发给任务)。
  2. 代理三件套必须一起转发(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,把内部请求发给了外部代理。补上转发即修复。
  3. 变量名大小写敏感(Linux),小写 http_proxy 也要转发时一并列出。
  4. 自定义 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_ENABLEDboolean启用 runner 模式
runner.token / SEMAPHORE_RUNNER_TOKENstringRunner 向服务器认证的 token(由 semaphore runner register 签发,敏感)
runner.token_file / SEMAPHORE_RUNNER_TOKEN_FILEstringtoken 文件路径
runner.name / SEMAPHORE_RUNNER_NAMEstringRunner 名称
runner.tags / SEMAPHORE_RUNNER_TAGSarrayRunner 标签(JSON 数组,模板按标签调度)
runner.max_parallel_tasks / SEMAPHORE_RUNNER_MAX_PARALLEL_TASKSinteger,默认 9999该 Runner 并发上限
runner.project_id / SEMAPHORE_RUNNER_PROJECT_IDinteger限定只服务单个项目
runner.one_off / SEMAPHORE_RUNNER_ONE_OFFboolean一次性 Runner:跑完即退出(动态弹性场景,官方流程:任务入队 → 回调 webhook → 拉起一次性 Runner → 处理任务 → 退出)
runner.check_interval_seconds / SEMAPHORE_RUNNER_CHECK_INTERVAL_SECONDSinteger,默认 1轮询服务器新任务的间隔(v2.19.17 新增可配,见下)
runner.webhook / SEMAPHORE_RUNNER_WEBHOOKstringRunner webhook URL
runners.offline_timeout_sec / SEMAPHORE_RUNNERS_OFFLINE_TIMEOUT_SECinteger,默认 120心跳超时判离线(离线 Runner 的 starting 任务会被改派)
runners.task_fail_timeout_sec / SEMAPHORE_RUNNERS_TASK_FAIL_TIMEOUT_SECinteger,默认 420心跳超时判任务失败(介于离线与失败之间留给慢 Runner 复联)
runners.reconcile_interval_sec / SEMAPHORE_RUNNERS_RECONCILE_INTERVAL_SECinteger,默认 30服务器核对任务与 Runner 存活的扫描间隔
runners.default_global_runners_mode / SEMAPHORE_DEFAULT_GLOBAL_RUNNERS_MODEstring全局 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)ProDocker 执行器全套:守护地址(支持 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)ProKubernetes 执行器:默认 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_ENABLEDboolean启用任务 JWT 签发
jwt.issuer / SEMAPHORE_JWT_ISSUERstringiss 声明值
jwt.default_ttl / SEMAPHORE_JWT_DEFAULT_TTLstring,默认 1h默认有效期(Go duration)
jwt.max_ttl / SEMAPHORE_JWT_MAX_TTLstring,默认 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_versionSMTP 邮件告警;email_secure 走 StartTLS,email_tls 走 SSL/TLS 直连;email_tls_min_version 默认 1.2
telegram_alert + telegram_chat + telegram_tokenTelegram;token 来自 BotFather,chat 为目标 Chat ID
slack_alert + slack_urlSlack webhook
rocketchat_alert + rocketchat_urlRocket.Chat webhook(v2.9.56 起)
microsoft_teams_alert + microsoft_teams_urlTeams webhook
dingtalk_alert + dingtalk_url钉钉 webhook(国内团队常用)
gotify_alert + gotify_url + gotify_tokenGotify 自托管推送

邮件渠道最小可用模板(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/loggerPro事件日志开关/格式(json 或文本)/输出器
log.tasks.enabled/format/logger/result_loggerPro任务日志同上四项
syslog.enabled/network/address/tag/formatPro输出到 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_ENABLEDboolean允许用户邀请成员进团队
teams.invite_type / SEMAPHORE_TEAMS_INVITE_TYPEstring,默认 username邀请标识类型:username / email / both
teams.members_can_leave / SEMAPHORE_TEAMS_MEMBERS_CAN_LEAVEboolean允许成员自行退出团队

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_ENABLEDEnterprise高可用模式开关
ha.node_id / SEMAPHORE_HA_NODE_IDEnterprise节点 ID(留空自动生成)
ha.redis.addr/db/pass/user/tls/tls_skip_verifyEnterpriseHA 用的 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)。

八、参考链接