GitLab CI/CD 教程:从入门到实践 – wiki词典

GitLab CI/CD 教程:从入门到实践

本教程旨在引导您了解 GitLab CI/CD 的基础知识,从理解其核心概念到为 Web 应用程序构建实用的管道。

什么是 CI/CD?

CI/CD 代表持续集成/持续交付(或部署)。它是一种方法论,在整个应用程序开发生命周期中引入自动化和持续监控,从集成和测试阶段到交付和部署。

  • 持续集成 (CI): 开发人员频繁地将他们的代码更改合并到中央存储库中。然后运行自动化构建和测试,以及时快速地发现集成错误。
  • 持续交付 (CD): CI 的延伸,确保所有代码更改都自动构建、测试并准备好发布到生产环境。它确保您可以快速持续地向客户发布新更改。
  • 持续部署 (CD): 将持续交付更进一步,自动部署通过管道所有阶段的每一个更改。无需人工干预。

为什么选择 GitLab CI/CD?

GitLab CI/CD 是 GitLab 中一个功能强大的内置工具,允许您直接在 GitLab 存储库中实现 CI/CD。它使用一个 .gitlab-ci.yml 文件来定义您的管道,该文件位于项目存储库的根目录中。这种紧密集成提供了以下几个优势:

  • 单一应用程序: 从源代码管理到 CI/CD,所有内容都集中在一个地方。
  • 易于设置: 配置通过 YAML 文件完成,使其版本受控且易于管理。
  • 可伸缩性: 可以处理具有许多阶段和作业的复杂管道。
  • 灵活性: 支持各种语言、框架和部署目标。

.gitlab-ci.yml 文件:您的管道定义

.gitlab-ci.yml 文件是您定义 CI/CD 管道的地方。它是一个 YAML 文件,位于项目根目录中。当您将代码推送到 GitLab 存储库时,GitLab Runner(执行您作业的代理)会查找此文件并执行定义的管道。

让我们来看一个针对 Node.js Web 应用程序的综合示例,其中包含详细的注释来解释每个部分。您应该在项目的根目录中创建一个名为 .gitlab-ci.yml 的文件,并将以下内容粘贴到其中:

