目录

📚 一、什么是 CI/CD?

简单理解

🏗️ 二、GitHub Actions 架构

核心概念

层级关系

🔄 三、完整构建流程

阶段 1:触发(Trigger)

阶段 2:分配 Runner(运行器)

阶段 3:执行 Job

阶段 4:Step 执行

📦 四、数据传递机制

1. Job 之间传递文件(Artifacts)

2. Step 之间传递数据(Outputs)

3. 缓存机制(Cache)

🔐 五、Secrets 机制

Secrets 是什么?

配置位置

使用方式

安全机制

🌊 六、完整流程图

📝 七、实际案例解析

你的 Workflow 执行过程

🔧 八、常见问题与原理

Q1: 为什么每次都要重新安装依赖?

Q2: 为什么 secrets 不能在日志中显示?

Q3: 为什么 Job 之间不能直接共享文件?

Q4: Runner 的文件系统结构

📊 九、优化建议

1. 合并 Jobs 减少时间

2. 使用缓存

3. 并行执行

🎯 总结


📚 一、什么是 CI/CD?

CI = Continuous Integration(持续集成)
CD = Continuous Delivery/Deployment(持续交付/部署)

简单理解

传统开发流程:
代码 → 手动测试 → 手动打包 → 手动上传服务器 → 手动重启

CI/CD 流程:
代码 → 自动测试 → 自动打包 → 自动部署 → 自动通知
      ↑________________________↓
              全自动!

🏗️ 二、GitHub Actions 架构

核心概念

┌─────────────────────────────────────────────────────────────┐
│                      GitHub Repository                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   .github/workflows/deploy.yml  ← Workflow 配置文件          │
│                                                              │
│   ┌─────────────────────────────────────────────────────┐   │
│   │                    Workflow(工作流)                 │   │
│   │                                                      │   │
│   │   ┌──────────┐   ┌──────────┐   ┌──────────┐       │   │
│   │   │  Job 1   │ → │  Job 2   │ → │  Job 3   │       │   │
│   │   │  测试    │   │  构建    │   │  部署    │       │   │
│   │   └──────────┘   └──────────┘   └──────────┘       │   │
│   │        ↓              ↓              ↓              │   │
│   │   ┌──────────┐   ┌──────────┐   ┌──────────┐       │   │
│   │   │  Step 1  │   │  Step 1  │   │  Step 1  │       │   │
│   │   │  Step 2  │   │  Step 2  │   │  Step 2  │       │   │
│   │   │  Step 3  │   │  Step 3  │   │  Step 3  │       │   │
│   │   └──────────┘   └──────────┘   └──────────┘       │   │
│   │                                                      │   │
│   └─────────────────────────────────────────────────────┘   │
│                                                              │
└─────────────────────────────────────────────────────────────┘

层级关系

Workflow(工作流)
    └── Job(作业)- 可以并行或串行
            └── Step(步骤)- 按顺序执行
                    └── Action(动作)- 具体执行的命令

🔄 三、完整构建流程

阶段 1:触发(Trigger)

on:
  push:           # 代码推送时触发
    branches:
      - main
      - dev
  pull_request:   # PR 时触发
    branches:
      - main
  schedule:       # 定时触发
    - cron: '0 2 * * *'  # 每天凌晨 2 点
  workflow_dispatch:  # 手动触发

触发流程图:

开发者 push 代码
       ↓
GitHub 检测到 push 事件
       ↓
