Zadig和ChatOps能不能擦出火花

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: Zadig和ChatOps能不能擦出火花

背景介绍


Zadig 是目前很火的云原生持续交付平台,具备灵活易用的高并发工作流、面向开发者的云原生环境、高效协同的测试管理、强大免运维的模板库、客观精确的效能洞察以 及云原生 IDE 插件等重要特性,为工程师提供统一的协作平面,可以满足大部分的企业交付场景。

但是,大家有没有遇到过以下情况:

  • 当你在”带薪拉屎“的时候,叫你发流水线
  • 当你在”聆听会议精神“的时候,叫你发流水线
  • 当你身边只有手机的时候,叫你发流水线
  • ......

总之,随时随地都可能叫你发流水线,对于这种无聊而又频繁的操作,有没有更好的解决办法呢?

Zadig 在1.15.0版本的时候,已经很友好的支持手机端了,按理说应该能满足平时的工作需求。但是,作为一个爱折腾的运维,并不满足于此,我希望能够通过机器人的方式来完成某些运维工作,比如合并分支、发流水线、执行脚本等,这样做主要有以下两个好处:

  1. 移动化:随时随地能够通过移动 APP 和机器人沟通,让机器人完成本来在命令行,或者是 web 端才能完成的任务。
  2. 共享化:机器人所在群里的成员都能看到群聊信息,能够收到任务的处理结果,极大的提高了信息沟通的效率。

这其实就是 ChatOps 的实现,但是这只是初级阶段——也就是字符串匹配的方式进行操作,但是随着人工智能、机器学习等技术不断成熟,ChatOps 的交付性体验会越来越好。

当然,我还停留在初级阶段,本文也是带大家通过钉钉机器人的方式发布 Zadig 流水线。


架构解析


ChatOps 的核心在于把 WEB 端或者命令行下的人工操作,转换能通过聊天工具机器人来完成,所以整体的架构并不会很复杂,如下:


640.png


整体流程如下:

  • 技术人员在聊天群里@机器人,发送需要执行的指令
  • 机器人接收到指令,对指令进行判断
  • 根据指令执行相关操作,并将结果反馈到聊天群

要想接入到 ChatOps,需要服务有对应的开放 API。所幸,Zadig 提供了一些 API【1】,可以到文档中进行查看学习。


开发阶段


为了不重复造轮子,我使用的是 Github 上一个 ChatOps bot 框架

【2】,该框架已经实现了命令行微信网页版企业微信钉钉等聊天机器人,我们只需要在此基础上实现具体的业务即可。


封装 Zadig 请求


要实现对 Zadig 进行 API 操作,就需要我们封装 HTTP 请求,为了便于操作,我将 Zadig 的一些 API 封装了一个 SDK【3】,该 SDK 简单实现了 Zadig 开发 API 的功能(没仔细调试,也许有 Bug),如下:


640.png


现在我们只需要在项目中实现自己需要的功能即可。

首先,需要创建 Zadig 请求,创建一个zadig/zadig.go文件,实现 Zadig 初始化,代码如下:


package zadig
import (
 "errors"
 "log"
 "github.com/joker-bai/go-zadig"
)
var MyZadig myZadig
type myZadig struct {
 client *zadig.Client
}
var (
 token       = "x.x.x"
 baseURL     = "http://xxx/"
)
func Setup() *myZadig {
 client, err := zadig.NewClient(token, zadig.WithBaseURL(baseURL))
 if err != nil {
  log.Fatalf("Failed to create client: %v", err)
 }
 return &myZadig{client: client}
}

!! PS:token、url 这些配置其实是可以放到配置文件中,这里为了便于演示,就放在代码文件中了。

其中:

  • token 是用户认证使用,在 WEB 端右上角用户->账号设置中获取
  • baseURL 是 zadig 的地址

然后再在该文件中实现CreateWorkflowTask方法,该方法用于执行工作流,如下:

package zadig
var (
    callbackURL="xxx"
)
......
func (m *myZadig) CreateWorkflowTask(workfolwName, envName, serviceName, serviceType, repoName, branch string) error {
 _, _, err := m.client.Workflow.CreateWorkflowTask(&zadig.CreateWorkflowTaskOptions{
  WorkflowName: workfolwName,
  EnvName:      envName,
  Targets: []zadig.TargetArgs{
   {
    Name:        serviceName,
    ServiceType: serviceType,
    Build: zadig.BuildArgs{
     Repos: []zadig.Repository{
      {
       RepoName: repoName,
       Branch:   branch,
      },
     },
    },
   },
  },
  Callback: zadig.Callback{
   CallbackUrl: callbackURL,
  },
 })
 if err != nil {
  return errors.New("执行工作流失败")
 }
 return nil
}

