在 上文中我介绍了ASP.NET Core应用程序容器化时需要注意的几个问题,并给出了一个案例应用程序: tasklist。今天接着上文的内容,继续了解一下如何使用Azure DevOps进行ASP.NET Core应用程序的持续集成。为了便于讨论,本文会将持续集成(Continuous Integration)缩写为CI,而将持续部署(Continuous Deployment)缩写为CD。 Azure DevOps前身是Visual Studio Team Services(VSTS),从2018年9月10日开始,VSTS改名为Azure DevOps,原来VSTS所提供的服务也作了相应的调整。有关Azure DevOps的介绍,可以参考 https://azure.microsoft.com/en-us/blog/introducing-azure-devops/。
容器化应用程序的CI/CD流程
下图展示了基于微软技术架构的容器化应用程序的CI/CD流程: 大致流程如下:
- 开发人员通过Visual Studio Team Services Backlog(也就是最新的Azure Boards)获取一些开发任务
- 开发人员使用Visual Studio进行应用程序开发
- 开发的代码保存在Visual Studio Team Services Git(也就是最新的Azure Repos)
- Visual Studio Team Services CI(也就是最新的Azure Pipelines)从代码库获取代码,进行编译和持续集成
- 编译产生的容器被推送到Azure Container Registry
- Visual Studio Team Services CD(也就是最新的Azure Pipelines)触发持续部署,从Azure Container Registry获取容器镜像,然后部署到Azure Container Service中(这里使用托管的Kubernetes服务作为例子)
- Azure Application Insights对运行的应用程序进行跟踪分析,并将结果反馈给开发人员
- 开发人员将结果记录到Visual Studio Team Services Backlog(也就是最新的Azure Boards)中
这个过程还是比较容易理解的。图片来自 https://azure.microsoft.com/en-us/solutions/architecture/cicd-for-containers/。对于tasklist而言,我所采用的持续集成/持续部署方案跟上图流程差不多,所不同的是,我没有使用Azure Repos,而是使用众所周知的GitHub,我也没有使用Azure Container Registry,而是使用Docker Hub。接下来,我们一起了解一下Azure DevOps Pipeline持续集成的配置过程。
基于Azure DevOps为tasklist搭建持续集成环境
首先使用你的微软账号(Microsoft Account)登录 Azure DevOps,默认还是会进入经典的VSTS界面,此时点击屏幕右上角的大头贴图标,选择Preview features: 然后在Preview features中打开New Navigation选项即可进入Azure DevOps的新界面: 接下来,我们可以点击界面右上角的Create project按钮来创建一个新的项目。在创建新项目的界面中,输入项目名称和描述,然后决定是否公开该项目,之后在Advanced部分可以选择版本控制方案(Git或者Team Foundation Version Control),并且选择一个开发流程。这里我将项目命名为tasklist-demo,版本控制方案使用Git,开发流程就选择Agile(其实在我们的案例中,这并不重要)。一切就绪之后,点击Create按钮创建项目。 项目创建成功之后,就自动进入了如上图所示的项目仪表板(Dashboard),此时我们可以在Boards里创建一些开发任务,然后通过Repos界面来初始化我们的代码库。不过,这两个步骤我们都不需要做,因为我们的代码已经在GitHub中了,我们可以直接进入Pipelines,定义我们的项目构建过程。
- 在Pipelines项目下,点击Builds,然后点击New pipeline按钮。在创建Build Pipeline的第一步,需要选择代码来源。Azure DevOps提供各种选择:Azure Repos Git、GitHub、GitHub Enterprise、Subvision、Bitbucket Cloud以及External Git。对于tasklist而言,我们选择使用GitHub。此时,如果你还没有创建GitHub连接,则需要新建一个。如下图指定GitHub连接的名称,然后通过OAuth或者GitHub访问token进行安全认证:
- 在认证成功后,即可选择需要编译的代码库,并指定需要编译的代码所在的分支(Branch)。在一切就绪后,点击Continue按钮继续:
- 接下来,在Select a template页面中,点击Empty job来创建一个空的构建任务,当然,也可以根据需要,在预定的构建模板中进行选择
- 在新建的Buid Pipeline中,可以看到,所有操作的第一步就是获取源代码,这一步已经在上面定义好了,不过还可以在这个界面中进行一些高级设置,比如可以指定在签出代码时,将submodule也同时签出
- 我们需要关注的就是Agent Job,一个Build Pipeline中,可以包含多个Agent Job,也就是执行过程需要Build Agent支持的Job;也可以包含多个Agentless Job,也就是执行过程不需要Build Agent支持的Job。Agent Job的执行需要依赖某种环境,比如托管的Linux环境,或者是装有VS2017的Windows环境。而Agentless Job的执行则不需要这样的环境,比如,调用RESTful API,或者设置一个定时器,延迟后续Job的执行等。对于tasklist而言,我们需要一个Linux的环境来执行Docker容器构建,因此,可以选择Hosted Ubuntu 1604的Agent Pool,于是,当代码构建开始执行时,Azure DevOps会从Hosted Ubuntu 1604的Agent池中,选择一个Agent执行构建
- 接下来,在这个新建的Agent Job中,点击加号(+),然后在列出的所有任务模板中,选择Docker Compose,并点击Add按钮,将它添加到Agent的任务中。事实上,Azure DevOps Pipelines提供了非常多的任务模板,比如,你可以选择一个执行单元测试的模板并将其添加到Agent Job中,然后根据自己的需要,配置单元测试的运行参数,这样的话,Agent Job就能帮你完成单元测试
- 在定义Docker Compose Command的界面中,注意将Container Registry Type切换为Container Registry,然后通过点击New按钮,新建一个Docker Registry连接。由于我们选用Docker Hub作为Registry,因此,选择Docker Hub,填上自己的账号和密码后,确认能够连接就可以了:
- 在Docker Compose File文本框中,输入tasklist代码库中docker-compose.yml文件的路径,也可以点击“…“按钮,在弹出的对话框中选择该文件:
- 在Action下拉框中,指定所执行的操作为Build service images,然后,在Additional Image Tags中,可以指定$(Build.BuildNumber),表示使用当前的构建编号为构建产生的容器镜像打上tag,同时可以选择Include Latest Tag选项,表示当前构建的容器镜像为最新版本(打上latest Tag)。完成这部分设置之后,参数大致如下:
- 在完成了上述步骤之后,我们已经可以完成整个tasklist App的编译了。可以看到,在Azure DevOps中设置Build Pipeline进行代码编译是非常简单的。由于我们已经定义了用于代码编译的Docker Compose文件,所以,只需要在Pipeline中添加一个Docker Compose的编译任务即可。现在测试一下,看看编译是否能够成功完成:
- 到目前为止,我们只是成功编译了tasklist的容器镜像,还没有将镜像推送到Docker Hub。在容器镜像被推送到Docker Hub之后,我们才能够将容器部署到Azure Container Service中运行。要推送编译好的容器镜像,只需要重复以上6到10步,在Agent Job下再添加一个Docker Compose的任务,所不同的是,Action需要修改为Push service images,保持其它配置不变。保存完Pipeline之后,再次触发编译:
- 打开Docker Hub,看看镜像是否已经成功推送:
- 最后一步,就是要将tasklist代码库中的yml文件作为编译结果(Artifacts)公布出来,这样做是为了在下一步做Azure Kubernetes Service(AKS)部署的时候,能够获取到部署的定义文件并根据该文件的内容进行部署。使用上述第6步的方法,添加一个Copy Files的任务和一个Publish Build Artifacts的任务。Copy Files的任务设置如下: Publish Build Artifacts的任务设置如下:
- 再次启动Build Pipeline,可以看到,tasklist已经成功编译: 所需的编译结果文件(yml文件)也复制成功:
- 在Triggers页面,可以选择Enable continuous integration选项,此时每当有新的代码签入代码库,就会触发一次新的构建。当然,还有一些高级选项,比如选择代码分支等,还可以启用Pull request validation,这些内容与持续集成的流程有关,我们可以在今后学习,在这里,我们先勾选Enable continuous integration选项
总结
本文首先简单介绍了容器化应用程序的CI/CD流程,然后基于Azure DevOps,为tasklist案例建立了一个Build Pipeline,成功完成了tasklist App的编译以及Docker容器镜像的发布,最后,启用了持续集成功能,使得每次代码变更提交都会触发CI过程。这部分设置与开发过程以及持续集成的流程有关,不同的项目进行持续集成的方式也会有所不同,我们可以单独在其它篇章中进行深入讨论学习。在接下来的第三部分,让我们一起看看,如何把编译好的tasklist容器部署到Azure Kubernetes Service中。