“`yaml

.gitlab-ci.yml

定义所有作业默认使用的 Docker 镜像,除非另有指定。

此镜像应包含项目所需的工具(例如,Node.js、npm、git)。

image: node:18-alpine

定义管道的阶段。阶段默认并行运行,但阶段内的作业按顺序运行。

这里的顺序定义了阶段的执行顺序。

stages:
– build
– test
– deploy

==================================================================================================

全局缓存配置

==================================================================================================

缓存允许您在作业和管道运行之间重用文件,显著加快执行速度。

这里,我们根据 package-lock.json 文件缓存 Node.js 模块 (node_modules)。

cache:
key:
files:
– package-lock.json # 使用 package-lock.json 生成唯一的缓存键
paths:
– node_modules/ # 要缓存的目录
policy: pull-push # 默认策略:作业前拉取缓存,作业后推送缓存

==================================================================================================

构建阶段作业

==================================================================================================

安装依赖项并构建应用程序的作业。

build_job:
stage: build # 将此作业分配给 ‘build’ 阶段
script:
– echo “Running build job…”
– npm ci # 安装依赖项 (npm ci 在 CI/CD 中优于 npm install)
– npm run build # 执行 package.json 中定义的构建命令
artifacts:
paths:
– build/ # 构建的应用程序文件的路径(例如,React 构建输出)
expire_in: 1 day # 这些工件的保留时间
# 仅在推送到主分支或合并请求时运行此作业
rules:
– if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
– if: $CI_MERGE_REQUEST_IID

==================================================================================================

测试阶段作业

==================================================================================================

运行单元测试的作业。

unit_test_job:
stage: test # 将此作业分配给 ‘test’ 阶段
script:
– echo “Running unit tests…”
– npm ci # 确保安装了依赖项(缓存应该有帮助)
– npm test # 执行 package.json 中定义的测试命令
# 此作业依赖于 ‘build_job’ 成功完成。
# 如果需要,它还将自动从之前的阶段检索工件。
needs: [“build_job”]
rules:
– if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
– if: $CI_MERGE_REQUEST_IID

运行 linting/代码质量检查的作业。

lint_job:
stage: test # 将此作业分配给 ‘test’ 阶段
script:
– echo “Running linting…”
– npm ci # 确保安装了依赖项
– npm run lint # 执行 lint 命令
needs: [“build_job”] # linting 可以与单元测试并行运行,但在构建之后
allow_failure: true # 即使 linting 失败也允许管道继续(可选,取决于策略)
rules:
– if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
– if: $CI_MERGE_REQUEST_IID

==================================================================================================

部署阶段作业

==================================================================================================

部署到预发布环境的作业。

deploy_staging_job:
stage: deploy # 将此作业分配给 ‘deploy’ 阶段
image: alpine/git:latest # 如果需要(例如,带有 git、curl、ssh),为部署使用不同的镜像
script:
– echo “Deploying to staging environment…”
# 在真实场景中,这会涉及以下命令:
# – scp -r build/ [email protected]:/var/www/html
# – ssh [email protected] “sudo systemctl restart webapp”
– echo “Simulating deployment to staging. Artifacts from build_job are available here.”
– ls -la build/ # 验证工件是否存在
environment:
name: staging # 定义环境名称,用于在 GitLab UI 中跟踪部署
url: https://staging.example.com # 可选:部署环境的 URL
needs: [“build_job”, “unit_test_job”] # 确保构建和测试通过后才部署
rules:
– if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # 仅从默认分支部署预发布环境

部署到生产环境的作业(手动触发)。

deploy_production_job:
stage: deploy # 将此作业分配给 ‘deploy’ 阶段
image: alpine/git:latest # 为部署使用不同的镜像
script:
– echo “Deploying to production environment…”
# 在真实场景中,这会涉及更健壮的部署步骤:
# – kubectl apply -f k8s/production-deployment.yaml
# – aws s3 sync build/ s3://production-bucket
– echo “Simulating deployment to production. Artifacts from build_job are available here.”
– ls -la build/
environment:
name: production # 定义环境名称
url: https://www.example.com # 可选:部署环境的 URL
needs: [“build_job”, “unit_test_job”] # 确保构建和测试通过后才部署到生产环境
when: manual # 此作业仅在从 GitLab UI 手动触发时运行
rules:
– if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # 仅允许从默认分支部署生产环境

==================================================================================================

可选:审查应用程序部署(用于合并请求)

==================================================================================================

此作业为每个合并请求创建一个临时“审查应用程序”,

允许审阅者在合并之前实时查看更改。

review_app_job:
stage: deploy
image: alpine/git:latest
script:
– echo “Deploying review app for MR $CI_MERGE_REQUEST_IID…”
# 在真实场景中,这会预配一个临时环境:
# – deploy_script –environment=review-$CI_MERGE_REQUEST_IID –branch=$CI_COMMIT_REF_SLUG
– echo “Review app URL: https://review-$CI_MERGE_REQUEST_IID.example.com”
environment:
name: review/$CI_COMMIT_REF_SLUG # 基于分支的动态环境名称
url: https://review-$CI_MERGE_REQUEST_IID.example.com
on_stop: stop_review_app_job # 定义一个停止此环境的作业
rules:
– if: $CI_MERGE_REQUEST_IID # 仅在合并请求时运行

当合并请求关闭或合并时停止审查应用程序的作业。

stop_review_app_job:
stage: deploy
image: alpine/git:latest
script:
– echo “Stopping review app for MR $CI_MERGE_REQUEST_IID…”
# – undeploy_script –environment=review-$CI_MERGE_REQUEST_IID
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop # 将此作业标记为停止环境
rules:
– if: $CI_MERGE_REQUEST_IID
when: manual # 通常是手动操作,也可以在 MR 关闭/合并时自动触发
“`

核心概念解释

1. image

  • 目的: 指定 GitLab Runner 将用于执行作业的 Docker 镜像。此镜像应包含项目所需的所有工具、语言和依赖项(例如,Node.js、Python、Java、Maven、npm、git)。
  • 示例: image: node:18-alpine 意味着所有作业都将在基于 node:18-alpine 镜像的 Docker 容器中运行,该镜像包含 Node.js 和 npm。
  • 按作业 image 如果特定作业需要不同的环境(例如,部署作业可能需要 alpine/git 用于 sshkubectl),您可以为这些作业覆盖全局 image

2. stages

  • 目的: 定义作业的逻辑顺序和分组。同一阶段内的作业并行运行。阶段本身按顺序运行。
  • 示例: stages: [build, test, deploy] 意味着所有 build 作业将在任何 test 作业开始之前完成,并且所有 test 作业将在任何 deploy 作业开始之前完成。

3. jobs

  • 目的: 管道的基本组成部分。每个作业都是一个独立的工作单元,执行一系列命令。
  • 结构: 每个作业都有一个唯一的名称(例如,build_jobunit_test_job)并且必须属于一个 stage
  • 作业内的关键关键字:
    • script:作业的核心,包含要执行的 shell 命令。
    • stage:将作业分配给已定义的阶段。
    • image:(可选)覆盖此特定作业的全局镜像。
    • before_script:(可选)在作业中的主 script 之前运行的命令。
    • after_script:(可选)在作业中的主 script 之后运行的命令,无论其成功或失败。