该方法接收执行工作流所需的参数,然后调用 SDK 完成执行。由于我这里都是构建部署的方式,所以只写了Targets实现。


注册 Zadig 插件


上面简单的把 Zadig 执行工作流的请求封装了,接下来就注册 Zadig 插件了。

rboot 项目【2】采用插件的方式注册新的指令,系统会自动把这些指令加载到应用中,并且可以通过使用help命令查看运行规则。

robot/plugins中创建zadig/zadig.go文件,用来注册 zadig 执行流水线指令,内容如下:

package zadig
import (
 "fmt"
 "regexp"
 "strings"
 "github.com/sirupsen/logrus"
 "devops-chatops/rboot"
 "devops-chatops/zadig"
)
var zadigInfo = map[string]map[string]string{
 "dev": {
  "branch":      "dev",
  "workflow":    "devops-dev",
  "serviceType": "helm",
  "env":         "dev",
 },
 "test": {
  "branch":      "test",
  "workflow":    "devops-qa",
  "serviceType": "helm",
  "env":         "qa",
 },
 "uat": {
  "branch":      "uat",
  "workflow":    "devops-uat",
  "serviceType": "helm",
  "env":         "uat",
 },
 "prod": {
  "branch":      "master",
  "workflow":    "devops-prod",
  "serviceType": "helm",
  "env":         "prod",
 },
 "yamldev": {
  "branch":      "master",
  "workflow":    "chatops-dev",
  "serviceType": "k8s",
  "env":         "dev",
 },
}
func init() {
 // 注册脚本
 rboot.RegisterPlugin(`pipeline`, rboot.Plugin{
  // 脚本处理函数
  Action: func(bot *rboot.Robot, incoming *rboot.Message) []*rboot.Message {
   // 去除空格
   content := strings.Replace(incoming.Content, " ", "", -1)
   res := createWorkflowTask(content)
   return rboot.NewMessages(res)
  },
  Ruleset: map[string]string{`pipeline`: `执行[\w ]+环境[\w- ]+流水线`}, // 脚本规则集
  Usage: map[string]string{
   "pipeline": "执行dev环境devops-chatops流水线",
  },
  Description: `example '执行dev环境devops-chatops流水线'`,
 })
}
func createWorkflowTask(content string) string {
 res := regexp.MustCompile(`[\w-/]+流水线`)
 s := res.FindStringSubmatch(content)
 sp := strings.Split(s[0], "流水线")
 pipelineName := sp[0]
 br := regexp.MustCompile(`[\w]+环境`)
 tb := br.FindStringSubmatch(content)
 env := strings.Split(tb[0], "环境")[0]
 workflow := zadigInfo[env]["workflow"]
 repoName := pipelineName
 branch := zadigInfo[env]["branch"]
 envName := zadigInfo[env]["env"]
 serviceName := pipelineName
 serviceType := zadigInfo[env]["serviceType"]
 logrus.Debugf("工作流:%v 流水线: %v 环境: %v 服务:%v 服务类型:%v 分支:%v\n",
  workflow,
  pipelineName,
  envName,
  serviceName,
  serviceType,
  branch,
 )
 zd := zadig.Setup()
 err := zd.CreateWorkflowTask(workflow, envName, serviceName, serviceType, repoName, branch)
 if err != nil {
  return fmt.Sprintf("执行%s环境的流水线%s失败", env, pipelineName)
 }
 return fmt.Sprintf("执行%s环境的流水线%s成功", env, pipelineName)
}

其中:

  • init 方法就是插件注册的实现
  • Action 脚本的处理函数
  • Ruleset 是指令规则
  • Usage 使用方式
  • Description 描述信息
  • createWorkflowTask 执行工作流方法,主要用来获取指令的关键词,然后调用 zadig.CreateWorkflowTask 执行工作流
  • zadigInfo 用来定义 zadig 的环境信息
  • workflow 是工作流名称
  • branch 是分支名
  • serviceType 是服务类型,有 k8s 和 helm 服务
  • env 部署环境信息

上面的匹配规则、环境信息等比较简单粗暴,最好是把这些数据存到数据库里,我这里为了不引入额外的组件就直接放代码中了。

