勇往直前plus头像

CI-CD详解-从GitLab流水线到Runner自动化部署

前言

代码从提交到上线,中间隔着检查、构建、部署一长串重复动作,靠人盯既慢又容易出错。CI/CD 就是把这套流程自动化、标准化的工程实践。

本文以 GitLab 为例,从概念、流水线、Runner 一直讲到怎么把 Claude Code 这类 AI 工具挂进流水线,把整个机制串清楚。


一、CI/CD 是什么

CI/CD 是两个概念拼起来的:

  • CI(Continuous Integration,持续集成):开发人员提交代码后,自动跑检查和测试,确认这批代码能安全合进主仓库。
  • CD(Continuous Delivery / Deployment,持续交付 / 部署):把验证过的代码或构建产物,按标准方式交付或部署到目标环境。

先看一个最关键的区别:

维度CICD
核心目标验证代码能否安全集成把版本交付或部署出去
主要工作静态检查、单测、构建验证发镜像、部署服务器、健康检查、回滚
执行时机提交代码、创建/更新 MR分支更新、版本发布、人工批准
最终结果检查通过 / 产出可交付物版本具备发布条件 / 已部署

重点:CI 和 CD 是按工程职责划分的概念,不是两个必须独立部署的软件系统。 比如"构建 Docker 镜像"这件事,既可以是 CI 阶段的构建验证,也可以是 CD 发版前的产物准备——边界是团队自己定的,没有绝对命令级分界。

CD 自己还有两种含义,别混淆:

  • 持续交付(Continuous Delivery):自动备好可发布版本,但生产发布保留人工审批。
  • 持续部署(Continuous Deployment):检查全过就自动部署到生产,不要人工批准。

一个典型流程长这样:

开发人员提交代码
       ↓
创建 MR / PR
       ↓
CI:自动检查、测试
       ↓
检查通过,合并代码
       ↓
构建并保存 Docker 镜像
       ↓
CD:交付或部署新版本
       ↓
目标服务器更新容器
       ↓
健康检查、验证运行

⚠️ 两句话钉死认知:CI 通过 ≠ 代码已上线;代码合并成功 ≠ 服务器已更新。 中间每一步都隔着一道门。


二、GitLab 流水线三件套:Pipeline / Stage / Job

1. 先说 MR:提交代码怎么变成"待办任务"

多人协作里,谁都不会直接往 main / develop 上写,而是开功能分支:

main                   生产分支
develop                集成开发分支
feature/sem            SEM 功能分支
feature/questionnaire  问卷功能分支

在 feature/sem 上写完:

git add .
git commit -m "feat: implement SEM"
git push origin feature/sem

然后申请把它合并到 develop。这个"申请合并"的动作:

  • GitHub 叫 PR(Pull Request)
  • GitLab 叫 MR(Merge Request)

本质都是一回事:请求把源分支合进目标分支。

易错点:PR/MR 本身不是 CI,它只是一个"可能触发 CI 的协作事件"。 真正的 CI 是 MR 创建后 GitLab 自动跑的那批检查。如果目标分支受保护,检查没过就不让合。

2. Pipeline / Stage / Job

GitLab 的自动化靠 Pipeline(流水线)组织,里面三个层次:

概念含义
Pipeline一次完整的流水线运行
Stage流水线里的逻辑阶段
Job一个具体任务,比如 pytest、docker build

结构示意:

Pipeline
│
├── Stage: check
│   ├── Job: python-static
│   ├── Job: frontend-types
│   └── Job: ai-review
│
├── Stage: build
│   └── Job: docker-build
│
└── Stage: deploy
    └── Job: deploy-test

规则很简单:同一 Stage 里的多个 Job 并行跑,下一个 Stage 等上一个 Stage 全部成功才开始。想打破"阶段串行"的默认行为,可以用 needs 显式声明 Job 间依赖,玩出更灵活的执行图。

3. 什么时候触发?

很多人以为"只有创建 MR 才触发 CI",其实触发方式很多:

事件典型用途
git push检查新提交
创建/更新 MR质量检查、代码审查
MR 合并到 develop构建镜像、部署测试环境
创建 Git Tag发布指定版本
手动运行 Pipeline人工触发构建/部署
定时任务周期性测试、安全扫描
API / 其他 Pipeline跨系统编排

核心机制是事件驱动:GitLab 收到事件后,读仓库里的 .gitlab-ci.yml,判断要不要建 Pipeline、跑哪些 Job。

看一段最小可读的 .gitlab-ci.yml:

stages:
  - check
  - deploy

# CI:代码检查
ci_check:
  stage: check
  image: python:3.11
  script:
    - python -m compileall -q .
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'

