前面已经介绍过了 .Net Core 程序发布到 Docker 容器的内容。但是每次通过 SSH 链接到服务器敲命令,运行脚本也是挺麻烦的一件事。程序员是最懒的,能让电脑解决的问题绝不手动解决,如果当我们push一次代码后自动build代码,自动跑单元测试,如果测试通过,自动发布程序,如果失败就发邮件通知管理员,这样的话该多美好。为了达成这个目标于是持续集成(CI)持续交付/部署(CD)就被发明出来了。CICD领域有个大名鼎鼎的工具:Jenkins,但是这次不使用它。如果你使用阿里云的话,阿里云已经提供了类似的功能,可以免去自己搭建Jenkins服务,以及Docker镜像私仓的过程,而且目前它们是免费的。
阿里云Codepipeline服务,是一套类似Jenkins的服务(其实我觉得它的核心引擎就是来自Jenkins)。#
阿里云容器镜像服务,是一个镜像仓库,可以是公开的,也可以是私有的。#
持续集成CI#
持续集成指的是,频繁地(一天多次)将代码集成到主干。
它的好处主要有两个。
(1)快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。 (2)防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
Martin Fowler说过,"持续集成并不能消除Bug,而是让它们非常容易发现和改正。"
摘自阮一峰大神的blog
下面就演示一下如何通过阿里云Codepipeline跟容器镜像服务来实现 .Net Core 程序的CICD。
持续集成#
流程#
代码push后Gitee通过webhook功能触发Codepipeline构建,构建成功后自动推送镜像到容器镜像服务
新建一个 .Net Core MVC 的程序#
新建一个 .net core mvc 程序名叫CoreCICDTest
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseKestrel(options => { options.Listen(IPAddress.Any, 5000); }); }
修改Program的main方法,使Kestrel监听5000端口
@{ ViewData["Title"] = "Home Page";} <h3> .NET CORE CICD TEST -- V 1.0</h3>
修改Home/index视图
运行一下看看效果,网站正常显示 .NET CORE CICD TEST -- V 1.0
新建一个 MSTest 项目#
在CoreCICDTest的解决方案下新建一个 MSTest 项目用来写单元测试,名叫CoreCICDTest.Tests
[TestClass] public class UnitTest1 { [TestMethod] public void TestMethod1() { string str = "00"; Assert.AreEqual(str, "00"); } }
修改UnitTest1文件中的TestMethod1方法,使其成为一个合法的TestMethod
运行一下单元测试,全部通过
添加Dockerfile文件#
FROM microsoft/dotnet:latest AS buildWORKDIR /appCOPY /. /appRUN dotnet restoreWORKDIR /app/CoreCICDTest.TestsRUN dotnet test CoreCICDTest.Tests.csprojWORKDIR /app/CoreCICDTestRUN dotnet publish -o ./out -c ReleaseEXPOSE 5000ENTRYPOINT ["dotnet", "out/CoreCICDTest.dll"]
Dockerfile注意文件名没有任何后缀,Dockerfile用来在Docker容器内自动test、build我们的代码
在Gitee上新建一个项目,并把CoreCICDTest解决方案推送上去#
使用Gitee的免费Git服务,新建一个项目名叫CoreCICDTest,使用Git Push命令把本地代码推送上去。
在阿里云容器镜像服务上新建项目并进行配置#
点击“创建镜像仓库”按钮,弹出创建界面。填写命名空间kklldog,仓库名称cicd_test
点击下一步,代码源选择“本地仓库”,点击“创建镜像仓库”完成仓库的创建
在阿里云Codepipeline上新建项目并进行配置#
点击“新建”按钮跳转至新建项目页面。这个界面跟Jenkins简直就是一模一样
项目名称填写cicd_test,这里没有.net相关的模板,囧!项目类型选择"构建一个自由风格的软件"就可以
点击下一步,填写项目基本信息,源码选择Gitee。构建类型默认是java,无所谓不用过它
点击“绑定云码账号”跳转至云码授权页面进行授权,以便阿里云可以拉取云码上的代码
进行授权后,源码管理界面就可以选择到Gitee上的项目,填写相应的分支
点击“增加构建步骤”,选择“镜像构建与发布”
在“镜像构建与发布”界面填写刚才创建的仓库信息
镜像仓库名格式为namespace/镜像仓库名。如果registry为Docker hub,拉取镜像命令为docker pull docker,则本配置项填写docker;如果 registry为阿里云Docker镜像仓库,拉取镜像命令为docker pull registry.cn-hangzhou.aliyuncs.com/acs-sample/wordpress, 则本配置项填写acs-sample/wordpress。
Registry地址 用来配置docker registry地址,如果为空,默认使用Docker hub registry (https://index.docker.io/v1/);如果使用阿里云registry, 请填写https://registry.cn-beijing.aliyuncs.com/v2/,其中地域(cn-beijing)根据用户实际的镜像仓库地域来修改。 Registry证书 用来添加授权信息,请添加Registry授权类型的证书。
勾选“远程触发器”,先填写分支master,然后点击“生成”会生成触发器地址,这里好像有点小bug,有的时候这个地址不起效,如果不起效,多生成几次试试
在“构建后操作”界面填写邮件地址,用来接收邮件通知。勾选“每次不稳定的构建都发送邮件通知”
在Gitee的CoreCICDTest项目上配置WebHook#
点击“管理>WebHook”菜单,进行WebHook的配置
WebHook的Url填写刚才Codepipeline里的“远程触发器”里生成的url地址;密码不填;勾选Push事件,勾选“激活”;点击“添加”按钮完成Webhook的配置。这样当我们push代码的时候,Gitee会自动给配置的url发送一次post请求,里面携带了详细的项目信息,提交信息等数据
当点击“添加”按钮后Gitee会立马往webHook配置的url地址Post一次请求,如果Codepipeline做出“Task has been scheduled to queue”的响应则说明Codepipeline开始进行自动构建了
返回Codepipeline项目列表,可以看到cicd_test项目已经构建成功了
这个时候构建的镜像也应该被推送到了容器镜像服务的cicd_test仓库里。
编写shell脚本运行容器#
sudo vim publish_cicd_test.sh 输入以下内容#!/bin/bashsudo docker stop cicd_test sudo docker rm cicd_test sudo docker rmi registry-vpc.cn-shanghai.aliyuncs.com/kklldog/cicd_test sudo docker login --username=xxx --password=xxx registry-vpc.cn-shanghai.aliyuncs.com sudo docker pull registry-vpc.cn-shanghai.aliyuncs.com/kklldog/cicd_test:latest sudo docker run --name cicd_test -d -p 7000:5000 -v /etc/localtime:/etc/localtime registry-vpc.cn-shanghai.aliyuncs.com/kklldog/cicd_test:latest
新建一个shell脚本命名为publish_cicd_test.sh;使用docker pull从仓库中拉取最近的镜像;使用docker run运行容器
sudo /bin/bash publish_cicd_test.sh
sudo docker ps -a
使用docker ps命令查看一下容器的运行状态,可以看到cicd_test容器已经运行成功了
使用浏览器访问一下对应的端口,网站已经正常运行了
Push代码触发构建#
刚才的构建是我们配置Webhook的时候Gitee默认发送的一次请求,正常应该是用户使用git push命令后Gitee会发送一次请求,让我们模拟一下。
修改home/index页面,把V1.0改成V2.0
提交成功之后查看Codepipeline项目列表,等待项目构建成功之后,我们再次运行一下publis_cicd_test.sh脚本,成功之后再次使用浏览器访问一下对应的端口看看home/index是否已经变为了V2.0
可以看到home/index已经变成V2.0了,说明我们的持续集成流程跑通了
持续交付/部署#
我们上面演示的过程离一开始说的push一下代码就自动构建自动发布程序就差一点点了,太晚了下次再说吧。
-----------------------------------------------
.Net Core in Docker - 使用阿里云Codepipeline及阿里云容器镜像服务实现持续交付/部署(CD)
上一次演示了如何使用阿里云Codepipeline,阿里云容器镜像服务实现CI,讲到这里我们push一下代码后就自动编译、自动跑单元测试、自动构建镜像、自动推送镜像到私仓。那么离我们最初设定的目标只差那么一小步了,那就是自动部署到测试/生产环境,这一步就是持续交付/部署(CD)。
CD其实是两个意思#
(1)Continuous delivery (持续交付) 指的是,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。
(2)continuous deployment(持续部署) 指的是代码通过评审以后,自动部署到生产环境。
之前我一直以为CD只是持续部署的意思,最近仔细查资料才发其实是有两层意思。虽然是两层意思,但是其实也差不多,都是部署到某个可以运行起来的环境中,把程序跑起来。持续交付一般是部署到测试环境,供测试团队评审;持续部署是指通过测试评审后把程序部署到生产环境。既然差不多这里我就不细分了,因为都是部署,只是部署的位置不一样。
流程#
上次的流程到把镜像推送到私仓(阿里云容器镜像服务)后就结束了,后面的流程需要手动跑shell脚本来完成。我们要把后面的流程串起来,让shell脚本自动运行起来,需要一个触发机制,比如webhook。幸好,阿里云容器镜像服务有这么一个功能,可以让我们把流程串起来,那就是触发器功能。这个触发器功能跟webhook其实差不多,当容器镜像服务收到新镜像后会对外发送一个HTTP POST请求。那么我们只需要在服务器上部署一个web服务,当接收到POST请求的时候就运行服务器端的shell脚本,拉取镜像,运行容器,这样程序就部署起来了。
新建PublishHook服务#
上面已经说了为了接收容器镜像服务发出的POST请求,需要一个web服务来接收处理请求。这个服务很简单,使用ASP.NET MVC都是杀鸡用牛刀,仅仅是监控一个请求而已。这里我使用另外一个轮子AServerhttps://github.com/kklldog/AServer 。
1. 新建一个控制台程序,取名PublishHook#
2. 使用nuget安装AServer#
3. 修改Program的main函数#
using Agile.FrameworkNetCore.Log;using System;using System.Diagnostics;namespace PublishHook{ class Program { static void Main(string[] args) { Console.WriteLine("PublishHook is running now !"); var server = new Agile.AServer.Server(); server.AddHandler(new Agile.AServer.HttpHandler() { Method = "POST", Path = "/api/hook", Handler = (req, resp) => { string shell_name = req.Query.shell; if (!string.IsNullOrEmpty(shell_name)) { RunShell(shell_name); } return resp.Write("ok"); } }); server .SetIP("0.0.0.0") .SetPort(9000) .Run(); Console.Read(); } static void RunShell(string fileName) { var processStartInfo = new ProcessStartInfo(fileName) { RedirectStandardOutput = true }; var process = Process.Start(processStartInfo); if (process == null) { Console.WriteLine("Can not run shell ."); } else { using (var sr = process.StandardOutput) { while (!sr.EndOfStream) { var str = sr.ReadLine(); Console.WriteLine(str); Logger.Info(str); } if (!process.HasExited) { process.Kill(); } } } } } }
启动一个http Server监听9000端口,添加一个http handler,接收请求,解析QueryString获取脚本名称,然后运行脚本
运行publish_hook#
sudo dotnet restoresudo dotnet publish
使用dotnet publish命令发布这个程序,然后复制到服务器上。
sudo dotnet PublishHook.dll
使用dotnet命令在服务器上运行这个服务。注意:这个服务不能使用docker运行,因为它要运行shell脚本来操作宿主机的docker。如果这个服务跑在容器内,那么它执行的shell是相对于它的容器来说的,无法操作宿主机的docker环境。
复制上次新建的publish_cicd_test.sh脚本文件到PublishHook程序目录并赋予权限#
复制上次新建的publish_cicd_test.sh脚本文件到PublishHook程序目录,一遍程序能够从根目录读取。
chmod +x publish_cicd_test.sh
使用chmod +x给shell脚本赋值可执行权限
在容器镜像服务新建触发器#
点击创建触发器
在新建界面填写触发器名称,触发器url。这个url就是PublishHook监听的地址
测试一下#
配置好容器镜像服务的触发器后,我们的配置工作基本都完成了。让我们修改一下CoreCICDTest项目,然后push到Gitee上,看push后能不能全自动的部署成功。
@{ ViewData["Title"] = "Home Page";} <h3> .NET CORE CICD TEST -- V 3.0</h3>
修改home/index首页,从V2.0改为V3.0,然后使用git push命令推送代码。等待一会后,访问一下CoreCICDTest的网址。
Wow!可以看到我们的网址已经自动部署成功了,终于完成了我们一开始设定的目标。
总结#
回顾整个过程,我们可以发现各个服务之间虽然是彼此独立,但是我们可以通过WebHook功能串联起来。甚至最后我们自己定义了一个WebHook的监听程序来替我们执行对应的脚步。其实通过这种思想我们可以把更多的流程串联起来,实现更多自动化流程。
这次我们顺利的使用阿里云的Codepipeline、容器镜像服务,实现了最基本的CICD。现在各大云服务厂商基本都提供了很多基础功能,而且大部分是免费的,有效的利用这些服务可以节省宝贵的时间,开发者可以更专注在核心业务上面。
----------------------------------------
转摘:
作者:Agile.Zhou
出处:https://www.cnblogs.com/kklldog/p/core_in_docker_cd.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。