庐山真面目之十一微服务架构手把手教你搭建基于Jenkins的企业级CI/CD环境
一、介绍
说起微服务架构来,有一个环节是少不了的,那就是CI/CD持续集成的环境。当然,搭建CI/CD环境的工具很多,但是有一个工具它却是出类拔萃,是搭建持续集成环境的首选,它就是Jenkins。在这里,有关Jenkins的具体内容我就不说了,网上有很多,我在这里只做很简单的介绍。Jenkins 自动化部署可以解决集成、测试、部署等重复性的工作,工具集成的效率明显高于人工操作;并且持续集成可以更早的获取代码变更的信息,从而更早的进入测试阶段,更早的发现问题,这样解决问题的成本就会显著下降:持续集成缩短了从开发、集成、测试、部署各个环节的时间,从而也就缩短了中间出现的等待时间;持续集成也意味着开发、集成、测试、部署得以持续。我们今天就开始搭建一个企业级别的CI/CD的环境,这个内容很多,也需要有很多的基础,比如:必须安装Docker了,必须会使用Linux系统,必须会使用Git,对GitHub比较熟悉,当然也要对Net5.0有所认识,等等还有很多,这些基础知识,我假定大家都是熟悉的,毕竟,文章要有主有次。
二、准备工作
1、开发环境升级,将Net Core3.1的环境升级为 Net5.0
官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/migration/31-to-50?view=aspnetcore-5.0&tabs=visual-studio#prerequisites
下载地址:https://dotnet.microsoft.com/download/dotnet/5.0
2、安装 Git 源代码托管工具。
在工作开始之前,先要检查自己是否安装了Git工具,如果安装了,就可以跳过本节,如果没有安装,那就跟着我们开始安装吧。当然了,安装完成之后,我们还要配置 VS 2019 的源代码管理工具是 Git,很简单,我就不写了。
(1)、去官网下载Git的安装文件,地址::https://git-scm.com/downloads/
(2)、将下载下来的 Git 安装包,存在自己的目录里,文件名:Git-2.30.0-64-bit.exe,双击该文件开始安装。
(3)、选择安装的组件,保持默认就好(我的选择)。
(4)、选择默认编辑器,保持默认就好(我的选择)。
(5)、可以修改默认分支的名称,我选择保持默认(我的选择)。
(6)、可以设置环境变量,保持默认就可以(我的选择)。
(7)、选择Https 传输协议,保持默认。
(8)、配置终端使用 Git Bash,保持默认就好。
(9)、配置行未的转换符。
(10)、选择“git pull”的默认行为,默认选择。
(11)、选择凭据帮助程序。
(12)、配置额外选项。
(13)、配置实验选项。
(14)、开始安装。
(15)、安装成功。
(16)、如何判断 Git 是否安装成功,在空白地方(任何地方),点击右键,出现如图效果表示安装成功。
3、新建一个Net5.0的项目,然后将其上传至 Git 服务器。
由于是测试项目,所以每个项目的代码都很简单,因为代码不是重点。
(1)、新建项目
【1】、PatrickLiu.CICD.Clients(Asp.Net Core WebApi),一个Core API项目。
代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Threading; 5 using Microsoft.AspNetCore.Mvc; 6 using Microsoft.Extensions.Configuration; 7 using Microsoft.Extensions.Logging; 8 using PatrickLiu.CICD.Interfaces; 9 using PatrickLiu.CICD.Models; 10 11 namespace PatrickLiu.CICD.Clients.Controllers 12 { 13 /// <summary> 14 /// 用户的 API 类型。 15 /// </summary> 16 [Route("api/[controller]")] 17 [ApiController] 18 public class UsersController : ControllerBase 19 { 20 #region 私有字段 21 22 private readonly ILogger<UsersController> _logger; 23 private readonly IUserService _userService; 24 private IConfiguration _configuration; 25 26 #endregion 27 28 #region 构造函数 29 30 /// <summary> 31 /// 初始化该类型的新实例。 32 /// </summary> 33 /// <param name="logger">日志记录器。</param> 34 /// <param name="userService">用户服务接口。</param> 35 /// <param name="configuration">配置服务。</param> 36 public UsersController(ILogger<UsersController> logger, IUserService userService, IConfiguration configuration) 37 { 38 _logger = logger; 39 _userService = userService; 40 _configuration = configuration; 41 } 42 43 #endregion 44 45 #region 实例方法 46 47 /// <summary> 48 /// 获取一条记录 49 /// </summary> 50 /// <param name="id"></param> 51 /// <returns></returns> 52 [HttpGet] 53 [Route("Get")] 54 public User Get(int id) 55 { 56 return _userService.FindUser(id); 57 } 58 59 /// <summary> 60 /// 获取所有记录。 61 /// </summary> 62 /// <returns></returns> 63 [HttpGet] 64 [Route("All")] 65 //[Authorize] 66 public IEnumerable<User> Get() 67 { 68 Console.WriteLine($"This is UsersController {this._configuration["port"]} Invoke"); 69 70 return this._userService.UserAll().Select((user => new User 71 { 72 ID = user.ID, 73 Name = user.Name, 74 Account = user.Account, 75 Password = user.Password, 76 Email = user.Email, 77 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}", 78 LoginTime = user.LoginTime 79 })); ; 80 } 81 82 /// <summary> 83 /// 超时处理 84 /// </summary> 85 /// <returns></returns> 86 [HttpGet] 87 [Route("Timeout")] 88 public IEnumerable<User> Timeout() 89 { 90 Console.WriteLine($"This is Timeout Start"); 91 //超时设置。 92 Thread.Sleep(3000); 93 94 Console.WriteLine($"This is Timeout End"); 95 96 return this._userService.UserAll().Select((user => new User 97 { 98 ID = user.ID, 99 Name = user.Name, 100 Account = user.Account, 101 Password = user.Password, 102 Email = user.Email, 103 Role = $"{this._configuration["ip"]}:{this._configuration["port"]}", 104 LoginTime = user.LoginTime 105 })); ; 106 } 107 108 #endregion 109 } 110 }
1 using Microsoft.AspNetCore.Builder; 2 using Microsoft.AspNetCore.Hosting; 3 using Microsoft.Extensions.Configuration; 4 using Microsoft.Extensions.DependencyInjection; 5 using Microsoft.Extensions.Hosting; 6 using Microsoft.OpenApi.Models; 7 using PatrickLiu.CICD.Interfaces; 8 using PatrickLiu.CICD.Services; 9 10 namespace PatrickLiu.CICD.Clients 11 { 12 public class Startup 13 { 14 15 /// <summary> 16 /// 17 /// </summary> 18 /// <param name="services"></param> 19 public void ConfigureServices(IServiceCollection services) 20 { 21 services.AddSingleton<IUserService, UserService>(); 22 services.AddControllers(); 23 services.AddSwaggerGen(c => 24 { 25 c.SwaggerDoc("v1", new OpenApiInfo { Title = "PatrickLiu.CICD.Clients", Version = "v1" }); 26 }); 27 } 28 } 29 }
【2】、PatrickLiu.CICD.Interfaces(Net Core 类库项目),定义抽象接口。
代码如下
1 using PatrickLiu.CICD.Models; 2 using System.Collections.Generic; 3 4 namespace PatrickLiu.CICD.Interfaces 5 { 6 /// <summary> 7 /// 用户服务的接口定义。 8 /// </summary> 9 public interface IUserService 10 { 11 /// <summary> 12 /// 查找指定主键的用户实例对象。 13 /// </summary> 14 /// <param name="id">用户的主键。</param> 15 /// <returns>返回查找到的用户实例对象。</returns> 16 User FindUser(int id); 17 18 /// <summary> 19 /// 获取所有用户的实例集合。 20 /// </summary> 21 /// <returns>返回所有的用户实例。</returns> 22 IEnumerable<User> UserAll(); 23 } 24 }
【3】、PatrickLiu.CICD.Models(Net Core 类库项目),定义数据模型。
代码如下:
1 using System; 2 3 namespace PatrickLiu.CICD.Models 4 { 5 /// <summary> 6 /// 用户模型。 7 /// </summary> 8 public class User 9 { 10 /// <summary> 11 /// 获取或者设置用户主键。 12 /// </summary> 13 public int ID { get; set; } 14 15 /// <summary> 16 /// 获取或者设置用户姓名。 17 /// </summary> 18 public string Name { get; set; } 19 20 /// <summary> 21 /// 获取或者设置用户账号名称。 22 /// </summary> 23 public string Account { get; set; } 24 25 /// <summary> 26 /// 获取或者设置用户密码。 27 /// </summary> 28 public string Password { get; set; } 29 30 /// <summary> 31 /// 获取或者设置用户的电子邮箱地址。 32 /// </summary> 33 public string Email { get; set; } 34 35 /// <summary> 36 /// 获取或者设置用户角色。 37 /// </summary> 38 public string Role { get; set; } 39 40 /// <summary> 41 /// 获取或者设置用户的登录时间。 42 /// </summary> 43 public DateTime LoginTime { get; set; } 44 } 45 }
【4】、PatrickLiu.CICD.Services(Net Core 类库项目),定义服务实现类型。
代码如下:
1 using PatrickLiu.CICD.Interfaces; 2 using PatrickLiu.CICD.Models; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 7 namespace PatrickLiu.CICD.Services 8 { 9 /// <summary> 10 /// 实现用户服务接口的实现类型。 11 /// </summary> 12 public class UserService : IUserService 13 { 14 private IList<User> dataList; 15 16 /// <summary> 17 /// 初始化类型的实例 18 /// </summary> 19 public UserService() 20 { 21 dataList = new List<User>() 22 { new User {ID=1,Name="黄飞鸿-修改",Account="HuangFeiHong",Password="HuangFeiHong123456",Email="huangFeiHong@sina.com", Role="Admin", LoginTime=DateTime.Now }, 23 new User {ID=2,Name="洪熙官",Account="HongXiGuan",Password="HongXiGuan54667",Email="HongXiGuan@sina.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-5) }, 24 new User {ID=3,Name="方世玉",Account="FangShiYu",Password="FangShiYu112233",Email="fangShiYu@163.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-30) }, 25 new User {ID=4,Name="苗翠花",Account="MiaoCuiHua",Password="MiaoCuiHua887766",Email="miaoCuiHua@sohu.com", Role="Admin", LoginTime=DateTime.Now.AddDays(-90) }, 26 new User {ID=5,Name="严咏春2",Account="YanYongChun",Password="YanYongChun09392",Email="yanYongChun@263.com", Role="Admin", LoginTime=DateTime.Now.AddMinutes(-50) }}; 27 } 28 29 /// <summary> 30 /// 查找指定主键的用户实例对象。 31 /// </summary> 32 /// <param name="id">用户的主键。</param> 33 /// <returns>返回查找到的用户实例对象。</returns> 34 public User FindUser(int id) 35 { 36 return dataList.FirstOrDefault(user => user.ID == id); 37 } 38 39 /// <summary> 40 /// 获取所有用户的实例集合。 41 /// </summary> 42 /// <returns>返回所有的用户实例。</returns> 43 public IEnumerable<User> UserAll() 44 { 45 return dataList; 46 } 47 } 48 }
(2)、在Visual Studio 2019中增加Git账号。
如果没有在Visual Studio 2019种添加账号,那就增加一下,方便进行Git相关操作。
【1】、点击 Visual Studio 2019 【帮助】菜单,选择【注册产品】,打开添加账号窗口。
【2】、点击【所有账户】右边的【+添加】菜单,将 GitHub 账号增加进来。
【3】、如果已经添加过账号,会显示出来。
如果没有GitHub账号,赶紧去申请一个,毕竟,我们要使用Git作为我们的源代码管理工具。说明:账号的确认页面,不要使用Microsoft Edge浏览器,因为这个浏览器总是验证(验证图标总是转圈),换个浏览器,我使用的是 Firefox ,很快就添加成功,具体原因我还没找到。
(3)将项目推送至Git服务器。
【1】、在【解决方案】上点击右键,选择【Git创建远程仓库】,打开创建仓库的窗体。
【2】、打开【创建GIT存储库】页面,进行设置,去掉【专用】选项,很简单就不多说了。
【3】、点击按钮【创建并推送】,完成操作。
完成操作,已经将我们的项目成功推送到 Github服务器
(4)、检查Github服务器上是否存在我们的项目。
三、开始搭建环境
1、准备4台服务器,构建企业级别 CI/CD 环境。
(1)、Jenkins 持续集成服务器,地址:192.168.127.146。
(2)、Docker Harbor 私服服务器,地址:192.168.127.143。
(3)、Docker 镜像构建服务器,地址:192.168.127.144。
(4)、发布服务器,地址:192.168.127.145。
2、搭建 Jenkins 持续集成服务器,服务器地址【192.168.127.146】。
要想搭建持续集成的环境,Jenkins是一个绕不过的话题。这台服务器也是我们企业级持续集成环境的核心,它搭建好了,也就完成了60%配置的任务了,废话不多说,我们开始吧,环节很多,大家要好好的看了。
(1)、开始安装 Jenkins,这里就省略了,如果想看安装步骤,请看我的《如何在Linux(CentOS7)环境搭建 Jenkins 服务器环境》。
网页地址:http://192.168.127.146:8084
登录账号:Administrator
登录密码:***********
(2)、登录Jenkins服务器,点击【Manage Jenkins】–》【Global Tool Configuration】按钮,打开【Global Tool Configuration】配置页面。
第一次登陆 Jenkins ,主要是为了两项全局配置,第一项是查看 Java 的 JDK 是否安装好,第二项是查看 Git 是否安装好。
【1】、增加 JDK 设置,配置 JDK 信息。
【2】、增加 Git,配置 Git 执行路径。
【3】、Git 执行路径如何获取。
命令:#whereis git
Java 的 JDK 安装路径可以通过命令:#which java 查看。
(3)、继续配置,点击【Manage Jenkins】–》【Manage Plugins】,检查Git是否安装。
(4)、配置 Jenkins 从 GitHub上拉取源码,这是手动拉取的。
【1】、点击【Dashboard】菜单,【新建Item】,在右侧打开【Create a Job】页面。
【2】、创建一个任务。
工作列表如下
【3】、开始配置工作。
【4】、配置源代码管理。
【5】、为源代码管理配置认证。
【6】、开始构建,从 GitHub 服务器上拉取源码。
【7】、我的工作任务正在拉取源码。
【8】、成功拉取源码。
【9】、点击【Dashboard】–》【项目名称】–》【工作空间】可以查看项目源码。
【10】、我们要实现在 Visual Studio 2019 里面,修改源码,自动同步到 Jenkins 服务器。
我们开始配置GitHub Server,在桌面【Dashboard】,点击【Manage Jenkins】–》【System Configuration】–》【Configure System】,打开【Configure System】页面。在这里我们主要配置 GitHub,其他保持默认。
1)、增加GitHub Server
然后,我们点击【管理Hook】,进入配置 Hook 页面,点击【覆盖 Hook Url】,由于我们这个地址是内网地址,所以这个url不能直接使用(外网地址就不用穿透了),要通过内网穿透实现,下边有实现方法。
这个地址可以直接保存,后面,我把这个内网地址穿透就可以。
2)、我们获取认证 Token,我们必须登录 GitHub.com 服务器。
1》、点击系统【Settings】菜单,进入设置页面。
2》、点击【Developer settings】,进入设置页面。
3》、点击【Personal access tokens】菜单,继续点击【Generate new token】按钮。
4》、进入【New personal access token】页面,进入相关设置。
5》、回到【Personal access tokens】页面,点击【复制】就可以获取Token,这个 Tokens 是为了建立 GitHub Server 通信凭据使用的,也就是步骤 2)里面要写的秘密文本。
3)、增加认证。
【11】、GitHub Server Url 不能直接用,可以通过【Nat内网穿透】实现。
1)、https://natapp.cn/,登录官网,注册账号。
2)、https://natapp.cn/,官网下载客户端工具。
3)、登录官网,购买【免费隧道】
4)、点击【我的隧道】–》【配置】,配置我的隧道。
开始配置。
5)、运行客户端程序,登录App,必须在APP的当前目录。
命令:#natapp -authtoken=9b25a6fb003b7a36 //每次重新执行获取的地址都不一样,该窗口如果长时间打开,该地址也会刷新,改变地址。
6)、获取外网的地址。
7)、将 NatAPP 获取的网址配置到 GitHub.Com 的 WebHook,这样就可以通过外网访问 Http://192.168.127.146:8084/github-webhook/。
(5)、配置 WebHook 完成触发 Jenkins 拉取新的源码到本地工作空间。
【1】、在GitHub 右侧,点击用户账号图标,选择【Your Repositories】菜单,打开所有仓库列表。
【2】、进入目标仓库【PatrickLiu.CICD.Demo】后,点击该项目的【Settings】菜单。
进入项目,然后点击项目的【Settings】菜单。
【3】、然后选择左侧【Webhooks】,然后点击右侧【Add webhook】,增加一个 Hook。
将(12)步骤中通过内网穿透生成的Url地址增加进去。
【4】、WebHook 增加成功,恭喜,还好成功了。
(6)、配置 Jenkins 里面的项目,点击左侧【My Views】,在右侧点击项目名称旁边的下拉菜单【配置】,进入配置页面。
我们要配置【构建触发器】,选择完毕,确认无误后点击【应用】,最后点击【保存】。
(7)、测试是否可以自动生成、拉取,看看是否能触发我们 Hook。
经过以上步骤,我们的 Hook 配置成功,当VS2019 修改代码,并提交到 Github 上,并触发 Hook ,促使 Jenkins 自动拉取 Github 上的源码到 Jenkins 中。
【1】、在 Visual Studio2019 修改我们的代码,然后提交,最后推到服务器上。
修改完毕,然后全部提交,最后推送到GitHub服务器。
【2】、在 Jenkins 里面,点击左侧【My Views】,然后点击右侧项目的名称,进入该项目页面。
【3】、点击【Build History】或者【相关链接】第一条记录,进入【Build】页面详情。
【4】、点击左侧【控制台输出】,在右侧可以看到详情。
【5】、也可以点击【工作空间】,右侧点击【查看】,查看项目源码。
【6】、最后我们来看看源码,是否修改了。
源码如下:
3、搭建 Docker Harbor 私服服务器,服务器地址【192.168.127.143】。
我们有了私服,就不用去远程服务器拉取有些需要的镜像,当然,我们可以事先把一些有用的镜像退到我们私服服务器,以后使用更方便,速度更快。
(1)、检查 Docker 是否安装,Docker-compose 是否安装,具体安装步骤就不写了,因为这个不是重点。
检查 Docker 环境是否安装,如果没有就安装。
命令:#Docker –version
[root@localhost143 ~]# docker –version
Docker version 20.10.2, build 2291f61
命令:yum install -y docker,执行该命令安装 Docker,安装完成,需要升级,因为该版本太低。如果想升级 Docker ,可以查看我的这篇文章《如何将Docker升级到最新版本》
(2)、检查 Docker-compose 是否安装,如果没有那就安装。
命令:#Docker-compose –version
[root@localhost143 ~]# docker-compose –version
docker-compose version 1.25.0, build 0a186604
以上说明已经安装,如果提示 -bash: docker-compose: 未找到命令,说明没有安装。
(3)、如果还没有安装,那就安装 Docker-compose,执行以下命令。
命令:#curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
命令:#chmod +x /usr/local/bin/docker-compose
说明:Docker-compose 的安装比较麻烦,所以在这里就不详说了,大家可以查看我的《 如何安装快速 Docker 和 Docker-Compose 服务》,里面有具体的安装方法。
(4)、下载 Harbor,开始安装和配置私服服务器。
【1】、检查是否安装了 Wget 命令,如果没有安装,要安装可以执行以下命令。
命令:# yum install -y wget
【2】、下载 Harbor,别直接下,最好用下载工具,因为文件太大,有 533 M(我直接保存下载,太慢,最后才用工具下载)。
文件地址:https://github.com/goharbor/harbor/releases/download/v2.1.3/harbor-offline-installer-v2.1.3.tgz
官网:https://github.com/vmware/harbor/releases
wget命令下载:#wget https://github.com/goharbor/harbor/releases/download/v2.1.3/harbor-offline-installer-v2.1.3.tgz(下载太慢,不建议,文件有533M),我是使用迅雷下载,然后在上传到服务器吧。
(5)、将文件上传到服务器,文件名:harbor-offline-installer-v2.1.3.tgz。
服务器目录:
[root@localhost143 privatefiles]# pwd
/root/privatefiles
文件保存:
[root@localhost143 ~]# ls
/root/privatefiles/harbor-offline-installer-v2.1.3.tgz
(6)、进入文件保存路径,然后,解压文件。
命令:#tar xf harbor-offline-installer-v2.1.3.tgz
(7)、进入 Harbor 目录。
命令:# cd harbor
(8)、修改 harbor.yml.tmpl文件名为harbor.yml文件名,并进行相关配置。
【1】、将 harbor.yml.tmpl 文件名改成 harbor.yml。
命令:#cp harbor.yml.tmpl harbor.yml
【2】、修改配置文件: 配置 hostname 0.0.0.0,没有vim 就安装:yum install vim -y 强制安装。
命令:#vim harbor.yml
修改:hostname:192.168.127.143,注释掉关于https 的配置。
【3】、其他配置内容,可以熟悉一下。
【4】、保存退出 Vim。
命令:#wq
(9)、安装 Harbor 。
【1】、开始安装,执行以下命令。
命令:#./install.sh
中间很多过程省略了。。。。
【2】、默认端口号:80,访问地址:http://192.168.127.143:80。
(10)、配置Harbor 私服。
【1】、登录Harbor,账号默认:admin,密码:Harbor12345。
【2】、新建项目。
新建项目。。。
【3】、为我们的私服服务器增加私服地址配置。
1)、查看所有harbor 是否都运行在 docker 里面。
命令:# docker ps -a
2)、查看Docker 后端配置文件。
命令:#cat /etc/docker/daemon.json。
3)、增加地址,”insecure-registries”:[“192.168.127.143”]。
命令:#vim /etc/docker/daemon.json
4)、 重新加载守护进程,加载配置。
命令:#systemctl daemon-reload
5)、重新启动 Docker 服务。
命令:#systemctl restart docker
【4】、验证 Harbor 私服是否正常运行,所有服务都不能运行。
1)、网页不能运行 。
2)、Harbor 服务也运行失败。
正常顺序应该是先配置 Harbor 私服,在运行私服。
【5】、重新部署 Harbor 私服,必须在 Harbor 安装的当前目录,执行以下命令。
1)、先关闭所有服务。
命令:#docker-compose down
2)、重启所有服务。
命令:#docker-compose up –d
【6】、查看服务和网页是否正常运行,正常才是成功。
重新刷新页面,页面显示正常页面。
(11)、将镜像推向 Harbor 私服,必须遵守以下规则,新镜像名称:harbar 私服IP地址:端口号/项目名/新镜像名称:版本号。
【1】、拉去一个测试的镜像。
命令:#docker pull nginx
【2】、给镜像重新命名,格式:harbar 私服IP地址:端口号/项目名/新镜像名称:版本号。
命令:#docker tag nginx:latest 192.168.127.143/patrickliu.microservices/nginx:v1
【3】、将重新的镜像推送至 Harbor 私服。
命令:# docker push 192.168.127.143/patrickliu.microservices/nginx:v1
【4】、如果提示未登录:
命令:#docker login 192.168.127.143
username:admin
password:Harbor12345
【5】、再次将镜像推向 Harbor推送。
命令:# docker push 192.168.127.143/patrickliu.microservices/nginx:v1
【6】、检查 Nginx 镜像是否推送成功。
【7】、拉取ASP.NET CORE 镜像,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
#docker pull registry.cn-hangzhou.aliyuncs.com/newbe36524/aspnet:5.0-buster-slim
#docker tag registry.cn-hangzhou.aliyuncs.com/newbe36524/aspnet:5.0-buster-slim mcr.microsoft.com/dotnet/core/aspnet:5.0-buster-slim
【8】、拉取Net Core SDK镜像,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
#docker pull registry.cn-hangzhou.aliyuncs.com/newbe36524/sdk:5.0-buster-slim
#docker tag registry.cn-hangzhou.aliyuncs.com/newbe36524/sdk:5.0-buster-slim mcr.microsoft.com/dotnet/core/sdk:5.0-buster-slim
【9】、将 mcr.microsoft.com/dotnet/core/aspnet:5.0-buster-slim 修改 tag,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
#docker tag mcr.microsoft.com/dotnet/core/aspnet:5.0-buster-slim 192.168.127.143/patrickliu.microservices/aspnet-core5:v1
【10】、推送 ASP.NET Runtime镜像去 Harbor 私服,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
#docker push 192.168.127.143/patrickliu.microservices/aspnet-core5:v1
【11】、将 mcr.microsoft.com/dotnet/core/sdk:5.0-buster-slim 修改tag,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
#docker tag mcr.microsoft.com/dotnet/core/sdk:5.0-buster-slim 192.168.127.143/patrickliu.microservices/sdk-core5:v1
【12】、推送 ASP.NET Runtime 镜像去 Harbor 私服,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
#docker push 192.168.127.143/patrickliu.microservices/sdk-core5:v1
【13】、检查 Harbor 上是否已经成功推送了 ASP.NET Runtime 和 SDK 镜像,这里这样做是为了 Docker 构建服务器使用该镜像构建我们的Net5.0镜像。
4、搭建 Docker 镜像构建服务器,地址是【192.168.127.144】。
构建服务器主要的功能就是把 Jenkins 拉取的代码打包成 Docker 镜像,并推送到 Harbor 私服服务器,便于我们的发布服务器从私服服务器拉取镜像,并部署镜像。
(1)、编辑 Docker 配置文件:/usr/lib/systemd/system/docker.service 开启 2376 端口。
【1】、命令:#vim /usr/lib/systemd/system/docker.service,在 ExecStart 模块增加 -H tcp://0.0.0.0:2376。
【2】、重新加载配置。
命令:#systemctl daemon-reload
【3】、重启 Docker 服务。
命令:#systemctl restart docker
【4】、配置 docker 的 daemon.json 文件,增加我们的 Harbor 私服地址。
命令:#vim /etc/docker/daemon.json
“insecure-registries”:[“192.168.127.143”],如果是新文件,格式这样:{“insecure-registries”:[“192.168.127.143”]}
记得重启相关服务。
【5】、检查 Docker 镜像构建服务器是否成功配置 Harbor 私服服务器。
【6】、检查2376 端口,是否成功打开。
命令:#netstat -anp |grep 2376
(2)、在构建服务器上要配置 Harbor 私服服务器:192.168.127.143。
(3)、确定 Jenkins 是否安装了 Docker-plugin 插件,【Dashboard】—>【Manage Jenkins】—>【插件管理】
【1】、升级站点:在右侧点击【高级】,拉到最后,看到【升级站点】,将镜像地址更换为腾讯或者清华都可以。然后点击【可更新】或者【可选插件】,有数据,说明站点升级成功。
https://updates.jenkins.io/update-center.json
腾讯:http://mirror.xmlssion.com/jenkins/updates/update-center.json
清华:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
【2】、安装 Docker 插件,点击【已安装】插件,输入 Docker 关键字,看看是否安装 Docker 插件,如果没有就安装插件,点击【可选插件】,在文本框输入Docker ,在查询结果中,选择要安装的插件。
(4)、登录 Jenkins,点击【Dashboard】–》【Manage Jenkins】–》【Configure System】,进入配置页面。
在右侧,一直向下拉,看到【Cloud】菜单结束。
【1】、Configure Clouds
1)、Docker 镜像构建服务器:192.168.127.144,进入服务器,检查端口 2376 是否打开。
命令:#netstat -anp |grep 2376
2)、点击【Add a new cloud】菜单,然后选择【Docker】菜单,因为我们没有安装 K8s 插件,云里面只有一个 Docker。
3)、如果安装了 K8s,点击【Add Docker Templates…】按钮,就会生成一个列表,供你选择。但是我们没有安装 K8s,所以我们选择【Docker Cloud details…】
开始配置。
如果提示:java.net.NoRouteToHostException: 没有到主机的路由,没有主机路由问题提到的大多是防火墙问题。可以查看我的文章《java.net.NoRouteToHostException: 没有到主机的路由》。
(5)、在 .Net5.0 的项目中增加 Dockerfile 文件,这个文件必须放在解决方案的本目录,便于以后的配置,该文件中的地址换成我们的私服服务器地址(远程服务器下载太慢)。
(6)、在 Jenkins 系统中,配置我们的项目,不是源码项目,是在 Jenkins 中创建的项目,以此项目进行构建。
【1】、点击【Dashboard】菜单,然后点击右侧【项目名称】,出现下拉菜单,选择【配置】,进入配置页面。
【2】、进入【配置】页面,选择【增加构建步骤】菜单,出现下拉菜单,然后选择【Build/Publish Docker image】菜单。
【3】、进入【Build/Publish Docker Image】 页面,开始配置信息。
【4】、增加 Harbor 凭据。
【5】、选择【Build Now】,开始构建镜像。
【6】、生成我们的项目。
【7】、最后生成了我们的镜像。
【8】、检查我们的构建服务器,看看是否成功生成我们的镜像和拉取了相关镜像。
完美,是不是很开心,反正我是很开心,终于成功了。还有差一步,继续努力。
5、搭建发布服务器,地址是【192.168.127.145】。
(1)、先检查我们是否成功安装了 Docker 环境,没有就安装。
(2)、配置 Harbor 私服镜像地址:192.168.127.143,并启动相关的服务。
(3)、Jenkins 系统中,安装 Publish Over SSH 插件,用于连接发布服务器。
(4)、Jenkins 系统中,配置 Publish over SSH 环境,连接发布服务器:192.168.127.145。
(5)、在 Jenkins 系统中,配置项目,【构建后操作】–>【Send Build artifacts over SSH】,增加【Exec command】就可以。
1 echo '==========================================================' 2 3 CONTAINER_NAME=net-2021113 4 5 docker pull 192.168.127.143/patrickliu.microservices/$CONTAINER_NAME:v1 6 7 echo '====================Remote 自动容器 start ==========================' 8 9 cid=$(docker ps -a | grep "$CONTAINER_NAME" | awk '{print $1}') 10 11 if [ "$cid" != "" ] ; then 12 docker rm -f $cid 13 sleep 3s 14 fi 15 16 docker run -d --name $CONTAINER_NAME -p 10000:80 192.168.127.143/patrickliu.microservices/$CONTAINER_NAME:v1 17 18 echo '============= Remote 自动容器 end ==========================='
(6)、开始构建我们的项目。
(6)、项目成功生成并发布到了发布服务器。
(7)、通过客户端检查我们的项目是否发不成功,镜像文件已经生成,镜像已经成功启动了实例,对外端口:10000。
(8)、我们通过网页打开我们发布的项目,地址是:http://192.168.127.145:10000/api/users/all,192.168.127.145是我们的发布服务器。
太开心了。测地成功了。
四、结束
今天就写到这里了,这篇文章可能是我写的所有文章中最长的一篇,大家看的时候要有耐心。既然是企业级别的持续集成环境,当然不会只有一台服务器。我这里选择了四台服务器,分别是:192.168.127.146【Jenkins服务器】,192.168.127.143【Harbor 私服服务器】,192.168.127.144【Docker 镜像构建服务器】,192.168.127.145【发布服务器】,这四台服务器,除了 Jenkins 服务器,其他三台服务器都需要配置私服服务器的地址,而且每台服务器都要安装 Docker 环境。配置这个过程很漫长,我大概经过了两个星期才未完成,经历了很多坑,最终都解决了。十分开心,不忘初心,每天进步一点点。