📚 全栈开发学习系列
第 34 篇 · 阶段五:扩展与部署
✅ 阶段一:编程基础(1-8篇) 已完成
✅ 阶段二:Web 后端(9-16篇) 已完成
✅ 阶段三:前端深化(17-25篇) 已完成
✅ 阶段四:跨平台 App(26-30篇) 已完成
🏆 阶段五:扩展与部署 已完成
✓ 31 Tauri 桌面应用入门 ✓ 32 Docker 容器化入门 ✓ 33 Nginx 反向代理 ✓ 34 CI/CD 自动化部署
读完本篇你将能:
✓ 理解 CI/CD 的核心理念与流水线阶段
✓ 掌握 GitHub Actions 工作流配置语法
✓ 搭建一条完整的前端 CI 流水线(lint → test → build)
✓ 实现自动化部署到服务器(SSH + Docker)
✓ 了解环境变量、缓存优化与安全最佳实践

CI/CD 自动化部署:从代码提交到一键上线

全栈开发学习系列 · 第 34 篇 · 阶段五收官
📑 本篇目录
一、为什么需要 CI/CD:从手动部署的痛点说起
二、核心概念:CI、CD、流水线、工件
三、GitHub Actions 入门:工作流配置语法
四、实战一:前端项目 CI 流水线(Lint → Test → Build)
五、实战二:自动化部署到服务器(SSH + Docker)
六、进阶技巧:缓存、矩阵构建与环境变量
七、安全最佳实践:Secrets 与权限控制
八、常见错误与实战练习

一、为什么需要 CI/CD:从手动部署的痛点说起

回想一下没有自动化的日子:开发完成后,你需要手动 SSH 到服务器,拉代码、装依赖、构建、重启服务,还要祈祷这次别出问题。如果是多人协作,还得协调部署时间,生怕两个人同时改导致冲突。

手动部署的痛点几乎每个团队都经历过:

💡 生活中的比喻
CI/CD 就像工厂的自动化流水线。以前手工做产品,每个工人凭经验组装,质量参差不齐,效率也低。有了流水线后,原料从一端进去,经过一道道标准化工序(检查、组装、测试、包装),合格的产品从另一端自动出来。任何一道工序不达标,流水线就会自动停下来报警。

CI/CD 就是软件开发的"自动化流水线"。代码提交后,自动触发一系列检查和操作,全部通过后自动部署到生产环境。整个过程不需要人工干预,又快又稳。

2026 年 CI/CD 工具格局