业务代码开发完,我们需要把 zadig 插件引入,在 robot/plugins/plugins.go 中 import 即可,如下:

package plugins
import (
 _ "github.com/ghaoo/rboot/robot/plugins/hello"
 _ "github.com/ghaoo/rboot/robot/plugins/ping"
 _ "github.com/ghaoo/rboot/robot/plugins/vote"
    _ "devops-chatops/robot/plugins/zadig"
)

至此,执行流水线业务开发完成。


部署 ChatOps


开发完成就要部署,部署要分几个阶段:

  • 创建聊天机器人
  • 部署应用

创建聊天机器人

该聊天机器人不是钉钉的普通自定义机器人,而是需要在钉钉开发者后台【4】创建机器人,具体操作见文档【5】,这里不再赘述。

创建到内部机器人过后,就会在钉钉上生成一个测试群并创建了一个机器人,如下:


640.png


该机器人和普通机器人的不同之处在于多了一个 POST 地址,该地址是我们创建机器人的时候配置的,也是应用的访问地址。

随着机器人的不断开发,关键词会越来越多,所以我这里选择的是加签校验。

部署应用

(1)修改配置文件,为了简单,我直接将配置文件放到代码仓库,推到镜像中。在代码根目录下创建.env 文件,内容如下:

# 机器人名称
ROBOT_NAME=DEVOPS-CHATOPS
# 聊天转接器名称
ROBOT_ADAPTER="dingtalk"
# 缓存器名称
ROBOT_BRAIN=bolt
# 消息秘钥
ROBOT_SECRET=
# 是否开启DEBUG
DEBUG=false
# 缓存位置
DATA_PATH=.data
# bolt数据保存地址
BOLT_DB_FILE=db/rboot.db
# web 服务监听端口
WEB_SERVER_PORT=9000
# 是否启用TSL
WEB_SERVER_TLS=false
# CA证书位置
WEB_SERVER_CERT=
# CA秘钥位置
WEB_SERVER_CERT_KEY=
# 钉钉机器人秘钥
DING_ROBOT_SECRET="xxxx"
# 钉钉webhook机器人access_token
DING_ROBOT_HOOK_ACCESS_TOKEN="xxxx"
# 钉钉webhook机器人秘钥
DING_ROBOT_HOOK_SECRET="xxxx"

配置转接器名称以及钉钉机器人相关信息。

(2)添加 Dockerfile,用于制作应用镜像,如下:

FROM golang:1.19.1 AS build-env
ENV GOPROXY https://goproxy.cn
ADD . /go/src/app
WORKDIR /go/src/app
RUN go mod tidy
RUN GOOS=linux GOARCH=386 go build  -v -o /go/src/app/app-server
FROM alpine
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
    apk add -U tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime
COPY --from=build-env /go/src/app/app-server /app/app-server
COPY --from=build-env /go/src/app/.env /app/.env
WORKDIR /app
EXPOSE 9000
CMD [ "./app-server" ]

(3)添加应用 K8S YAML 配置清单,主要有 deployment、service、ingress 资源,如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: devops-chatops
  name: devops-chatops
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/instance: devops-chatops
      app.kubernetes.io/name: devops-chatops
  template:
    metadata:
      labels:
        app.kubernetes.io/instance: devops-chatops
        app.kubernetes.io/name: devops-chatops
    spec:
      containers:
        - image: registry.cn-hangzhou.aliyuncs.com/coolops/devops-chatops:1c5e4c9274959c8efcecfb286103b052abb44d27
          imagePullPolicy: IfNotPresent
          name: devops-chatops
          ports:
            - containerPort: 9000
              name: http
              protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/instance: devops-chatops
    app.kubernetes.io/name: devops-chatops
  name: devops-chatops
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: http
  selector:
    app.kubernetes.io/instance: devops-chatops
    app.kubernetes.io/name: devops-chatops
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: devops-chatops
spec:
  rules:
    - host: chatops.jokerbai.com
      http:
        paths:
          - backend:
              serviceName: devops-chatops
              servicePort: 80
            path: /

(4)在 Zadig 上部署应用 由于我们这里使用的 YAML 类应用,所以先在 Zadig 上创建一个 YAML 类项目,如下:


640.png


然后在项目中创建添加服务,我们选择从代码仓库中同步,如下:


640.png


接下来我们需要给该应用增加构建操作,配置如下:


640.png


接着我们把服务添加到环境即可。

现在就可以执行工作流发布任务了,如下:


