Azure Pipelines入门:从CI/CD到YAML管道实战指南
简介:这是一份 Azure DevOps Pipelines 官方文档整理而成的操作手册,面向需要搭建持续集成与持续交付体系的开发、运维及 DevOps 工程师,适合从入门到进阶查阅。手册系统覆盖 Azure Pipelines 核心概念,包括代理、条件、表达式、环境、作业、运行时参数、阶段、任务、模板与触发器,并完整讲解经典发布管道、快速入门、自定义管道、YAML 架构及预定义变量等关键内容。资源共 1 个 PDF 文件,整体大小 106.6MB,便于离线检索与按章节学习。已有 412 人浏览学习,内容版块清晰,既包含在 Windows、Linux、macOS 上生成多语言应用的操作指南,也涵盖部署到 Azure SQL、AKS、Azure Key Vault 等服务的教程,以及持续测试、资源管理、常见故障排查和发布包等实践章节,可帮助读者从零搭建管道并解决实际发布中的问题。
1. Azure Pipelines到底是什么:一个帮你自动"搬砖"的助手
刚接触代码发布的人可能都有过这种体验:每次改完功能,都要手动登录服务器、上传代码、跑一遍测试、再重启服务。改一行,半小时没了;改十行,一下午就没了。Azure Pipelines 就是来帮你解决这个问题的——它是 Azure DevOps 平台的自动化服务,核心能力是持续集成与持续交付(CI/CD)。你只要把代码推到仓库,它会自动完成构建、测试甚至部署,再把结果反馈给你。它适合任何写代码的人,不管你是刚入门的新手,还是在团队负责发版的老手,都能把重复的手工操作交给它。这篇指南不聊复杂原理,只带你先搞懂它是什么,再亲手跑通第一个管道。
2. 先弄懂两个核心概念:持续集成和持续交付的区别
Azure Pipelines 身上贴着两个最常见的标签:CI 和 CD。很多新手第一次打开官方文档,看到这两个缩写直接懵了。别慌,这俩概念一点都不玄学,也不难理解。我尽量用大白话把它讲清楚,你带着这两个印象再去看文档,会觉得顺眼很多。
2.1 持续集成(CI):每次提交代码都自动"体检"
持续集成,英文叫 Continuous Integration,缩写 CI。它的核心动作只有一个:每当你的代码发生变动——比如有人往仓库里推送了一次新的提交——系统就自动把最新的代码拉下来,做一次完整的"体检"。
这个体检包含什么呢?至少包含两件事:一是构建(Build),把源代码变成可以运行的产物,比如把 Java 代码编译成 jar 包,把前端代码打包成静态文件;二是测试(Test),跑你写好的一堆自动化测试用例,确认这次改动没有把原来的功能弄坏。如果构建失败,或者测试没通过,你就需要赶紧回去看这次提交的代码。
为什么要这样做?因为问题发现得越早,修起来越便宜。如果你把两个星期的代码攒在一起合并后再统一测试,一旦出错,很难定位到底是哪一次改动引入的。但如果是每次提交都自动跑一遍测试,某一次红了,你立刻就知道是哪里出了问题。用官方文档的说法,这叫"在开发周期的早期捕获 bug,从而降低修复成本"。
所以 CI 解决的核心问题就是这个:让代码仓库保持一个"基本健康"的状态,避免出现"本地跑得好好的,一合并就炸了"的尴尬局面。它不负责部署,只负责保证你的代码在被合并进主干之前,是经得起验证的。
2.2 持续交付(CD):把成品自动送到每个环境
持续交付,Continuous Delivery,缩写 CD。如果说 CI 的目标是"把代码变成可运行的产物",那 CD 的目标就是"把这个产物安全地送到各个运行环境里去"。
运行环境大家应该不陌生:本地开发是一个环境,公司有一台测试服务器,线上有一台生产服务器,可能还有给客户演示用的预发布环境。每次发版,你得把这些环境挨个部署一遍:传文件、改配置、重启服务。CD 要解决的就是把这个过程自动化——你用 CI 生成的构建产物,通过管道自动传递到测试环境、预发布环境,最后再部署到生产环境。
你可能听说过"多环境部署提升质量"这句话,意思是代码不是直接上生产的,而是先在测试环境跑一遍验证,验证通过再往下一个环境推。这就像发货之前先经过质检,质检合格了才装箱。Azure Pipelines 支持你把整个流程定义成多个阶段,每个阶段对应一个环境,阶段之间还可以加审批——没有人确认,管道不会继续往下走。
2.3 为什么非得自动化:一次手动发布翻车之后
光讲概念可能感受不深,我讲一个某团队的亲身经历。这个团队当时发布全靠手工:A 同学负责打包,把代码上传到一台跳板机,再手动执行脚本部署到服务器。最开始人少,一周发一次版,勉强能撑住。后来项目需求增多,变成一天发好几次,问题就开始爆发了——打包出来的版本偶尔不一致,测试环境验证过的东西一到生产就行为奇怪,偶尔还会出现两个人同时部署"撞车"的情况。
后来他们引入了 CI/CD,把打包、跑测试、部署测试环境、部署生产环境全部写进管道里。从那以后,发版变成一件很"无聊"的事:推一次代码,等几分钟,看管道跑完,完事。就算出错,管道也会明确指出是哪一步挂的,日志都给你整理好,不用再靠猜。手动流程最要命的不是慢,而是不可复现——你永远没法保证每次手点的按钮、每个手敲的命令都完全一致。而管道里的每一步都是写死的脚本和参数,跑一千次结果都一样。
2.4 它到底能跑什么:语言、平台和部署目标
Azure Pipelines 一个很受欢迎的特点是"什么都不挑"。官方文档里列出的支持范围非常大:构建和测试的编程语言包括 Node.js、Python、Java、PHP、Ruby、C#、C++、Go、.NET、Android,还有 iOS 和 Xcode 项目,几乎覆盖了主流技术栈。
部署目标同样广泛:虚拟机、容器、Azure Kubernetes 服务、云平台服务、本地服务器都可以作为部署终点,甚至还能把你的移动应用发布到应用商店。它还内置了针对 .NET、Java、Node.js、Android 等常用项目的现成任务,省去你到处找插件的功夫。这意味着你只要学会一次,以后换语言、换部署平台,这套思路都能复用,不用担心白学。
3. 亲自上手:免费注册并创建第一个管道
概念讲得再多,不如自己亲手跑通一次。这一章我们只做一件事:把一个简单的项目通过 Azure Pipelines 自动构建一次。你全程跟着做,大约十五分钟就可以看到第一个结果。第一次跑通之后,你心里就有底了,后面再怎么折腾都不怕。
3.1 第一步:准备一个代码仓库
Azure Pipelines 有一个硬性前提:你的源代码必须放在版本控制系统里。它支持很多种仓库,例如 GitHub、Azure Repos Git 等。如果你手头还没有项目,最简单的做法是在 GitHub 上建一个空仓库,往里面放一个最简单的项目文件。不用多复杂,一个单文件的 Python 脚本,或者一个 HTML 页面都可以——先别追求项目本身的复杂度,我们的目标是让管道"有东西可跑"。
如果你用的是 GitHub 仓库,直接把代码推上去就行。仓库是公开还是私有都可以,两者在使用上有一些区别:公开项目使用管道是免费的,私有项目每个月有固定的免费分钟数,这个我们在第 5 章会详细讲。
3.2 第二步:注册 Azure DevOps 并创建组织
打开浏览器,进入 Azure DevOps 的注册页面,选择"免费开始"。你可以用已有的 GitHub 账号登录,也可以用 Microsoft 账号登录。第一次进来,系统会引导你创建一个组织(Organization)。
组织怎么理解?你把它当成一个团队工作区就行,所有项目、管道、构建记录都放在这个工作区里。创建的时候需要做两件事:给组织起个名字,然后选择数据中心的位置。完成后你会得到一个访问地址,格式是 https://dev.azure.com/你的组织名。以后所有项目都从这个地址进入。
这里给你一个小建议:组织名字最好用英文或拼音。因为后面生成的各类链接都会带上组织名,纯英文最不容易在复制粘贴的时候出问题。
3.3 第三步:创建项目并找到 Pipelines 入口
登录进组织之后,页面会引导你创建一个项目(Project)。项目名可以随意,比如就叫 my-first-pipeline。可见级别暂时选"私有"就行,以后想改成公开随时可以调整。
项目创建完成,左侧导航栏里会有一个写着 Pipelines(管道)的菜单,点进去就是管道管理页面。页面上会有一个明显的按钮叫"创建管道"或"Create Pipeline",我们点击它,开始创建第一个管道。
3.4 第四步:选择代码源并让系统识别你的仓库
创建管道的第一步是选择代码放在哪里。前面我们用 GitHub 的话,这里就选 GitHub 选项;系统接下来会要求你授权,让你选择刚才那个仓库。
选好仓库之后,Azure Pipelines 会主动做一件事:扫描你的仓库内容,然后根据项目类型推荐一个管道模板。比如仓库里有一个 Python 文件,它会推荐 Python 包构建模板;如果检测到 package.json,会推荐 Node.js 模板。这一步对新手特别友好,你直接选它推荐的第一个模板即可。
3.5 第五步:看一眼生成的 YAML,然后点运行
选择完模板,系统会打开一个编辑器,里面已经生成好了一个名为 azure-pipelines.yml 的文件。下面是一个 Python 项目可能生成的示例:
trigger: - main # 推送到main分支时自动触发运行 pool: vmImage: 'ubuntu-latest' # 使用微软托管的Ubuntu环境来执行任务 steps: - task: UsePythonVersion@0 # 官方任务:指定Python版本 inputs: versionSpec: '3.11' addToPath: true - script: | # 运行脚本:升级包管理工具并安装依赖 python -m pip install --upgrade pip pip install -r requirements.txt displayName: '安装依赖' - script: | # 运行脚本:执行pytest测试 python -m pytest displayName: '运行测试'先别急着理解每一行的含义,这一章的最终目标只是让它跑起来,文件里该有的内容系统已经帮你填好了。直接点击"保存并运行",系统会把这份 YAML 文件提交到你的仓库里,然后立刻开始第一次构建。
等待一两分钟,页面会跳转到构建运行的详情页。你会看到几个步骤依次执行:安装依赖、运行测试、最后完成构建。每一步前面都有一个绿色的对勾,表示这一步通过了。到这里,你的第一个管道就正式建成了,是不是没有想象中那么复杂?
提示:第一次运行如果系统提示需要授权或创建服务连接,按页面提示点一下"许可"或"批准"即可。这是为了让管道能访问你的仓库,属于正常的安全流程。
第一次跑通之后,你可能会开始好奇:那个 YAML 文件里到底写了什么?为什么它能指挥管道干活?带着这个疑问,我们进入第 4 章。
4. 读懂YAML管道:一份配置文件如何驱动整个流程
跑通第一个管道之后,你会产生一个新的困惑:那个 YAML 文件里面到底写了什么?为什么它能指挥管道一步一步干活?这一章我们就把它拆开来看。你不需要背语法,只需要理解它的组织逻辑——下次再拿到别人的管道文件,你能大概看出它的执行顺序和关键参数,那就算达标了。
4.1 从一份最简单的 YAML 开始拆解
我们先用一份最简单的 YAML 来举例:
trigger: - main # main分支收到推送时自动运行 pool: vmImage: 'ubuntu-latest' # 运行环境:Ubuntu最新版虚拟机 steps: - script: echo "Hello, Azure Pipelines!" displayName: '打个招呼' # 这一步在控制台打印一行问候这份配置的每一块都有明确的意义。trigger:表示触发条件,意思是:当这个仓库的 main 分支收到新的代码推送时,管道就自动启动。如果你以后想改成别的分支,把 main 换成对应分支名即可。
pool:定义管道在哪种运行环境里执行。ubuntu-latest是"微软托管虚拟机"的一个镜像代号,代表最新版 Ubuntu 系统。你可以把它换成windows-latest或macos-latest,管道就会跑到对应系统的虚拟机上——跨平台构建大致就是这么实现的。
steps:是步骤列表,每一步就是一个任务。这里只有一个任务,执行一条脚本命令echo,作用是打印一行字。displayName是给这一步起的可读名字,方便你在运行记录里一眼看出这一步在做什么。
这里要特别提醒你注意:YAML 对缩进极度敏感。steps:下面的每一项,前面必须有相同的缩进层级,通常统一用两个空格。如果你复制别人的配置时缩进乱了,管道会直接解析失败,这也是新手最常踩的坑,第 5 章会展开讲。
4.2 认识任务、作业和阶段三个层级
在管道文件里,你会反复看到三个概念:任务、作业、阶段。它们的关系是从小到大、层层包含的,可以对照下面这张表来理解:
| 层级 | 作用 | 类比 |
|---|---|---|
| 任务(Task) | 一个具体操作,如运行脚本、安装依赖、发布产物 | 一次具体动作 |
| 作业(Job) | 一组任务的集合,在指定的运行环境上按顺序执行 | 一个工作台 |
| 阶段(Stage) | 一组作业的逻辑分组,常对应不同部署环境 | 流水线上的工位 |
任务(Task)是最小的执行单元,代表"做一件具体的事"。前面例子里的script就是一个任务。Azure Pipelines 内置了大量任务,比如指定 Python 版本、运行测试、发布构建产物等。你可以在官方任务索引里查到所有可用的任务,基本覆盖了常见开发需求。
作业(Job)是一组任务的集合。默认情况下,一个 YAML 文件里的所有任务都在同一个作业里按顺序执行。但如果你希望并行跑多个环境的构建,可以把它们拆成多个作业,每个作业有自己独立的运行环境和任务列表。
阶段(Stage)是更大的一层,用于组织作业。通常一个阶段对应一个环境:构建是一个阶段,部署到测试环境是下一个阶段,部署到生产环境又是更下一个阶段。阶段可以串行执行,也可以设置条件,比如"前一个阶段成功后,才继续执行下一个阶段"。
你不需要现在就掌握全部细节,只要知道执行顺序大致是任务在作业里跑、作业在阶段里跑,就够了。后面你真正配置多环境部署时,这些概念自然会被串起来。
4.3 触发器:管道什么时候自动运行
管道不会平白无故跑起来,它需要一个"起跑信号",这个信号就叫触发器。最常用的就是前面看到的那段:
trigger: - main它的意思是:只要 main 分支有新的代码推送,就自动触发管道运行。如果你希望任意分支都触发,可以写成:
trigger: - '*'除了代码推送之外,触发器也可以是定时运行。比如你想每天晚上自动跑一遍全量测试,可以用schedules来配置计划任务。当然,最原始的触发方式还是手动运行:在管道详情页直接点击"运行管道",随时可以手动执行一次。
这里补充一个容易忽略的知识点:一个仓库里可以同时存在多套管道,每套对应一个 YAML 文件。你可以让不同的管道各司其职,一个负责日常构建,一个负责发布部署,互不干扰。
4.4 执行环境的真相:什么是 Agent
你可能会好奇,管道真正运行的时候,代码到底是在哪台机器上执行的呢?答案是 Agent,它也常被翻译成"构建代理"。它是实际执行任务的运行环境,你可以把它理解成一台"管道专用电脑"。
Azure Pipelines 提供两类 Agent。第一类是微软托管的 Agent:你在pool里写一个vmImage,微软就临时从云端分配一台全新的虚拟机给你跑管道,跑完自动销毁。它的优点是完全不用自己维护系统,开箱即用;缺点是每次都是新机器,安装依赖会花一些时间。
第二类是自托管 Agent:你准备一台自己的机器,安装 Agent 程序并注册到 Azure DevOps,之后管道就可以指定使用这台机器。它适合什么场景呢?比如构建过程需要访问内网资源、需要特殊的硬件环境,或者你觉得托管机器的免费额度不够用。不过入门阶段,直接用微软托管的最省事,不要急着折腾自建环境。
4.5 变量和变量组:让配置不再写死
管道里如果全是写死的值,时间久了你会觉得很难受。比如现在把 Python 版本写死成 3.11,过几个月想升级到 3.12,就得打开文件改一遍。更灵活的做法是使用变量。
YAML 里定义变量的方式是这样:
variables: pythonVersion: '3.11' # 定义一个变量,后面用$(pythonVersion)引用 buildConfiguration: 'Release' steps: - task: UsePythonVersion@0 inputs: versionSpec: $(pythonVersion) # 引用变量,而不是写死具体版本这段配置先定义了两个变量pythonVersion和buildConfiguration,后面用$(变量名)的语法来引用。以后要改版本,只需要动 variables 下面的一行,不需要满文件找需要改动的位置。
如果多个管道都想用同一批变量,比如服务器地址、账号名称,可以创建"变量组"(Variable Group)来统一维护。至于密码、密钥这类敏感信息,千万不要直接写进 YAML 文件,正确做法是放进变量组并标记为"机密",或者存进 Azure Key Vault,管道运行时再引用。具体原因和后果,第 5 章的坑五会详细说。
5. 避坑指南:新手最常见的5个翻车时刻
跑管道这件事,十个新手有九个会在前几次运行里遇到各种各样的报错。这一章我把最常见的几个坑拿出来逐个拆开,每条都按"现象、原因、解决"的顺序讲。以后你遇到类似问题,直接对照这里排查,能省下不少摸索时间。
5.1 坑一:YAML缩进对不齐,管道直接罢工
现象:管道连跑都没跑起来,运行记录里直接显示解析失败,错误提示类似 "Failed to parse the YAML file",有时候还配着一个让人摸不着头脑的行号。
原因:YAML 是一种对缩进极其敏感的文件格式。steps:下面每个任务必须处于相同的缩进层级,多一个空格或少一个空格,解析器都会认为它不是同一个列表里的元素。另一个常见情况是 Tab 键和空格混用,也会引发同样的解析问题。
解决:尽量用代码编辑器来编辑 YAML 文件,并装上相应的语法扩展,它能实时标出缩进异常的位置。如果已经报错,就展开错误提示中提到的行号附近,检查每一行的缩进是否一致。我常用的做法是统一用两个空格做缩进,全程不用 Tab,这个习惯帮我避免了很多次解析错误。
5.2 坑二:依赖安装失败,npm或pip一直报错
现象:管道前面的步骤都正常,到了"安装依赖"这一环就红了。npm 报 "ENOENT" 或 "404 Not Found",pip 报 "Could not find a version that satisfies the requirement",看起来是包找不到。
原因:微软托管的构建机器是全新的,每次跑完就销毁,所以机器上没有任何缓存和多余的全局包。如果安装命令里引用的依赖源地址过期了,或者包名写错了,就会直接失败。还有一类情况是缺少系统级运行库,导致某个底层工具装不上。
解决:先展开失败步骤的完整日志,看清楚失败的命令是哪一行。如果是下载源的问题,换用官方源或可用的镜像源。如果是缺少系统库,可以在安装依赖之前加一步,先执行系统包管理命令把基础库装上。还有一个好习惯:在安装依赖前先升级包管理工具本身,很多诡异的安装报错都是因为包管理器版本太旧。
5.3 坑三:私有项目的免费分钟数很快用完
现象:管道突然不再启动了,运行请求一直在排队或者直接提示资源不可用,页面提示没有可用的并行作业额度。如果你用的是私有项目,每个月默认只有 1800 分钟(也就是 30 小时)的免费构建时长。
原因:每次管道运行都在消耗免费分钟数,构建越频繁、单次构建越久,额度消耗越快。新手反复调试的过程中,很容易就把一个月的额度用掉一大半,然后在下一次真正需要发布的时候发现没额度了。
解决:三个方向。如果项目本身允许公开源码,可以把项目改成"公开",公开项目使用管道不占用免费分钟数。或者配置一台自托管 Agent,自托管的构建不消耗托管时长。另外,优化构建速度也能变相省额度,比如启用依赖缓存、减少不必要的步骤,让每次构建跑得更快。
5.4 坑四:管道一直在排队,构建迟迟不开始
现象:代码提交后,管道状态一直停在"排队中",等了几十分钟还在排队,看起来就像卡住了一样。
原因:账户的并行作业数是有限的,免费额度下同一时间能并行跑的作业通常只有一个。如果你同时触发多个管道,或者上一个构建还占着唯一的并行额度,新触发的就会排队等待。
解决:先打开运行历史,看看是不是有卡住或长时间运行的旧构建占着额度。如果有,直接取消那些没必要跑的构建,排队就会立刻消失。如果确认没有占用,还是排着队,再检查是否触发了数量限制。这个问题的排查思路其实很简单:先挤掉占坑的,再看别的。
5.5 坑五:密钥明文写在 YAML 里
现象:管道跑通了,但过一段时间发现,数据库密码、存储连接串这些敏感值被明文写在 azure-pipelines.yml 文件里,而这个文件已经被提交进了共享仓库,甚至公开仓库。
原因:图省事。很多新手第一次配置管道时,顺手就把密钥复制粘贴进 YAML——因为这样最快,而且本地跑确实能用。但问题在于,YAML 文件是跟着代码仓库走的,仓库的可见范围就是 YAML 内容的可见范围,一旦仓库共享出去,密钥就跟着泄露了,这个时候可没有后悔药吃。
解决:把密钥放进变量组,并在变量组设置里把它标记为"机密",这样日志里会自动打码。更严谨的做法是把密钥放到 Azure Key Vault 之类的专用机密管理服务里,通过服务连接在管道内读取。任何不应该公开的值,都不可以明文出现在 YAML 文件里。如果发现已经泄露,不要只删文件了事,一定要立刻到对应平台轮换该密钥,强制失效换新。
6. 下一步怎么学:从能跑通到能独立搭建
到这里,你已经走完了"了解概念、注册账号、创建并运行第一个管道、读懂基本 YAML、避开常见坑"的完整入门过程。接下来按什么顺序继续深入,我给出我比较推荐的一条路径。
第一件事:试着改模板。把第 3 章生成的 YAML 里的脚本,换成你自己项目的真实命令,比如让管道跑一遍项目完整的测试命令。能改通,说明你真正开始操作了。第二件事:学习让管道"发布产物"。在官方教程里检索发布 NuGet 包、npm 包或 Python 包的文档,把你构建好的包发布出去。这个话题你可能暂时用不上,但它是理解"CI 的产物如何交给 CD 使用"的关键一课。第三件事:挑战多阶段部署。定义一个既有构建又有部署的管道,先把文件构建出来,再部署到一个测试环境,并在阶段之间加上人工审批,体验一把"没人确认就不会往下走"的发布流程。第四件事:熟悉变量组和服务连接,然后去配置一个真实部署目标,比如一台云虚拟机。等这一步做完,你基本已经能独立搭建一个像样的 CI/CD 管道了。最后,再回头翻官方文档的概念区,把环境、模板、门禁这些概念逐个补齐。
给你讲一个我自己的小教训:我刚开始学的时候,特别喜欢在 YAML 里堆功能,触发条件写得花哨,变量用了一堆,结果一跑就挂。后来我改了一个习惯:先跑通最简单的版本,再加下一个功能,每加一项都确认之前的功能都还正常。从那以后,我的每个管道基本都是一次成型。另外一个很实用的小习惯是,每次管道报错,不要只看日志的最后几行,要从失败的步骤往回翻十几行,前因后果才能连起来。把这个习惯坚持下去,你排查问题的速度会明显快起来。希望这份指南能帮到你,接下来就打开控制台,动手创建你的第一个管道吧。
本文还有配套的精品资源,点击获取