目前主流的 CI/CD 平台各有侧重:[$TRAE_REF](https://devstarsj.github.io/devops/ci-cd/2026/03/15/cicd-comparison-github-actions-vs-gitlab-vs-circleci-vs-dagger-2026/)

平台 优势 适用场景 免费额度
GitHub Actions 生态最丰富,与 GitHub 深度集成 代码托管在 GitHub 的项目 2000 分钟/月
GitLab CI 一体化 DevSecOps 平台 企业级自托管需求 400 分钟/月
CircleCI 测试性能强,资源灵活 对构建速度要求高 1500 分钟/月
Dagger 可移植性强,本地可调试 跨平台迁移、本地调试 开源免费

本篇我们以 GitHub Actions 为主线讲解——它是目前最流行、生态最丰富的选择,而且对大多数项目来说免费额度完全够用。[$TRAE_REF](https://mecanik.dev/en/posts/ci-cd-pipeline-best-practices-for-uk-development-teams-in-2026/)

二、核心概念:CI、CD、流水线、工件

在动手之前,先搞清楚几个经常被混用的概念。

CI(持续集成)

Continuous Integration,持续集成。核心思想是:开发者频繁地把代码合并到主干,每次合并都自动构建和测试。

以前大家各写各的,到发布前才合并,一合并就是一大堆冲突,修都修不过来。CI 要求"小步快跑"——每天多次提交,每次提交后自动跑一遍检查,有问题立刻暴露,而不是攒到最后一起爆发。

CD(持续交付 / 持续部署)

CD 有两层含义,经常被混淆:

📦 持续交付
Continuous Delivery
代码随时可以安全发布,但发布按钮还是人来按。确保"随时可发",发不发由人决定。
🚀 持续部署
Continuous Deployment
代码通过所有检查后,自动部署到生产环境。全程无人干预,真正的"一键上线"。

流水线的典型阶段

一条完整的 CI/CD 流水线通常包含以下阶段,从前到后依次执行,任何一个阶段失败就中止:

阶段 做什么 失败了怎么办
检出代码 拉取代码、检出对应分支 仓库权限或网络问题
安装依赖 npm install / pip install 等 依赖包不存在或版本冲突
代码检查 Lint、格式检查、类型检查 代码风格不达标,修复后重提
单元测试 运行所有单元测试用例 测试不通过,修复 bug
构建 编译、打包、生成可部署产物 构建失败,检查代码
部署 把产物部署到目标环境 部署失败,回滚到上一版本

什么是工件(Artifact)

流水线的每个阶段可能会产生一些中间文件,比如编译后的代码、测试报告、打包好的镜像等。这些文件就叫 工件(Artifact)。

工件可以在流水线的不同 Job 之间传递,也可以保留下来供后续下载排查。比如构建阶段产出的 dist 目录,可以传给部署阶段用来发布。

三、GitHub Actions 入门:工作流配置语法

GitHub Actions 是 GitHub 内置的 CI/CD 工具,最大的优势是和 GitHub 深度集成——代码推上去自动触发,不需要额外的账号和服务器。配置文件是 YAML 格式,放在仓库的 .github/workflows/ 目录下。

核心概念

最简工作流示例

YAML - .github/workflows/ci.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 工作流名称(显示在 Actions 页面)
name: CI Pipeline
# 触发条件
on:
  push:            # 代码 push 时触发
    branches: ["main"]  # 只监听 main 分支
  pull_request:      # 提交 PR 时触发
    branches: ["main"]
# 任务定义
jobs:
  test:            # 任务名(自定义)
    runs-on: ubuntu-latest  # 运行环境
    steps:          # 步骤列表
      - uses: actions/checkout@v4  # 第一步:检出代码 ⭐
      - run: echo "Hello, GitHub Actions!"  # 第二步:执行命令

常用触发事件

事件 触发时机 常见用途
push 代码推送时 CI 检查、自动构建
pull_request 创建/更新 PR 时 合并前检查
schedule 定时触发(cron 语法) 定时任务、夜间构建
workflow_dispatch 手动点击触发 手动部署、按需运行
release 发布 Release 时 发布时自动部署生产环境

常用 Action 速查

Action 是 GitHub Actions 的精髓——社区已经写好了成千上万的可复用动作,你直接 uses 就行:

Action 用途 说明
actions/checkout@v4 检出代码 几乎每个工作流第一步都要用到
actions/setup-node@v4 安装 Node.js 指定版本,支持缓存 npm 依赖
actions/cache@v4 缓存依赖 大幅提升构建速度
actions/upload-artifact@v4 上传工件 在 Job 间传递文件
actions/download-artifact@v4 下载工件 配合 upload 使用
appleboy/ssh-action@v1.2.0 SSH 远程执行 部署到自己的服务器

四、实战一:前端项目 CI 流水线(Lint → Test → Build)

理论说够了,来实战。我们给一个 React + TypeScript + Vite 项目搭建一条完整的 CI 流水线,包含代码检查、单元测试和构建验证。

完整工作流配置

YAML - .github/workflows/ci.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: Frontend CI
on:
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]
jobs:
  lint-and-test:
    runs-on: ubuntu-latest
    strategy:          # 矩阵构建:多个 Node 版本
      matrix:
        node-version: ["18", "20", "22"]
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Setup Node.js ${{ matrix.node-version }}

继续看后面的步骤:

YAML - 续上:安装依赖、Lint、Test、Build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: "npm"            # 自动缓存 npm 依赖 ⭐
      - name: Install dependencies
        run: npm ci            # ci 比 install 更快更严格
      - name: Run linter
        run: npm run lint
      - name: Type check
        run: npx tsc --noEmit
      - name: Run unit tests
        run: npm test -- --coverage --ci
      - name: Build project
        run: npm run build
      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
💡 npm install vs npm ci
CI 环境中推荐用 npm ci 而不是 npm install。区别是:ci 会严格按照 package-lock.json 安装,版本完全一致,不会自动更新锁文件,确保每次构建的依赖都一样。而且 ci 比 install 更快,因为它跳过了某些版本协商逻辑。

五、实战二:自动化部署到服务器(SSH + Docker)

CI 通过了只是第一步,最终目的是把代码部署到服务器。最常见的方式是通过 SSH 连接服务器,然后执行部署命令。配合 Docker 的话,部署流程会更优雅。

方案一:SSH 直接部署

这是最简单直接的方式:GitHub Actions 通过 SSH 登录到你的服务器,执行拉代码、构建、重启等命令。

YAML - .github/workflows/deploy.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
name: Deploy to Server
on:
  push:
    branches: ["main"]  # 只有 main 分支才部署
  workflow_dispatch:      # 支持手动触发
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      # 通过 SSH 连接服务器并执行部署脚本
      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1.2.0
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          port: ${{ secrets.SSH_PORT }}

SSH 命令部分继续:

YAML - 续上:SSH 执行部署命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
          script: |
            # 进入项目目录
            cd /var/www/my-app
            # 拉取最新代码
            git pull origin main
            # 安装依赖并构建
            npm ci
            npm run build
            # 用 Docker Compose 重启服务
            docker compose up -d --build
            docker image prune -f

配置 Secrets(密钥)

注意上面的 ${{ secrets.XXX }} 语法——这些是存在 GitHub 仓库设置里的密钥,不会明文出现在代码和日志中。

配置位置:GitHub 仓库 → Settings → Secrets and variables → Actions → New repository secret

💡 安全小贴士
永远不要把密码、密钥、Token 等敏感信息直接写在 YAML 文件里。一定要用 Secrets 机制存储。GitHub 会自动在日志中屏蔽 Secrets 的值,即使不小心打印出来也会显示为 ***。

方案二:Docker 镜像 + 部署

更规范的做法是在 CI 中构建 Docker 镜像,推送到镜像仓库(如 Docker Hub、GitHub Container Registry),然后在服务器上拉取新镜像重启。这样做的好处是构建和部署分离,镜像可以复用,可以回滚到任意版本。

YAML - 构建 Docker 镜像并推送到 GHCR
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push
        uses: docker/build-push-action@v6
        with:

六、进阶技巧:缓存、矩阵构建与环境变量

依赖缓存:显著提速

每次 CI 都重新安装依赖是最大的时间浪费。用好缓存可以节省 80% 以上的安装时间。setup-node 的 cache: "npm" 参数已经帮你缓存了 npm 依赖,但如果需要更细粒度的控制,可以手动配置:

YAML - 手动缓存 node_modules
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Cache node_modules
        uses: actions/cache@v4
        id: cache-deps
        with:
          path: node_modules
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-
      - name: Install dependencies
        if: steps.cache-deps.outputs.cache-hit != 'true'
        run: npm ci

缓存的 key 由 package-lock.json 的哈希值决定——锁文件变了缓存就失效,确保依赖版本一致。restore-keys 提供了"降级匹配",即使精确 key 没命中,也能恢复最近的缓存,加快安装速度。

矩阵构建(Matrix)

想同时在多个 Node 版本、多个操作系统上测试?矩阵构建可以让你一份配置自动生成多组并行任务:

YAML - 矩阵构建设置
1
2
3
4
5
6
7
8
9
10
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false  # 一个失败不取消其他任务
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: ["18", "20", "22"]
        exclude:      # 排除某些组合
          - os: windows-latest
            node-version: "18"

上面的配置会生成 3 × 3 - 1 = 8 个并行任务(排除了 Windows + Node 18 的组合),同时在不同系统和 Node 版本上运行测试,确保兼容性。

环境变量与上下文

GitHub Actions 提供了丰富的内置变量和上下文,可以在工作流中直接使用:

变量 说明 示例值
github.actor 触发工作流的用户名 octocat
github.sha 当前提交的完整 SHA a1b2c3d4...
github.ref 当前分支或标签引用 refs/heads/main
github.run_number 工作流运行次数 42
runner.os 当前运行器操作系统 Linux
secrets.GITHUB_TOKEN 自动生成的仓库访问令牌 (自动注入)

七、安全最佳实践:Secrets 与权限控制

CI/CD 流水线天然拥有访问代码、服务器、云资源的权限,一旦被攻破后果严重。安全是 CI/CD 设计中不可忽视的环节。2026 年的趋势是 DevSecOps——安全不再是最后一道门,而是左移到流水线的每个阶段。[$TRAE_REF](https://ai.gravitydevops.com/articles/best-cicd-platforms-2026)

Secrets 管理的最佳实践

流水线安全加固

YAML - 安全加固配置示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: Secure Deploy
on:
  push:
    branches: ["main"]
# 限制 GITHUB_TOKEN 的默认权限(最小权限)
permissions:
  contents: read        # 只读代码
  packages: write      # 可以推送镜像
  security-events: write # 安全扫描结果
jobs:
  security-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      # 依赖漏洞扫描

PR 流水线的安全风险

开放源码项目特别要注意:外部贡献者提交的 PR 也会触发 CI,如果流水线里有 Secrets,恶意攻击者可以通过 PR 提交代码把 Secrets 偷出来。

GitHub 的默认保护机制是:外部贡献者的 PR 首次提交需要仓库成员手动批准才能运行工作流。但即便如此,也建议遵循以下原则:

八、常见错误与实战练习

常见踩坑记录

❌ 错误 1:YAML 缩进错误
症状:工作流文件无法解析,报错 "unexpected key" 或 "mapping values are not allowed here"
常见原因:YAML 对缩进非常敏感,必须用空格(不能用 Tab),层级要对齐
排查技巧:
  1. 用支持 YAML 的编辑器(VS Code 装 YAML 插件),会实时报错
  2. 同一层级的键必须左对齐
  3. 列表项(- 开头)比父级缩进 2 个空格,列表内容再缩进 2 个
  4. 在线工具 yamllint.com 可以快速验证语法
❌ 错误 2:Secrets 不生效
症状:用了 ${{ secrets.XXX }} 但值是空的,或者报 undefined
常见原因:Secrets 名字写错了大小写,或者配置在了错误的位置
排查步骤:
  1. 确认 Secrets 存在于正确的仓库(不是个人设置里的 Secrets)
  2. Secrets 名字区分大小写,检查拼写
  3. 如果用的是 Environment Secrets,需要在 job 中指定 environment: production
  4. 不要直接 echo Secrets 来调试(会被屏蔽为 ***),可以检查是否为空:test -n "$SECRET" && echo "exists" || echo "missing"
❌ 错误 3:本地能跑 CI 失败
症状:本地 npm test 一切正常,CI 里却报错
常见原因:操作系统不同、Node 版本不同、依赖不一致、缺少环境变量
排查步骤:
  1. 确认 CI 用的 Node 版本和本地一致(用 .nvmrc + setup-node 的 node-version-file)
  2. 用 npm ci 而不是 npm install,确保依赖完全一致
  3. 检查 CI 环境是否有项目需要的环境变量
  4. 注意文件路径的大小写:Linux 区分大小写,macOS/Windows 不区分
  5. 用 act(可搜索 "nektos/act" 了解详情) 工具在本地运行 GitHub Actions 调试

动手练习

🏋️ 练习:为你的项目搭建 CI/CD 流水线
目标:给你之前的项目加一条完整的 CI/CD 流水线

基础要求(必做):
1. 创建 .github/workflows/ci.yml,在 push 和 PR 时触发
2. 包含:安装依赖 → Lint → 类型检查 → 单元测试 → 构建
3. 开启依赖缓存,观察第二次运行是否提速
4. 故意提交一段有语法错误的代码,验证 CI 是否会失败

进阶挑战(选做):
1. 用矩阵构建测试多个 Node 版本
2. 配置部署流水线,推送到自己的服务器
3. 配置 Environment 和人工审批
4. 加入代码覆盖率报告上传

验证方法:打开仓库 Actions 页面,查看工作流运行日志
📝 知识回顾
核心概念
CI 持续集成、CD 持续交付/部署、流水线、工件、Runner
工作流结构
on 触发 → jobs 任务 → steps 步骤 → uses/run 执行
常用 Action
checkout@v4、setup-node@v4、cache@v4、upload-artifact@v4
部署方式
SSH 远程执行、Docker 镜像推送、GitHub Pages 部署
优化手段
依赖缓存、矩阵构建、并行 Job、npm ci 替代 install
安全实践
Secrets 管理、最小权限、PR 安全、Environment 审批
🎯 阶段五 · 扩展与部署 · 完
恭喜你完成了全栈开发学习系列的最后一个阶段!
从桌面应用到容器化部署,从反向代理到自动化流水线
你已经拥有了从开发到部署的完整工程能力

34 篇文章 · 5 个阶段 · 从零基础到全栈工程师
全栈开发学习系列 · 完结撒花 🎉
感谢一路陪伴,我们下个系列见