640.png


测试机器人

现在我们可以在群里进行测试了,先测试简单的help,看能不能输出我们想要的帮助信息,如下:


640.png


我们发现可以得到我们想要的信息。

接下来测试发布 Zadig 流水线,如下:


640.png


可以看到给我们反馈的是流水线创建成功,那到底有没有成功呢?

我们到 Zadig WEB 端查看如下:


640.png


我们可以看到有一个由 openAPI 触发的流水线正在运行,这表示流水线已经触发成功。

为了得到工作流执行的最终结果,我们可以在 Zadig 上为工作流添加 IM 通知,同样可以使用该机器人,这样就形成闭环了。


最后


到此,我们把 Zadig 和 ChatOps(聊天机器人)结合就算完成了,当然,这种机器人需要我们根据规则来玩,如果你输的指令和规则不匹配,就没法进行下一步了。

在整个过程中,还是发现一些问题:

  • 使用 openAPI 触发 Helm 项目目前存在问题,无法正常获取到服务,导致流水线无法进行
  • 使用 openAPI 触发的工作流不会进行 IM 通知

聊天机器人,可以接入很多能力,如果某种操作比较频繁且无趣,可以考虑做成各种自动化,chatops 就是其中的选择之一。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
3月前
|
JavaScript 前端开发 开发者
震撼揭秘!JS模块化进化史:从混沌到秩序,一场代码世界的华丽蜕变,你怎能错过这场编程盛宴?
【8月更文挑战第23天】在 Web 前端开发领域,JavaScript 模块化已成为处理日益复杂的 Web 应用程序的关键技术。通过将代码分解成独立且可重用的模块,开发者能够更有效地组织和管理代码,避免命名冲突和依赖混乱。从最早的全局函数模式到 IIFE,再到 CommonJS 和 AMD,最终进化到了 ES6 的原生模块支持以及 UMD 的跨环境兼容性。本文通过具体示例介绍了这些模块化规范的发展历程及其在实际开发中的应用。
45 0
|
6月前
|
Web App开发 人工智能 前端开发
视野修炼-技术周刊第65期 | 兴趣是一种天赋
🔥强烈推荐 1. 和尤大聊项目进展、开源社区协作和前端思考 围绕近期 Vue.js / Vite的技术变化、开源社区维护、前端未来发展的思考展开。也聊了一些轻松话题,比如:怎么看他被称呼尤大,祖师爷这个绰号?github 上yyx990803 神秘的数字是什么意思?Vue4 啥规划?未来是否有计划退休?写 Vue 用不用 Copilot?发际线如何保养等非技术话题。 这是音频内容,推荐对 Vue&Vite&尤大 感兴趣的同学听一下,干货挺多 尤大 Github(yyx990803) 账号这串数字是初中学号😄 很喜欢尤大最后说的一句话 ”兴趣是一种天赋“
|
人工智能 算法 机器人
《流浪地球2》中的硬核科技会在未来50年实现的会是哪些?
《流浪地球2》里面的黑科技和科幻理念比较超前,堪比欧美科幻大片,这也正是《流浪地球2》能这么受欢迎的原因。之前有人说,科幻片的魅力在于它不存在我们的生活之中,却能够帮助我们完成一个又一个远大的理想。但是近期热映电影《流浪地球2》中层出不穷的硬核科技,不仅令人大呼过瘾,而且大家高呼“希望成为现实”。
349 1
《流浪地球2》中的硬核科技会在未来50年实现的会是哪些?
|
达摩院
达摩严选|鄢志杰: 从波音 747 的诞生, 感受到充满创造力的中国
不管在哪种商业环境和时代背景之下,“无中生有”的故事有天然的魅力,其中有着太 多的博弈与创造。
317 0
|
容灾 分布式数据库 数据库
星光不问赶路人,感恩有你 1 路同行!
OceanBase 取得了哪些小成绩?快来跟我一起解锁吧
星光不问赶路人,感恩有你 1 路同行!
|
弹性计算 云计算
当九年义务教育的精英,遇上十年寒窗苦读的翘楚,必将擦出耀眼的火花!
这一组古今搭档,因为语言差异,总是能逗的人捧腹大笑,这不,美好的一天又开始了~
当九年义务教育的精英,遇上十年寒窗苦读的翘楚,必将擦出耀眼的火花!
|
人工智能 物联网 程序员
怡水科技:艺术生也不惧的上云路
艺术生也不惧的上云路
2336 0