YAML 在 CI/CD 流水线中怎么用?
YAML 在 CI/CD 流水线中承担的是"流水线即代码"的角色——所有构建步骤、触发条件、环境变量、依赖关系都用 YAML 声明式定义,和代码一起入库版本管理。主流平台各有自己的 YAML 约定:GitHub Actions 用 .github/workflows/*.yml,GitLab CI 用根目录的 .gitlab-ci.yml,CircleCI 用 .circleci/config.yml。虽然语法细节不同,但核心结构都是"触发条件 → 作业定义 → 步骤执行",掌握一个平台后迁移到另一个成本很低。
面试中容易踩的坑:很多人能写出基本流水线,但被问到"怎么控制部署只在 main 分支触发""缓存键怎么设计才能命中""矩阵构建怎么用"就卡壳了。这几个是区分"写过流水线"和"理解流水线"的分水岭。
追问
GitHub Actions 和 GitLab CI 的 YAML 结构有什么区别?
GitHub Actions 以 jobs 为核心,每个 job 下有 steps,step 可以是 run(执行命令)或 uses(引用 Action),job 间通过 needs 声明依赖。GitLab CI 以 stage 为核心,同 stage 的 job 并行,stage 间串行,job 用 script 执行命令。最大的差异是复用机制:GitHub Actions 有可复用工作流(workflow_call)和组合 Action,GitLab CI 用 include 拆分模板和 extends 继承配置。
条件执行有哪些常见写法?
GitHub Actions 用 if 表达式,支持 github.ref、github.event_name 等上下文变量,也支持 always()、failure() 等状态函数。GitLab CI 用 rules 和 only/except,rules 优先级更高且支持 when + if 组合。实际项目中最常见的场景是:main 分支自动部署生产、develop 分支部署 staging、其他分支只跑测试。
缓存配置怎么写才能实际命中?
关键在缓存键的设计。很多人直接用 key: npm-cache,结果永远命中旧缓存。正确做法是用文件哈希作为键的一部分:${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }},这样依赖变化时缓存自动失效。GitLab CI 的 cache:key 同理,用 $CI_COMMIT_REF_SLUG 配合 files 关键字。还要注意缓存路径要对——npm 缓存 ~/.npm 而不是 node_modules,后者用 artifacts 传递更可靠。
矩阵构建怎么用?有什么坑?
矩阵构建用来同时在多个环境组合下测试,比如不同 Node 版本和操作系统:
yamlstrategy: matrix: node-version: [16, 18, 20] os: [ubuntu-latest, macos-latest]
坑主要两个:一是矩阵爆炸,3 个版本 × 3 个系统 = 9 个 job,GitHub 免费额度很快用完,建议用 fail-fast: true 加 max-parallel 控制;二是某些组合天然跑不了(比如 macOS 上没有 Docker),要用 exclude 排除。
YAML 锚点和别名在 CI/CD 里能用吗?
语法上 YAML 的 & 锚点和 * 别名是标准特性,GitLab CI 支持得很好,可以复用默认配置减少重复。但 GitHub Actions 不支持锚点和别名——它的 YAML 解析器会报错。所以在 GitHub Actions 里要复用配置,只能用可复用工作流或组合 Action,别想走锚点捷径。
写段代码
一个实用的 GitHub Actions 缓存 + 条件部署精简模板:
yamljobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} - run: npm ci && npm test deploy: needs: test if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - run: echo "deploy to production"