Microsoft AZ-400: 使用 Azure Pipelines 的 CI/CD 管道 — 学习指南
属于 Microsoft DevOps Engineer Expert AZ-400 — 学习指南. 使用经过验证的答案练习: Microsoft 考试中心, 或参加限时模拟考试: ExamRoll.io.
概述
Azure Pipelines 以代码形式提供端到端的 CI/CD,通过多阶段 YAML 流水线统一构建、测试和发布,同时保留企业级控制。要构建可扩展、安全且可重复的交付系统,精通 YAML 编写、触发器、代理、变量、模板、部署作业、工件、缓存和服务连接至关重要。
使用 YAML 和模板进行编写
一个 YAML 流水线由阶段 (stage)、作业 (job) 和步骤 (step) 组成。阶段模拟了生命周期的边界,如构建、测试、发布;作业在代理上执行,可以并行运行;步骤是在作业中执行的任务或脚本。依赖关系通过 dependsOn 显式声明,从而实现细粒度的编排和条件执行。多阶段 YAML 整合了 CI 和 CD,支持扇入/扇出模式,并将审批与环境绑定,而不是与独立的发布构造绑定。
模板支持在不同粒度上进行组合和重用:
- 步骤模板 (Step templates):封装一系列任务(例如,工具设置、还原、构建、测试),以便在存储库之间重用。
- 作业模板 (Job templates):将步骤与特定的代理规范和策略(例如,测试矩阵作业)捆绑在一起。
- 阶段模板 (Stage templates):打包整个阶段,包括审批、条件和环境目标,以实现一致的晋升流程。
- 扩展模板 (Extends templates):强制实施流水线继承。顶层的
extends引用一个中央模板,该模板规定了必需的阶段/作业/步骤和治理策略。这对于组织范围的策略非常强大,可以确保每个团队都继承安全扫描、合规性检查和命名约定。
模板在运行时执行之前于编译时进行评估。使用 ${{ }} 作为模板表达式,在编译时对流水线结构进行分支(例如,仅为主分支 main 包含某些作业)。宏语法 $(var) 和运行时表达式 $[ ] 在运行时解析,这会影响机密和变量组的可用时机。将共享模板存储在中央存储库中,并通过 resources repositories 导入;将其固定到特定分支或标签上,以实现确定性构建。
触发器、代理、变量和表达式
触发器管理自动化入口点:
- CI 触发器 (CI triggers):在代码被推送到受跟踪的分支时启动流水线运行。包含和排除路径筛选器可以减少不必要的运行。批处理 (Batch) 允许合并多个推送。
- PR 触发器 (PR triggers):验证拉取请求。配置目标分支和路径筛选器,并启用自动取消被取代的运行。
- 计划触发器 (Scheduled triggers):根据 cron 表达式运行,以支持夜间构建或带有区域控制的定期验证。
- 流水线触发器 (Pipeline triggers):在上游流水线发布新的运行或工件时触发。声明流水线资源并附加
trigger: true及分支筛选器,以跨存储库或项目链接流水线。
代理和代理池决定作业的运行位置:
- Microsoft 托管代理 (Microsoft-hosted agents):在
ubuntu-latest、windows-latest或macOS镜像上提供预装了工具集的临时虚拟机。它们是实现弹性和最小化维护的理想选择。通过购买并行作业来规划并发性,并考虑缓存预热的限制。 - 自托管代理 (Self-hosted agents):在您自己的基础设施上运行,以支持自定义工具链、私有网络访问和可预测的性能。加固主机,根据需要限制出口流量,并轮换用于注册代理的 PAT。使用规模集或容器化代理以实现弹性。
- 代理池 (Agent pools):对代理进行逻辑分组,并用于委派权限。向代理池授予项目级别的“使用”权限,并通过专用池隔离敏感工作负载。作业指定
pool,并可选地通过demands来选择具有所需能力的代理。
变量和参数驱动可配置性:
- 流水线变量 (Pipeline variables):是键值对,可作为环境变量并通过
$(name)宏供任务使用。机密变量在日志中被屏蔽,并且绝不会在编译时模板表达式中暴露。在库 (Library) 或流水线中将其标记为机密。 - 变量组 (Variable groups):在库 (Library) 中集中管理共享值和机密。链接到 Azure Key Vault 以在运行时获取机密,确保这些值不存储在流水线中。控制流水线权限,以限制哪些流水线可以使用某个变量组。
- 运行时参数 (Runtime parameters):在排队时定义强类型输入(字符串、数字、布尔、对象),并通过
${{ parameters.* }}在编译时进行评估,以塑造流水线结构(例如,启用/禁用阶段)。当需要更改流水线结构时,首选参数;当需要在步骤中使用运行时值时,首选变量。 - 表达式 (Expressions):使用
${{ }}进行编译时模板逻辑处理,使用$(var)进行宏替换,使用$[condition()]在属性中进行运行时条件判断。通过日志记录命令从任务中设置变量,并使用isOutput变量在作业之间传播输出。
部署、环境、策略和门禁
部署作业 (Deployment job) 提供了一流的 CD 语义。部署作业以一个环境为目标,并根据控制发布和生命周期挂钩 (lifecycle hooks) 的策略来运行:
- 环境 (Environments) 代表部署目标(例如,dev、test、prod),可以包含 Kubernetes 集群、虚拟机等资源,或用于平台无关部署的通用“none”资源。环境统一了遥测、审批和检查。
- 审批 (Approvals) 和检查 (checks) 附加到环境和服务连接上。审批要求指定的审批人在部署继续前进行批准。检查充当门禁 (gates),评估诸如工作时间、必需的工作项、Azure Monitor 信号、调用 REST API 或 Azure Functions 以及分支保护等条件。如果性能基线或合规性条件未得到满足,这些门禁会阻止晋级。
- 策略 (Strategies) 决定了更新的发布方式:
- runOnce 以单波次方式应用变更,带有 preDeploy 和 postDeploy 挂钩。
- rolling 在实例间分批部署,通过 maxParallel 和故障阈值确保安全推进。
- canary 通过增量方式逐步转移流量,在完全发布前通过 routeTraffic 和 postRouteTraffic 阶段进行验证。
- blue-green(也称为 red/black)通过部署到并行环境或槽位,并在负载均衡器或 App Service 槽位交换 (slot swap) 处切换流量来实现。尽管 blue-green 不是一个具名的 YAML 策略,但它是通过环境、路由和交换任务实现的,并通过恢复流量来提供快速回滚。
将部署逻辑编码为每个环境阶段 (stage) 的部署作业。利用环境检查来建立稳健的门禁,而不是使用临时的脚本轮询。当需要密钥时,应通过服务连接从 Azure Key Vault 中检索,而不是将它们嵌入到变量中。
工件、缓存和服务连接
工件 (Artifacts) 和缓存可以提高重用率和性能:
- 管道工件 (Pipeline artifacts) 是发布和使用构建输出的原生方式。使用 PublishPipelineArtifact 发布具名工件,使用 DownloadPipelineArtifact 从当前或特定的运行中获取。它们经过优化,在 YAML 中具有高可靠性并支持跨阶段共享。当从另一个管道使用工件时,应声明一个管道资源 (pipeline resource),并使用其工件资源名称进行精确检索。
- 通用包 (Universal packages) 通过 Azure Artifacts 为非特定语言的资产(例如,CLI 工具、数据文件)提供版本化、不可变的二进制分发。使用 Universal Packages 任务进行发布和下载,通过源视图 (feed views)(例如,prerelease vs release)进行组织,并在源 (feeds) 中管理保留策略。
- 管道缓存 (Pipeline caching) 可加速依赖项的还原。Cache 任务使用一个键 (key) 和路径 (path)。键应包含锁文件(package-lock.json、Pipfile.lock、packages.lock.json、go.sum)的哈希值,以及操作系统和工具版本,以实现精确的缓存失效。还原键 (Restore keys) 为部分缓存命中提供后备匹配。避免在缓存路径中嵌入密钥,遵守缓存大小限制,并在锁文件不稳定时为临时工具禁用缓存。观察 cacheHitVar 以便对任务行为进行分支处理。
服务连接 (Service connections) 定义了 Azure Pipelines 用于访问外部系统的身份:
- 类型包括 Azure Resource Manager(用于 Azure 订阅和资源组)、GitHub(用于仓库读/写、状态报告)和 Docker/Container Registry(用于 Docker Hub、ACR)。其他类型还包括用于 AWS、GCP、通用服务端点和包注册表的服务连接。
- OIDC 联合(工作负载身份联合)通过在 Azure DevOps 和云身份提供商之间建立信任关系,消除了长期存在的密钥。对于 ARM,需要配置一个 Entra ID 应用程序,并为其设置一个联合凭据,该凭据绑定到 Azure DevOps 的颁发者 (issuer) 以及仓库/管道的声明 (claims)。在运行时,Azure DevOps 用一个短期令牌换取云访问令牌,从而消除了服务主体密钥,并降低了凭据泄漏的风险。
- 范围界定和治理至关重要。将 ARM 连接的范围限定在最小权限(理想情况下是具有自定义 RBAC 的资源组级别)。禁用“向所有管道授予访问权限”选项,改为显式授权特定的管道。将审批和检查附加到服务连接上,以在使用前要求人工审查或策略验证。
经典管道与 YAML 管道的对比及迁移
经典管道使用可视化设计器,将“生成 (Build)”和“发布 (Release)”作为独立概念。它们提供基于任务的创作、变量管理、发布环境和门禁 (gate)。YAML 管道则提供管道即代码 (pipeline-as-code)、多阶段统一、模板以及与存储库集成的强大版本控制。功能对等性已基本实现:环境审批和检查取代了发布门禁;部署作业 (deployment job) 用于对环境建模;管道工件 (pipeline artifact) 取代了生成工件 (build artifact);模板和 extends 则实现了大规模的集中治理。剩下的差异通常在于基于 UI 的手动干预和一些小众的发布设计器功能,这些在 YAML 中通过手动验证 (Manual Validation) 任务和环境检查来弥补。
一个务实的迁移路径如下:
- 盘点经典的生成和发布定义、任务、变量、环境、审批和门禁。
- 使用“导出为 YAML”助手将生成管道转换为 YAML,然后将其重构为模板以提高可重用性和可维护性。
- 将每个发布环境建模为一个 YAML 阶段,其中包含一个以环境为目标的部署作业。将发布门禁转换为环境审批和检查(例如,Azure Monitor 查询检查、工作项查询检查)。
- 将共享变量外部化到变量组中,并链接 Key Vault 以管理密钥。使用基于 OIDC 的服务连接替换服务主体的密钥。
- 将发布工件触发器替换为管道资源触发器。在 CI 阶段发布管道工件,并在 CD 阶段使用它们。
- 通过临时并行运行两种管道来验证功能对等性,然后进行切换,并根据适当的回滚计划停用经典定义。
实际问题场景
星巴克正在为其微服务平台标准化交付流程,并且必须从经典发布迁移到 YAML,同时强制执行性能门禁、降低凭据风险并加快构建速度。
- 使用 extends 模板编写多阶段 YAML
- 方法:创建一个组织级别的中央 extends 模板,该模板注入用于静态分析、SCA 和安全检查的通用阶段,以及标准的通知。每个服务管道都继承此模板,并定义特定于服务的构建和部署阶段。
- 理由:Extends 统一强制执行治理,并保持服务管道的精简,同时保证满足必要的合规性步骤。
- 实现 CI、PR、计划和管道触发器
- 方法:为每个服务配置带有路径筛选器的 CI 和 PR 触发器;添加一个夜间计划以运行耗时较长的集成测试;通过管道资源将一个打包管道链接起来,以触发一个部署管道。
- 理由:确保对代码变更的快速反馈、定期的健康检查以及对已知工件的确定性提升。
- 使用混合代理策略和代理池
- 方法:构建作业在 Microsoft 托管的 ubuntu-latest 代理上运行以获得弹性;部署作业在星巴克 VNet 内部的自托管代理上运行,以便访问内部集群。按环境将代理隔离到不同的池中,并限制池的使用。
- 理由:托管代理最大限度地减少了 CI 的维护工作;自托管代理为 CD 提供了安全的网络访问。池范围划分强制执行最小权限原则。
- 使用变量组和运行时参数管理变量
- 方法:将共享的非机密值放入变量组,通过链接的变量组从 Azure Key Vault 检索机密,并公开一个布尔参数 enablePerfGate 以在非生产分支中切换性能门禁的开关。
- 理由:集中配置避免了重复;Key Vault 保护了机密;参数驱动了编译时的结构选择。
- 使用环境、审批和检查来定义部署作业
- 方法:将开发 (dev)、预演 (staging) 和生产 (prod) 建模为环境。为预演和生产环境添加审批。添加检查:为生产环境设置办公时间检查,并添加一个 Azure Monitor 查询检查,如果预演环境的延迟超过基线,则阻止提升。
- 理由:环境级别的审批和检查实现了受控的提升,并在生产部署前强制执行 SLO。
- 应用金丝雀部署,然后是蓝绿部署策略
- 方法:在预演环境中使用金丝雀策略来验证增量变更。在生产环境中,部署到并行的槽位/环境,然后切换流量(蓝绿/红黑部署),以实现即时回滚能力。
- 理由:金丝雀部署降低了验证过程中的风险;蓝绿部署最大限度地减少了部署时间并提供了最快的回滚。
- 使用管道工件和缓存进行优化
- 方法:将构建输出作为管道工件发布;在部署阶段使用它们。使用基于锁文件哈希的键来缓存依赖项恢复,并使用 restoreKeys 作为后备。
- 理由:工件确保了不可变的、可追溯的提升;缓存在不牺牲正确性的前提下显著缩短了构建时间。
- 使用 OIDC 和范围权限保护服务连接
- 方法:使用工作负载身份联合创建范围限定于资源组的 ARM 服务连接。要求对服务连接进行审批和检查,并禁用“授予所有管道访问权限”选项。
- 理由:消除了长期存在的密钥,并通过可审计的审批强制执行最小权限原则。
这种端到端的设计将 YAML 即代码的治理与企业级的审批和检查相结合,通过缓存和工件加速交付,并通过 OIDC 和范围受限的服务连接加强安全性。
← 源码控制与仓库管理 · 所有领域 · 基础架构即代码与配置管理 →
练习这些题目 → · 在 ExamRoll.io 上限时练习 →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
通过考试 →