在 GitLab CI/CD 里跑 Claude Code:与 GitHub Actions 不通用的那几处
如果你的代码托管在自建或 SaaS 版 GitLab 上,想让 Claude Code 参与流水线,第一件会撞墙的事是:网上能搜到的绝大多数配置都是 GitHub Actions 的写法,而那套写法在 GitLab 上一行都用不了。
不是语法差异那么简单。GitHub 那边官方文档给的是一个现成的 Action——工作流里写 uses: anthropics/claude-code-action@v1,再用 with: 传 prompt、claude_args、anthropic_api_key 这些输入项,剩下的事情由 Action 内部完成。GitLab 这边,官方文档《Claude Code GitLab CI/CD》页给出的形态完全不同:没有可以 uses 的封装,你在 .gitlab-ci.yml 里写一个普通 job,自己把 CLI 装进容器,自己拼命令行。所以两边的”配置字段”根本不是同一批东西——GitHub 侧你填的是 Action 的输入项,GitLab 侧你填的是 GitLab 的 job 关键字加环境变量。
这篇就把 GitLab 侧真正要写的那些字段逐个过一遍。
前置条件:先确认这几件事成立
第一,这是 beta。 官方文档在这一页顶部明确写着 Claude Code for GitLab CI/CD 目前处于 beta,功能与行为可能继续调整。同一段还写明:这个集成由 GitLab 维护,寻求支持的入口是文档里给出的那条 GitLab issue,而不是 Anthropic 的渠道。这一点值得在立项前就跟团队说清楚,它决定了出问题时你去哪里提问。
第二,你要有改 .gitlab-ci.yml 的权限,以及往项目里加 masked CI/CD 变量的权限。 官方文档把加变量这步写成在项目设置里添加 masked 变量,原文给出的位置是 Settings → CI/CD → Variables,变量名 ANTHROPIC_API_KEY,并注明可以按需要再设为 protected。
第三,选定 provider。 这一页列出的运行方式有三种:Claude API(SaaS)、Amazon Bedrock(基于 IAM 的访问)、Google Cloud’s Agent Platform(GCP 原生、走 Workload Identity Federation)。后两种在文档里各自列了一段前置条件,核心是要先把 OIDC 身份联合配好,后面单独说。
第四,别指望”评论里 @claude 就会自动跑”是开箱即用的。 官方文档在手动配置一节把它列为可选步骤,并写明做法是:给项目加一个 “Comments (notes)” 的 webhook 指向你自己的事件监听器,由这个监听器在检测到评论包含 @claude 时去调 GitLab 的 pipeline trigger API,并带上 AI_FLOW_INPUT、AI_FLOW_CONTEXT 这类变量。也就是说,mention 触发这一环需要你自己搭一个服务,文档里那句 “if you use one”(如果你用了监听器)就是这个意思。
步骤:每个字段在改什么
官方文档的快速配置给的是一个最小 job。下面按它给出的字段逐个说明改的是什么:
stages:
- ai
claude:
stage: ai
image: node:24-alpine3.21
# Adjust rules to fit how you want to trigger the job:
# - manual runs
# - merge request events
# - web/API triggers when a comment contains '@claude'
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
variables:
GIT_STRATEGY: fetch
before_script:
- apk update
- apk add --no-cache git curl bash
- curl -fsSL https://claude.ai/install.sh | bash
# The installer places claude in ~/.local/bin, which isn't on PATH in this image
- export PATH="$HOME/.local/bin:$PATH"
script:
# Optional: start a GitLab MCP server if your setup provides one
- /bin/gitlab-mcp-server || true
# Use AI_FLOW_* variables when invoking via web/API triggers with context payloads
- echo "$AI_FLOW_INPUT for $AI_FLOW_CONTEXT on $AI_FLOW_EVENT"
- >
claude
-p "${AI_FLOW_INPUT:-'Review this MR and implement the requested changes'}"
--permission-mode acceptEdits
--allowedTools "Bash Read Edit Write mcp__gitlab"
--debug
image:这是你自己指定的运行环境。GitHub 那边的 Action 自带运行逻辑,GitLab 这边容器里有什么全看你写什么。官方示例用的是一个 Node 的 Alpine 镜像。rules:决定这个 job 什么时候进流水线。示例给的两条按$CI_PIPELINE_SOURCE判断——"web"(网页/API 触发)和"merge_request_event"(MR 事件)。注释里还提到手动运行这一路。这里就是”触发条件”的落点:GitHub 侧靠 Action 的trigger_phrase之类输入,GitLab 侧靠你写rules加外部触发。variables: GIT_STRATEGY: fetch:GitLab 的仓库拉取策略关键字,写在 job 级variables下。before_script:装依赖和装 CLI。示例先apk update、apk add --no-cache git curl bash,再curl -fsSL https://claude.ai/install.sh | bash。- 紧跟的那行
export PATH="$HOME/.local/bin:$PATH"是最容易漏的一行。 官方注释直接写明了原因:安装器把claude放在~/.local/bin,而这个目录在该镜像里不在 PATH 上。漏了这行,后面调claude就是找不到命令。 script里的/bin/gitlab-mcp-server || true:官方注释写的是”可选:如果你的环境提供了 GitLab MCP server 就启动它”。这个二进制从哪来、怎么装,这一页没有说明这一点。|| true是 shell 的写法,作用是这条命令返回非零时整个script不因此中断,官方文档没有解释为什么要这样写。AI_FLOW_INPUT/AI_FLOW_CONTEXT/AI_FLOW_EVENT:官方注释写明这组变量用于”通过 web/API 触发并带上下文负载”的场景。它们不是 GitLab 内置变量,是前面那个自建监听器调 trigger API 时塞进来的。示例里-p "${AI_FLOW_INPUT:-'...'}"用了 shell 的默认值写法,没有外部输入时退回到一句固定提示词。- 命令行部分:
-p传指令、--permission-mode acceptEdits、--allowedTools "Bash Read Edit Write mcp__gitlab"、--debug。注意 这一页并没有解释acceptEdits这个 permission mode 的具体语义,只是把它写在示例里,要弄清它允许什么、拦什么,得去查权限相关的文档页。
变量这一侧,官方文档在手动配置一节还写明了 GitLab API 操作的凭证:默认用 CI_JOB_TOKEN,或者创建一个带 api scope 的 Project Access Token,用 PAT 时以 GITLAB_ACCESS_TOKEN 存成 masked 变量。
走 Bedrock 或 Google Cloud 时多出来的字段
这两条路的共同点是不存长期密钥,靠 GitLab 的 OIDC token 去换云厂商凭证。GitLab 侧新出现的关键字是 id_tokens::
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
官方文档写明:GitLab 由这个 id_tokens: 块签发 job 的 OIDC token 并以 GITLAB_OIDC_TOKEN 暴露出来;aud 要填你在云侧那个 OIDC 身份提供方上配置的 audience 值,文档举的例子是你的 GitLab 实例地址。这个值两边必须对得上。
Amazon Bedrock 那条路要的 CI/CD 变量是 AWS_ROLE_TO_ASSUME(IAM role 的 ARN)和 AWS_REGION,job 的 variables 里再置 CLAUDE_CODE_USE_BEDROCK: "1"。示例的 before_script 把 token 写进 /tmp/oidc_token,用 aws sts assume-role-with-web-identity 换出临时凭证,再 jq 解出三个 AWS_* 环境变量。
Google Cloud’s Agent Platform 那条路要的是 GCP_WORKLOAD_IDENTITY_PROVIDER(文档特别注明:填不带 //iam.googleapis.com/ 前缀的 provider 资源名)、GCP_SERVICE_ACCOUNT、GCP_PROJECT_ID、CLOUD_ML_REGION,job variables 里置 CLAUDE_CODE_USE_VERTEX: "1" 与 ANTHROPIC_VERTEX_PROJECT_ID。示例把一份 type: external_account 的凭证配置写到 /tmp/cred.json,其中 credential_source.file 指向前面那个 token 文件,再用 GOOGLE_APPLICATION_CREDENTIALS 指向它,让凭证通过 Application Default Credentials 被读到。
以上均为官方文档中给出的示例片段,我们没有做过实测;参数语义以官方文档与 claude --help 的实际输出为准。
边界:这一页没有覆盖的地方
Windows。 官方这一页给的三个 job 示例,两个跑在 Alpine 容器里(apk),一个跑在 Google Cloud CLI 的镜像里(apt-get),装 CLI 用的都是同一条 shell 安装脚本。在 Windows runner 上怎么装、怎么跑,官方文档没有说明这一点。 如果你的 GitLab runner 是 Windows executor,照抄这两段不成立,得先确认能不能改用 Linux runner 或容器。另外,本机在 Windows 上编辑 .gitlab-ci.yml 与 runner 是什么系统是两回事——编辑器的换行符与编码设置属于通用工程注意事项,非本页官方内容,这里只提醒一句。
订阅制凭证。 GitHub Actions 那一页写明了两种认证方式,除 API key 外还有 CLAUDE_CODE_OAUTH_TOKEN(用订阅认证的 OAuth token,由 claude setup-token 生成)。GitLab 这一页只写了 ANTHROPIC_API_KEY,我们在其中没有找到订阅 token 的对应说明。
谁能触发。 GitHub 那一页专门有一节讲触发者校验:写权限检查、机器人检查、allowed_bots、allowed_non_write_users。GitLab 这一页没有写对应机制,它讲的安全边界是另一套表述:文档自述每次交互跑在有网络与文件系统规则约束的容器里、Claude Code 施加工作区范围的写入权限、所有改动经由 MR 让评审者看到 diff 且审批流程照常生效。这是文档的说法,不等于你可以省掉自己的评审——同一页的安全建议里也写着”像对待任何其他贡献者一样评审 Claude 的 MR”,以及限制 job 权限与网络出口。具体权限边界请以权限文档能核到的部分为准。
Microsoft Foundry。 GitHub Actions 那一页列了它,GitLab 这一页的 provider 里没有出现,我们没有找到对应说明。
一处口径不一致,值得单独记一笔。 GitHub Actions 页把 --allowedTools 描述为”逗号分隔的工具列表”,而 GitLab 页的三个示例里写的都是 --allowedTools "Bash Read Edit Write mcp__gitlab",空格分隔。两处白纸黑字就是这样写的,这里只把它们并排指出来。真要落地时,以 claude --help 在你那个版本上的实际输出为准——GitLab 页自己也有一条注记说明:确切的 flag 与参数可能随版本变化,建议在 job 里跑 claude --help 看支持哪些选项。
控量的字段官方也点了名:--max-turns 限制来回轮次,GitLab 的 job 级 timeout 关键字限制总执行时长(文档举的写法是 timeout: 30m),再配合并发限制控制并行运行数。
怎么验证配对了
官方文档给的第一步验证很直接:加完 job 和变量后,从流水线页面手动跑一次这个 job(原文写的位置是 CI/CD → Pipelines),或者从一个 MR 触发它。示例里已经带了 --debug,日志能给你更多线索。
排障时按官方 troubleshooting 的三组对照着看:
| 现象 | 官方文档给的检查点 |
|---|---|
@claude 没反应 | 确认流水线确实被触发了(手动、MR 事件,或经由 note 事件监听器/webhook);确认 ANTHROPIC_API_KEY 或云厂商变量存在;确认评论里是 @claude 而不是 /claude,且 mention 触发已配置 |
| job 不能发评论或开 MR | 确认 CI_JOB_TOKEN 在该项目上权限足够,或改用带 api scope 的 Project Access Token;确认 --allowedTools 里启用了 mcp__gitlab;确认 job 跑在 MR 上下文里,或通过 AI_FLOW_* 变量拿到了足够上下文 |
| 认证报错 | Claude API:确认 ANTHROPIC_API_KEY 有效未过期。Bedrock / Google Cloud’s Agent Platform:核对 OIDC/WIF 配置、role 与服务账号模拟、变量名,以及区域与模型可用性 |
第二条那个”确认 --allowedTools 里有 mcp__gitlab”值得和前面那行 /bin/gitlab-mcp-server || true 并排读:官方文档把”job 不能发评论或开 MR”这个现象下的检查点写成了三条并列——token 权限、--allowedTools 里有没有 mcp__gitlab、job 有没有拿到 MR 上下文。也就是说,同一个现象在文档口径里对应三处不同的配置,排查时三处都要过一遍,不能只看到第一条就收工。至于每一处配错时日志会打印什么,这一页没有说明这一点。
最后一句实话:这一页目前是 beta,且由 GitLab 维护。把它放进关键流水线之前,先按上面的字段清单把每一项在你自己的项目里核一遍,而不是把示例整段贴进去等它自己跑通。
本文依据 Claude Code 官方文档(code.claude.com/docs)于 2026-08-17 的公开内容整理。
该产品闭源,本文只复述官方文档写明的机制,不推断其内部实现;
我们没有对文中涉及的功能做过实测,因此不涉及界面外观、操作手感与运行速度的任何描述。
该产品迭代频繁,文中涉及的命令、配置项与默认值随版本变动,请以官方文档最新内容为准。
本文不涉及价格、额度与限流的具体数值,相关信息请以官方定价与用量说明页为准。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。