# CD:部署测试环境
deploy_test:
  stage: deploy
  needs: [ci_check]
  tags:
    - deploy-runner
  script:
    - ssh "$DEPLOY_USER@$DEPLOY_HOST" "cd /srv/app && docker compose pull && docker compose up -d"
  rules:
    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'

字段含义:

  • stages:定义有哪些阶段。
  • script:Job 里要执行的命令。
  • rules:Job 在什么条件下运行。
  • needs:声明任务依赖(可跨 Stage)。
  • tags:选择带特定标签的 Runner 来跑。

这段配置干了两件事:创建 MR 时跑 CI 检查;代码合进 develop 后再跑一次 CI,过了就部署测试环境。

CI 和 CD 可以写在同一个 YAML 里,也可以拆成多个文件,甚至跑在不同项目的不同流水线里——怎么切是工程选择,不是技术限制。


三、GitLab Runner:真正干活的人

到这里有个核心疑问:

GitLab 本身是个代码托管平台,它怎么去执行 Python 测试、Docker 构建、SSH 部署这些活? 它又不会在你服务器上长出手脚。

答案就是 GitLab Runner。

1. Server 和 Runner 谁干什么

CI/CD 里其实是三个角色:

组件职责
GitLab Server管仓库、解析配置、创建并调度 Job
GitLab Runner领 Job、准备环境、跑命令、上报结果
部署服务器跑最终发布的业务系统

Runner 本质是一个独立的任务执行程序,可以装在任意一台 Linux 服务器、虚拟机或容器里。它不一定在 GitLab 服务器上,也不一定在测试服务器上——它是单独的"工人"。

常见架构:

               GitLab Server
                     │
              HTTP API 通信
                     │
                GitLab Runner
                     │
           ┌─────────┴─────────┐
           │                   │
        CI 检查              CD 部署
           │                   │
     Python / Node.js       SSH / Docker
     Claude Code                │
                         测试 / 生产服务器

GitLab.com 提供共享 Runner;公司自建 GitLab 一般要自己装 Runner。Runner 软件免费,但跑它的机器要算计算资源和维护成本。

2. Runner 怎么领任务?

Runner 是主动拉任务,不是被动等推送。流程:

GitLab 收到代码事件
        ↓
读取 CI/CD 配置
        ↓
创建 Pipeline 和 Jobs
        ↓
Runner 向 GitLab API 请求 Job
        ↓
GitLab 返回可执行 Job
        ↓
Runner 准备执行环境
        ↓
拉代码,执行 script
        ↓
上传日志、产物和执行状态

Runner 通过 GitLab Jobs API 领活:

POST /api/v4/jobs/request

拿到 Job 后,根据 Executor(执行器) 类型准备运行环境:

  • Shell Executor:直接用宿主机 Shell 跑命令。
  • Docker Executor:在一个 Docker 容器里跑 Job。
  • Kubernetes Executor:用 K8s Pod 跑 Job。

易错点:Runner 所在的机器,和 Job 实际执行的环境,不一定是同一个进程或容器。 比如用 Docker Executor 时,Runner 只负责"调度管理",真正的检查命令跑在它拉起来的 Job 容器里。这俩是分开的。


四、Runner 怎么调用 Claude Code 这类工具

这是很多人会卡住的地方:Runner 怎么"集成" Claude Code?

答案是:根本不用集成它的内部代码。 Runner 只需要在 Job 脚本里启动 Claude Code CLI,就像调用 pytest、npm、docker 一样自然。

Claude Code 除了交互模式,还支持非交互式命令行调用:

claude -p "检查当前代码中的安全问题" \
  --output-format json

在 Python 里也能用 subprocess 调:

import subprocess

result = subprocess.run(
    [
        "claude",
        "-p",
        "检查本次代码变更中的安全问题",
        "--output-format",
        "json",
    ],
    capture_output=True,
    text=True,
    timeout=600,
)

print(result.stdout)

底层调用链:

GitLab Server
     │  HTTP API
     ▼
GitLab Runner
     │  执行 Job 脚本
     ▼
Shell / Python 进程
     │  subprocess 启动子进程
     ▼
Claude Code CLI
     │  HTTPS API
     ▼
Claude 模型服务
     │  返回分析结果 + 工具调用请求
     ▼
Claude Code 执行允许的本地工具
     ▼
返回审查报告
     ▼
审查脚本解析结果,决定是否通过
     ▼
Runner 上报 GitLab

这里有两层通信,要分清楚:

第一层:Runner ↔ 本地程序。 Runner 跑脚本,脚本启动 Claude Code 子进程,靠命令行参数传任务、靠标准输出/标准错误/退出码收结果。

