阿里云Kubernetes实战3--DevOps
前言:
在上一篇文章中,我们已经在K8S集群部署了Jenkins、Harbor和EFK。作为本系列最后一篇文章,将通过实际案例串联所有的基础软件服务,基于K8S做DevOps。
整体的业务流程如下图所示:
一、一机多Jenkins Slave
由于业务需要,我们的自动化测试需要基于windows做web功能测试,每一个测试任务独占一个windows用户桌面,所以我们首先要给Jenkins配置几个Windows的Slave Node.在我之前的post《持续集成CI实施指南三–jenkins集成测试》中详细讲解了给Jenkins添加Node的方法步骤。 本篇无需重复,但这里主要讲的是,如何在一台Windows服务器上搭建多个Jenkins Node,供多用户使用。
在目标机上建立多个用户,如下图所示:
用Administrator用户安装JDK
在Jenkins的节点管理建立三个Node,分别为WinTester01、WinTester02、WinTester03,配置如下
在目标机的Administrator,用IE打开Jenkins并进入节点管理,在WinTester01、WinTester02、WinTester03中分别点击“Launch”启动Slave
确认启动成功后,点击“File”下的“Install as service”
三个Slave都启动后,可以在服务管理器看到
除了Jenkins Slave1无需配置,Slave2和Slave3都需要右键进入属性,修改登录用户分别为JenkinsSlave2和JenkinsSlave3
通过上面的配置,可以在一台目标机部署三个用户对应三个Jenkins Slave以满足我们的业务需求。
二、 二次开发Jenkins 钉钉通知插件
在整个DevOps的业务流程图上,我们想使用钉钉作为通知方式,相比邮件而言,实时性和扩展性都很高。在2018年4月,Jenkins的钉钉通知插件有两款,分别是Dingding JSON Pusher和Dingding notification plugin,前者长期未更新,已经不能使用,后者可以在非Pipeline模式下使用,对于Pipeline则有一些问题。虽然目前,Dingding notification plugin已经更新到1.9版本并支持了Pipeline,但在当时,我们不得不在1.4版本的基础上做二次开发。
整体开发经过参考《Jenkins项目实战之-钉钉提醒插件二次开发举例》,总体来说还是比较简单:
修改”src/main/java/com/ztbsuper/dingtalk/DingTalkNotifier.java”,钉钉的消息API类型有文本、link、markdown、card等,我们这里把通知接口改成文本类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71public class DingTalkNotifier extends Notifier implements SimpleBuildStep {
private String accessToken;
private String message;
private String imageUrl;
private String messageUrl;
public DingTalkNotifier(String accessToken, String message, String imageUrl, String messageUrl) {
this.accessToken = accessToken; //钉钉的accesstoken
this.message = message; //消息主体
this.imageUrl = imageUrl; //缩略图
this.messageUrl = messageUrl; //消息的链接来源,一般是jenkins的build url
}
public String getAccessToken() {
return accessToken;
}
public String getMessage() {
return message;
}
public String getImageUrl() {
return imageUrl;
}
public String getMessageUrl() {
return messageUrl;
}
public void perform( Run<?, ?> run, FilePath filePath, Launcher launcher, TaskListener taskListener)throws InterruptedException, IOException {
String buildInfo = run.getFullDisplayName();
if (!StringUtils.isBlank(message)) {
sendMessage(LinkMessage.builder()
.title(buildInfo)
.picUrl(imageUrl)
.text(message)
.messageUrl(messageUrl)
.build());
}
}
private void sendMessage(DingMessage message) {
DingTalkClient dingTalkClient = DingTalkClient.getInstance();
try {
dingTalkClient.sendMessage(accessToken, message);
} catch (IOException e) {
e.printStackTrace();
}
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {
public boolean isApplicable(Class<? extends AbstractProject> aClass) {
return true;
}
public String getDisplayName() {
return Messages.DingTalkNotifier_DescriptorImpl_DisplayName();
}
}
}用maven打包
maven需要安装java环境,为了方便,我直接run一个maven的docker image,编译完成后把hpi文件send出来
在jenkins的插件管理页面上传hpi文件
在钉钉群中开启自定义机器人
找到accesstoken
在jenkins pipeline中可以使用以下命令发送信息到钉钉群
1
dingTalk accessToken:"2fccafaexxxx",message:"信息",imageUrl:"图片地址",messageUrl:"消息链接"
三、 DevOps解决方案
针对每一个软件项目增加部署目录,目录结构如下:
- _deploy
- master
- deployment.yaml
- Dockerfile
- other files
- test
- deployment.yaml
- Dockerfile
- other files
- master
master和test文件夹用于区分测试环境与生产环境的部署配置
Dockerfile和other files用于生成应用或服务的镜像
如前端vue和nodejs项目的Dockerfile:
1 | # 前端项目运行环境的Image,从Harbor获取 |
又如dotnet core项目的Dockerfile:
1 | # dotnet项目编译环境的Image,从Harbor获取 |
deployent.yaml用于执行应用或服务在k8s上的部署
由于deployment有很多配置项可以抽离成公共配置,所以deployment的配置有很多占位变量,占位变量用两个#中间加变量名表示,如下所示:
1 | apiVersion: v1 |
其中几个关键变量的解释如下:
- dockerconfigjson:因为所有的镜像需要从Harbor获取,而Harbor的镜像如果设置为私有权限,就需要提供身份验证,这里的dockerconfigjson就是Harbor的身份信息。生成dockerconfigjson的方法如下:
- 进入K8S任何一个节点,删除” ~/.docker/config.json “ 文件
- 使用命令” docker login harbor地址”登录harbor
- 通过命令” cat ~/.docker/config.json “可以看到harbor的身份验证信息
- 使用命令” cat /root/.docker/config.json | base64 -w 0 “对信息编码,将生成后的编码填写到deployment.yaml的dockerconfigjson节点即可
- namespace:同一个项目的不同k8s组件应置于同一个namespace,所以namespace可统一配置,在我们的项目实践中,生产环境的namespace为” 项目名 “,测试环境的namespace为” 项目名-test “
- app:应用或服务名称
- image:应用或服务的镜像地址
- replicas:副本数量
- port:应用或服务的Pod开放端口
- log:应用或服务的日志路径,在本系列的第二篇文章中,提到我们的日志方案是给每个应用或服务配一个filebeat,放在同一Pod中,这里只需告知应用或服务的日志的绝对路径,filebeat就能将日志传递到ES中,日志的tag命名方式为” namespace-app”
- host:在本系列的第一篇文章中,讲了使用nginx ingress做服务暴露与负载。这里的host就是给nginx ingress设置的域名,端口默认都是80,如果需要https,则在外层使用阿里云SLB转发
- urlPath:很多情况下,如微服务,需要通过相同的域名,不同的一级目录将请求分发到不同的后台,在nginx中,就是location的配置与反向代理,比如host的配置是确定了域名aaa.bbb.com,而urlPath的配置是确定aaa.bbb.com/user/getuser将会被转发到用户服务podIP:podPort/getuser中
以上所有的占位变量都是在Pipeline Script中赋值,关于Jenkins Pipeline的相关内容介绍这里不再多讲,还是去看官方文档靠谱。我们这里将k8s的部署文件deployment.yaml与Jenkinsfile结合,即可做到一个deployment.yaml能适配所有项目,一个Pipeline Script模板能适配所有项目,针对不同的项目,只需在Pipeline Script中给占位变量赋值,大大降低了配置复杂度。下面是一个项目的Jenkins配置示例:
对于一个项目,我们只需配置Trigger和Pipeline,上图“Do not allow concurrent builds ”也是通过Pipeline的配置生成的。Pipeline Script示例如下:
1 | pipeline { |
发布完成后,可以参考《持续集成CI实施指南三–jenkins集成测试》,做持续测试,测试结果也可通过钉钉通知。最后我们利用自建的运维平台,监控阿里云ECS状态、K8S各组件状态、监控ES中的日志并做异常抓取和报警。形成一整套DevOps模式。
综上,对于每个项目,我们只需维护Dockerfile,并在Jenkins创建持续集成项目时,填写项目所需的参数变量。进阶情况下,也可定制性的修改deployment文件与pipeline script,满足不同的业务需要。至此,完结,撒花!
阿里云Kubernetes实战3--DevOps