检查 .github/workflows/*.yml
       ↓
匹配触发条件?
   ├── 是 → 启动 Workflow
   └── 否 → 忽略

阶段 2:分配 Runner(运行器)

jobs:
  build:
    runs-on: ubuntu-latest  # 指定运行环境

Runner 是什么?

┌─────────────────────────────────────────────────────────────┐
│                    GitHub 云端服务器                         │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│   │   Runner 1  │  │   Runner 2  │  │   Runner 3  │        │
│   │  ubuntu-22  │  │  windows-22 │  │  macos-14   │        │
│   │             │  │             │  │             │        │
│   │  ┌───────┐  │  │  ┌───────┐  │  │  ┌───────┐  │        │
│   │  │ 你的  │  │  │  │ 其他  │  │  │  │ 其他  │  │        │
│   │  │ Job   │  │  │  │ Job   │  │  │  │ Job   │  │        │
│   │  └───────┘  │  │  └───────┘  │  │  └───────┘  │        │
│   └─────────────┘  └─────────────┘  └─────────────┘        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

可用的 Runner 类型:

Runner 系统 配置
ubuntu-latest Ubuntu 22.04 2核 CPU, 7GB RAM, 14GB SSD
ubuntu-22.04 Ubuntu 22.04 同上
windows-latest Windows Server 2022 2核 CPU, 7GB RAM
macos-latest macOS 14 3核 CPU, 14GB RAM

阶段 3:执行 Job

┌─────────────────────────────────────────────────────────────┐
│                      Job 执行流程                            │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   1. 创建全新的虚拟机                                        │
│      ↓                                                       │
│   2. 克隆代码仓库                                            │
│      ↓                                                       │
│   3. 设置环境(Node.js, pnpm 等)                            │
│      ↓                                                       │
│   4. 安装依赖                                                │
│      ↓                                                       │
│   5. 执行构建命令                                            │
│      ↓                                                       │
│   6. 上传产物 / 部署                                         │
│      ↓                                                       │
│   7. 销毁虚拟机(每次都是全新的!)                          │
│                                                              │
└─────────────────────────────────────────────────────────────┘

重要概念:每个 Job 都在全新的虚拟机中运行!

jobs:
  job1:
    runs-on: ubuntu-latest  # 虚拟机 A
    steps:
      - run: echo "我在虚拟机 A"
      
  job2:
    runs-on: ubuntu-latest  # 虚拟机 B(完全独立!)
    steps:
      - run: echo "我在虚拟机 B,看不到 A 的任何文件"

阶段 4:Step 执行

steps:
  # Step 1: 使用预定义的 Action
  - name: 📥 Checkout code
    uses: actions/checkout@v4  # 从 GitHub Marketplace 获取
    
  # Step 2: 执行 shell 命令
  - name: 📦 Install dependencies
    run: pnpm install
    
  # Step 3: 多行命令
  - name: 🏗️ Build
    run: |
      echo "开始构建..."
      pnpm run build
      echo "构建完成!"

Step 执行原理:

┌─────────────────────────────────────────────────────────────┐
│                      Step 执行                               │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   uses: actions/checkout@v4                                  │
│         ↓                                                    │
│   1. 从 GitHub 下载 actions/checkout 仓库的 v4 版本          │
│   2. 执行该 Action 的 action.yml 定义的逻辑                  │
│   3. 将你的代码克隆到 /home/runner/work/repo/repo           │
│                                                              │
│   run: pnpm install                                          │
│         ↓                                                    │
│   1. 在 bash shell 中执行命令                                │
│   2. 工作目录是 /home/runner/work/repo/repo                 │
│   3. 输出实时显示在 GitHub Actions 日志中                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

📦 四、数据传递机制

1. Job 之间传递文件(Artifacts)

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pnpm install && pnpm build
      
      # 上传构建产物
      - uses: actions/upload-artifact@v4
        with:
          name: dist-files
          path: dist/
          
  deploy:
    needs: build  # 依赖 build job
    runs-on: ubuntu-latest
    steps:
      # 下载构建产物
      - uses: actions/download-artifact@v4
        with:
          name: dist-files
          path: dist/

原理图:

┌─────────────┐                    ┌─────────────┐
│   Build     │                    │   Deploy    │
│   Job       │                    │   Job       │
│             │                    │             │
│  dist/      │   upload-artifact  │             │
│  ├─index.html ──────────────────→│  dist/      │
│  ├─app.js   │   download-artifact│  ├─index.html
│  └─style.css│                    │  ├─app.js   │
│             │                    │  └─style.css│
└─────────────┘                    └─────────────┘
     虚拟机 A        GitHub 存储        虚拟机 B

2. Step 之间传递数据(Outputs)

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.get_version.outputs.version }}
    steps:
      - id: get_version
        run: |
          VERSION=$(node -p "require('./package.json').version")
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          
  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "部署版本: ${{ needs.build.outputs.version }}"

3. 缓存机制(Cache)

- uses: actions/cache@v4
  with:
    path: ~/.pnpm-store
    key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}
    restore-keys: |
      pnpm-

缓存原理:

第一次运行:
┌─────────────────────────────────────────────────────────────┐
│   pnpm install                                               │
│        ↓                                                     │
│   下载所有依赖包(耗时 2 分钟)                              │
│        ↓                                                     │
│   保存到 ~/.pnpm-store                                       │
│        ↓                                                     │
│   上传缓存到 GitHub(key: pnpm-abc123)                      │
└─────────────────────────────────────────────────────────────┘

第二次运行:
┌─────────────────────────────────────────────────────────────┐
│   检查缓存 key: pnpm-abc123                                  │
│        ↓                                                     │
│   找到缓存!下载到 ~/.pnpm-store                             │
│        ↓                                                     │
│   pnpm install(只需 10 秒,因为依赖已存在)                 │
└─────────────────────────────────────────────────────────────┘

🔐 五、Secrets 机制

Secrets 是什么?

Secrets = 加密存储的敏感信息(密码、密钥、Token 等)

配置位置

GitHub 仓库 → Settings → Secrets and variables → Actions

使用方式

steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.API_KEY }}  # 注入为环境变量
    run: |
      echo "API_KEY 已注入,但不会显示在日志中"
      # 日志中会显示 ***

安全机制

┌─────────────────────────────────────────────────────────────┐
│                    Secrets 安全机制                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   1. 加密存储:使用 libsodium sealed box 加密                │
│   2. 运行时解密:只在 Job 运行时解密                         │
│   3. 日志脱敏:自动将 secret 值替换为 ***                    │
│   4. Fork 隔离:Fork 仓库无法访问原仓库的 secrets            │
│   5. 环境隔离:可以设置不同环境的 secrets                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

🌊 六、完整流程图

┌─────────────────────────────────────────────────────────────────────────┐
│                        GitHub Actions 完整流程                           │
└─────────────────────────────────────────────────────────────────────────┘

    开发者                    GitHub                      服务器
      │                         │                           │
      │  1. git push            │                           │
      │ ───────────────────────→│                           │
      │                         │                           │
      │                         │  2. 触发 Workflow         │
      │                         │  ┌─────────────────┐      │
      │                         │  │ 读取 .github/   │      │
      │                         │  │ workflows/*.yml │      │
      │                         │  └─────────────────┘      │
      │                         │                           │
      │                         │  3. 分配 Runner           │
      │                         │  ┌─────────────────┐      │
      │                         │  │ 创建 Ubuntu     │      │
      │                         │  │ 虚拟机          │      │
      │                         │  └─────────────────┘      │
      │                         │                           │
      │                         │  4. 执行 Jobs             │
      │                         │  ┌─────────────────┐      │
      │                         │  │ checkout        │      │
      │                         │  │ setup-node      │      │
      │                         │  │ pnpm install    │      │
      │                         │  │ pnpm build      │      │
      │                         │  └─────────────────┘      │
      │                         │                           │
      │                         │  5. 部署                  │
      │                         │ ─────────────────────────→│
      │                         │        SCP/SSH            │
      │                         │                           │
      │                         │  6. 通知结果              │
      │ ←───────────────────────│                           │
      │   ✅ 部署成功            │                           │
      │                         │                           │

📝 七、实际案例解析

你的 Workflow 执行过程

name: Build and Deploy

on:
  push:
    branches: [dev]

执行时间线:

时间    事件
─────────────────────────────────────────────────────────────
0:00    你执行 git push origin dev
0:01    GitHub 收到 push 事件
0:02    GitHub 检测到 .github/workflows/deploy.yml
0:03    匹配 on.push.branches: [dev] ✓
0:04    创建 Workflow Run #13
0:05    分配 Runner(ubuntu-latest)
        
        ┌─── lint-and-test Job ───┐
0:10    │ 创建虚拟机              │
0:15    │ actions/checkout        │  克隆代码
0:20    │ pnpm/action-setup       │  安装 pnpm
0:25    │ actions/setup-node      │  安装 Node.js
0:30    │ pnpm install            │  安装依赖
0:45    │ pnpm run lint           │  代码检查
1:00    │ pnpm run test           │  运行测试
1:05    │ Job 完成 ✓              │
        └─────────────────────────┘
        
        ┌─── build Job ───────────┐
1:10    │ 创建新虚拟机            │  (全新的!)
1:15    │ actions/checkout        │
1:20    │ pnpm/action-setup       │
1:25    │ actions/setup-node      │
1:30    │ pnpm install            │
2:00    │ pnpm run build          │  构建项目
2:30    │ upload-artifact         │  上传 dist/
2:35    │ Job 完成 ✓              │
        └─────────────────────────┘
        
        ┌─── deploy Job ──────────┐
2:40    │ 创建新虚拟机            │
2:45    │ download-artifact       │  下载 dist/
2:50    │ scp-action              │  上传到服务器
3:00    │ ssh-action              │  重启 Nginx
3:05    │ Job 完成 ✓              │
        └─────────────────────────┘
        
3:10    Workflow 完成 ✅

🔧 八、常见问题与原理

Q1: 为什么每次都要重新安装依赖?

因为每个 Job 都在全新的虚拟机中运行!
上一个 Job 安装的依赖,下一个 Job 看不到。

解决方案:
1. 使用 cache 缓存依赖
2. 使用 artifacts 传递文件
3. 合并 Jobs(减少虚拟机创建)

Q2: 为什么 secrets 不能在日志中显示?

安全机制!GitHub 会自动检测日志中的 secret 值,
并替换为 *** 防止泄露。

Q3: 为什么 Job 之间不能直接共享文件?

因为它们运行在不同的虚拟机上!
必须通过 artifacts 或 cache 传递。

Q4: Runner 的文件系统结构

/home/runner/
├── work/
│   └── your-repo/
│       └── your-repo/     ← 你的代码在这里
│           ├── package.json
│           ├── src/
│           └── dist/      ← 构建产物
├── .npm/                  ← npm 缓存
├── .pnpm-store/           ← pnpm 缓存
└── ...

📊 九、优化建议

1. 合并 Jobs 减少时间

# ❌ 慢:3 个 Job = 3 次虚拟机创建
jobs:
  lint:
    ...
  test:
    needs: lint
    ...
  build:
    needs: test
    ...

# ✅ 快:1 个 Job = 1 次虚拟机创建
jobs:
  build:
    steps:
      - run: pnpm lint
      - run: pnpm test
      - run: pnpm build

2. 使用缓存

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: 'pnpm'  # 自动缓存 pnpm 依赖

3. 并行执行

jobs:
  lint:
    runs-on: ubuntu-latest
    ...
  test:
    runs-on: ubuntu-latest  # 与 lint 并行!
    ...
  build:
    needs: [lint, test]  # 等待两个都完成
    ...

🎯 总结

GitHub Actions = 
    触发器(on)
  + 运行环境(runs-on)
  + 执行步骤(steps)
  + 数据传递(artifacts/cache/outputs)
  + 安全机制(secrets)

核心原理:

  1. 事件驱动:push/PR/定时 触发
  2. 容器隔离:每个 Job 独立虚拟机
  3. 声明式配置:YAML 定义流程
  4. 可组合:Actions 可复用
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