阿里云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等,我们这里把通知接口改成文本类型
    public class DingTalkNotifier extends Notifier implements SimpleBuildStep {

       private String accessToken;
       private String message;
       private String imageUrl;
       private String messageUrl;

       @DataBoundConstructor
       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;
      }

       @Override
       public void perform(@Nonnull Run run, @Nonnull FilePath filePath, @Nonnull Launcher launcher, @Nonnull 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();
          }
      }

       @Override
       public BuildStepMonitor getRequiredMonitorService() {
           return BuildStepMonitor.NONE;
      }

       @Symbol("dingTalk")
       @Extension
       public static final class DescriptorImpl extends BuildStepDescriptor {

           @Override
           public boolean isApplicable(Class