4. script

  • 目的: 包含作业将执行的实际 shell 命令。这些命令在指定的 Docker 镜像的上下文中运行。
  • 示例: npm cinpm run buildnpm test

5. cache

  • 目的: 通过在作业和后续管道运行之间重用文件(如已安装的依赖项)来加速管道执行。
  • key 定义如何识别缓存。使用 files:package-lock.json 确保只有当依赖项更改时才使缓存无效并重新构建。
  • paths 指定要缓存的目录或文件(例如,node_modules/)。
  • policy 控制何时拉取 (pull)、推送 (push) 或两者 (pull-push) 缓存。

6. artifacts

  • 目的: 允许您指定应从作业工作区中提取并由 GitLab 保存的文件或目录。然后可以从 GitLab UI 下载这些工件,或将其传递给管道中的后续作业。
  • paths 指定要收集的文件/目录(例如,build/)。
  • expire_in 定义工件应存储多长时间。
  • 用例: 将编译后的代码从 build 作业传递到 deploy 作业。

7. needs

  • 目的: 显式定义作业之间的依赖关系。具有 needs 的作业只有在所有指定的作业都成功完成后才会开始,无论它们所处的阶段如何。这允许不同阶段的作业在满足依赖关系后更早地并行运行。
  • 示例: needs: ["build_job", "unit_test_job"] 意味着当前作业将等待 build_jobunit_test_job 都成功完成才能开始。

8. rules (或 only/except)

  • 目的: 根据各种条件(例如,分支名称、标签、合并请求状态)控制何时将作业包含在管道中。
  • rules(推荐):only/except 更灵活和强大。它允许复杂的条件逻辑。
    • if:指定一个条件(例如,$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH)。
    • when:定义作业何时运行(on_successon_failuremanualalwaysnever)。
  • 示例: if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH 使作业仅在默认分支(例如,main)上运行。if: $CI_MERGE_REQUEST_IID 使其仅在合并请求时运行。

9. environment

  • 目的: 用于部署作业,以定义和跟踪部署环境(例如,stagingproductionreview)。GitLab 提供了一个专门用于环境的 UI。
  • name 环境的名称。
  • url(可选)部署应用程序的 URL,将显示在 GitLab UI 中。
  • on_stop(可选)指定一个应运行以拆除环境的作业(对于动态审查应用程序很有用)。

10. when: manual

  • 目的: 使作业需要从 GitLab UI 手动触发。这通常用于生产等敏感部署,需要人工批准。

11. 预定义 CI/CD 变量

GitLab 提供了许多预定义变量,您可以在 .gitlab-ci.yml 文件中使用。一些常见的变量包括:

  • $CI_COMMIT_BRANCH:管道运行所针对的分支或标签的名称。
  • $CI_DEFAULT_BRANCH:项目的默认分支(通常是 mainmaster)。
  • $CI_MERGE_REQUEST_IID:如果管道用于合并请求,则为合并请求的 IID。
  • $CI_PROJECT_DIR:克隆项目目录的完整路径。
  • $CI_COMMIT_SHORT_SHA:提交 SHA 的前 8 个字符。

入门

  1. 创建 GitLab 项目: 如果您没有 GitLab 项目,请在 GitLab 上创建一个新项目。
  2. 添加您的代码: 将您的应用程序代码推送到存储库。
  3. 创建 .gitlab-ci.yml 将上面提供的示例 .gitlab-ci.yml 内容复制到项目根目录中名为 .gitlab-ci.yml 的文件中。
  4. 提交并推送: 提交 .gitlab-ci.yml 文件并将其推送到您的 GitLab 存储库。
  5. 观察管道: 在您的 GitLab 项目中,转到 CI/CD > Pipelines。您应该会看到您的管道正在运行。
  6. 配置 Runner: 确保您已配置并向项目注册了 GitLab Runner。对于 GitLab.com 上的共享 Runner,这通常会自动处理。对于自托管 GitLab,您需要设置自己的 Runner。

后续步骤

  • 探索更多 rules 深入了解作业的复杂条件逻辑。
  • 变量: 了解自定义 CI/CD 变量(项目、组或实例级别),用于敏感数据(API 密钥、密码)或配置。
  • Include: 在多个项目之间重用 .gitlab-ci.yml 配置。
  • 模板: 利用 GitLab 的内置 CI/CD 模板,适用于常见的语言和框架。
  • 安全扫描: 集成 SAST、DAST、依赖项扫描等安全工具。
  • 审查应用程序: 为每个合并请求设置动态环境。

本教程为使用 GitLab 构建健壮的 CI/CD 管道奠定了坚实的基础。祝您自动化愉快!

滚动至顶部