第二层:Claude Code ↔ 远程模型。 CLI 跑在本地执行环境里,通过 HTTPS 调远端模型。一次 claude -p 内部可能包含多轮模型调用、文件读取和工具使用,不一定只对应一次大模型 API 请求。

⚠️ 关键认知:模型成功返回报告 ≠ 审查通过。 比如模型发现了高危漏洞,Claude Code 进程可能照样正常退出(退出码 0),但你的审查脚本可以读 JSON 里的风险等级,主动返回非零退出码,让 GitLab 把这个 Job 标红失败。门禁逻辑握在你脚本手里,不在模型手里。

另外,无人值守运行需要配好模型 API 凭证、工具权限和执行环境;凭证走 CI/CD Variables / 密钥管理,绝不硬编码进仓库。


五、实战:从 MR 检查到自动部署

以一个 FastAPI + Vue + Docker 的科研应用为例,公司用 GitLab 管代码。

1. 已有的 CI 代码集成流程

开发人员在 feature/sem 上写完功能:

git add .
git commit -m "feat: 完成 SEM 功能"
git push origin feature/sem

然后创建 feature/sem → develop 的 Merge Request。GitLab 自动建流水线,跑四项检查:

Job功能
policy-and-staticPython 语法、静态问题、仓库规范检查
frontend-types前端 TypeScript 类型检查
secret-scan敏感密钥泄露扫描
ai-review用 Claude Code 做安全、业务、架构审查

检查失败 → 改代码、再 push 到原分支 → 重新触发检查。
检查全过、无冲突、结果仍有效 → 自动合并机器人把 MR 合进 develop。

到这里完成的是"代码质量门禁 + 持续集成",并不代表服务器已经发版。 别把"合并"和"上线"画等号。

2. CD 怎么接进来?

develop 更新后,可以再串一段自动部署:

develop 分支更新
        ↓
触发 CI/CD Pipeline
        ↓
验证代码
        ↓
构建 Docker 镜像
        ↓
推送镜像仓库
        ↓
执行 CD 部署 Job
        ↓
Runner 通过 SSH 访问测试服务器
        ↓
拉新镜像、更新容器
        ↓
健康检查

Runner 通过 SSH 在服务器上执行部署命令:

ssh deploy@server \
  "cd /srv/app && docker compose pull && docker compose up -d"

部署完用 docker ps 看运行中的容器和镜像版本。生产环境还能加人工审批、灰度发布、健康检查和回滚。

这一步要求提前备好:SSH 授权、网络连通、镜像仓库权限、服务器上的 Docker Compose 配置。少一样都跑不通。


六、踩坑点与总结

踩坑点

  1. 把"用了 GitLab"等同于"全流程自动化":有些公司只做了 MR 自动检查;有些做到镜像构建;有些能自动部署生产。自动化到哪一步,取决于配置,不取决于工具。别想当然。
  2. 流水线通过 ≠ 业务正确:静态检查和 AI 审查只覆盖配置范围内的问题。统计计算、计费、权限这类敏感业务,还得靠业务测试和人工验收兜底。
  3. 配置和环境混在一起:.gitlab-ci.yml 定义任务,GitLab 设置管变量/Runner/权限,Runner 负责执行,部署服务器跑应用——各司其职,别把服务器密码、SSH 私钥、API Key 写进仓库,走受保护的 CI/CD Variables 或密钥管理服务。
  4. 分片/Executor 没分清:Runner 机器 ≠ Job 执行环境。用 Docker Executor 时改了 Runner 宿主机的环境,Job 容器里根本看不到。
  5. 以为 claude -p 退出码 0 就是审查通过:模型正常返回不代表没问题,门禁标准由你的脚本根据 JSON 内容决定,务必显式判断风险等级再定退出码。

总结

核心概念一句话理解
CI保证新代码满足集成检查要求
CD把验证过的版本交付或部署出去
PR / MR开发人员提出的代码合并申请
Pipeline一次由配置组织起来的自动化流程
Stage流水线里的逻辑阶段
Job流水线里真正要执行的任务
GitLab Server流水线管理和任务调度中心
GitLab Runner真正执行 Job 的程序
ExecutorRunner 跑 Job 用的执行机制(Shell/Docker/K8s)
.gitlab-ci.yml定义 Job、触发条件和依赖的配置文件

一句话串联: 开发人员 git push → GitLab Server 根据事件和 YAML 创建流水线 → Runner 领任务、跑脚本、调用各种工具 → CI 把质量关、CD 把发版关 → 目标服务器跑起发布后的业务。

打个比方:GitLab Server 是大脑(调度),Runner 是手脚(执行),.gitlab-ci.yml 是剧本(流程),CI 是质量门禁,CD 是发版动作。 五者齐备,"提交即上线"才算真正跑起来。

参考资料:

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_38673558/article/details/170292787

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--