云效+mqtt实现本地构建和远程自动发版

news2024/11/24 12:16:10

之前写过一篇jenkins+mqtt实现本地构建和远程自动发版_jenkins远程调用和本地调用-CSDN博客

由于本地搭建jenkins实在太费机器了,这次改用云效搭建。不过云效并没有直接发送mqtt的方法,需要编写中转接口。

中转接口采用go-gin框架实现,代码如下

main.go

package main

import (
	"encoding/json"
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"github.com/gin-gonic/gin"
	"os"
	"time"
)

func main() {

	router := gin.Default()
	router.POST("/publish/notify", func(c *gin.Context) {
		obj := struct {
			App  string `json:"app"`
			Link string `json:"link"`
		}{}

		err := c.BindJSON(&obj)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(obj)
		}
		//把读取到的json透传发送到mqtt服务器
		Publish(obj.App, obj.Link, "/publish/notify")

		c.JSON(200, gin.H{
			"msg": "this is a post msg",
		})
	})

	router.POST("/publish/notifyProd", func(c *gin.Context) {
		obj := struct {
			App  string `json:"app"`
			Link string `json:"link"`
		}{}

		err := c.BindJSON(&obj)
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(obj)
		}
		//把读取到的json透传发送到mqtt服务器
		Publish(obj.App, obj.Link, "/publish/notifyProd")

		c.JSON(200, gin.H{
			"msg": "this is a post msg",
		})
	})
	// 默认端口是8080,也可以指定端口 r.Run(":80")
	router.Run(":80")
}

func Publish(app string, link string, topic string) {
	broker := "tcp://broker.emqx.io:1883"
	clientId := "go-mqtt-client"

	opts := mqtt.NewClientOptions().AddBroker(broker).SetClientID(clientId)
	opts.SetUsername("") // 设置用户名
	opts.SetPassword("") // 设置密码
	opts.SetCleanSession(true)
	opts.SetKeepAlive(2 * time.Second)
	opts.SetDefaultPublishHandler(f)
	opts.OnConnect = func(c mqtt.Client) {
		fmt.Println("Connected")
	}
	opts.OnConnectionLost = func(c mqtt.Client, e error) {
		fmt.Println("Disconnected")
	}
	c := mqtt.NewClient(opts)
	if token := c.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}

	// 构建JSON消息
	message := map[string]string{
		"app":  app,
		"link": link,
	}
	jsonMessage, err := json.Marshal(message)
	if err != nil {
		fmt.Println("Error marshaling JSON:", err)
		os.Exit(1)
	}

	// 发布消息
	if token := c.Publish(topic, 0, false, jsonMessage); token.Wait() && token.Error() != nil {
		fmt.Println(token.Error())
		os.Exit(1)
	}

	// 等待一段时间以确保消息被发送
	time.Sleep(2 * time.Second)

	c.Disconnect(250)
}
func f(client mqtt.Client, msg mqtt.Message) {
	fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}

云效调用

在构建制品后选择执行命令

命令内容填写

# input your command here
# 构造 JSON 参数
json_data=$(jq -n --arg app "myapp" --arg link "${artifacts}" '{app: $app, link: $link}')

# 打印 JSON 参数(可选)
echo "$json_data"

# 发送 HTTP POST 请求
curl -X POST "http://transfer.example.com/publish/notify" \
     -H "Content-Type: application/json" \
     -d "$json_data"

将myapp替换成你想改的app名,transfer.example.com改成你部署在公网的中转接口域名或ip

上面用到了${artifacts}参数,需要在云效中添加artifacts=制品名称xxx

之后在部署的服务器上部署发布的客户端

客户端的逻辑跟上一篇文章类似,代码如下

main.go

package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"time"

	"github.com/bitly/go-simplejson"

	mqtt "github.com/eclipse/paho.mqtt.golang"
)

// 全局变量,存储程序启动时的当前工作目录
var baseDir string

var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
	go handleMessage(client, msg)
}

var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
	fmt.Println("Connected")
}

var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
	fmt.Printf("Connect lost: %v", err)
}

func main() {
	// 获取程序启动时的当前工作目录
	var err error
	baseDir, err = os.Getwd()
	if err != nil {
		log.Fatalf("获取当前工作目录失败: %v", err)
	}
	fmt.Println("程序启动时的当前工作目录:", baseDir)

	//合建chan
	c := make(chan os.Signal)
	//监听指定信号 ctrl+c kill
	signal.Notify(c, os.Interrupt, os.Kill)
	//阻塞直到有信号传入
	fmt.Println("启动")

	//执行具体方法
	initmqtt()

	//阻塞直至有信号传入
	s := <-c
	fmt.Println("退出信号", s)
}

func initmqtt() {
	var broker = "broker.emqx.io"
	var port = 1883
	opts := mqtt.NewClientOptions()
	opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
	opts.SetDefaultPublishHandler(messagePubHandler)
	opts.OnConnect = connectHandler
	opts.OnConnectionLost = connectLostHandler
	client := mqtt.NewClient(opts)
	if token := client.Connect(); token.Wait() && token.Error() != nil {
		panic(token.Error())
	}

	sub(client)
}

func sub(client mqtt.Client) {
	topic := "/publish/notify"
	token := client.Subscribe(topic, 1, nil)
	token.Wait()
	fmt.Printf("Subscribed to topic: %s\n", topic)
}

// readFile 使用ioutil.ReadFile 直接从文件读取到 []byte中
func readFile(fileName string) string {
	f, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Printf("读取文件失败:%#v", err)
		return ""
	}
	return string(f)
}

// 读取消息的发布模块名和链接
func readIssueModule(issuejson string) (string, string) {
	buf := bytes.NewBuffer([]byte(issuejson))
	js, _ := simplejson.NewFromReader(buf)
	var each_map = make(map[string]interface{})
	each_map, _ = js.Map()
	app := each_map["app"].(string)
	link := each_map["link"].(string)
	return app, link
}

// 根据模块名和模块匹配本地json模块发布
func issueModuleLocalJson(app string, link string, localjson string) {
	//读本地配置 war包路径 存储命令等
	fmt.Println(localjson)

	buf := bytes.NewBuffer([]byte(localjson))
	js, _ := simplejson.NewFromReader(buf)

	fmt.Println(js)
	//获取json字符串中的  数组
	rows, _ := js.Array()
	fmt.Println(rows)

	//遍历rows数组
	for _, row := range rows {
		each_map := row.(map[string]interface{})
		jsonapp := each_map["app"].(string)
		warpath := each_map["warpath"].(string)
		warname := each_map["warname"].(string)
		backpath := each_map["backpath"].(string)
		stop := each_map["stop"].(string)
		start := each_map["start"].(string)
		transfer := each_map["transfer"].(string)
		unzip := each_map["unzip"].(string)

		if jsonapp == app {
			fmt.Println("找到对应模块" + app)
			// 创建备份目录
			fmt.Println("创建备份目录" + backpath)
			exec_shell("mkdir -p " + backpath)

			// 获取当前时间并格式化
			timestamp := time.Now().Format("20060102150405")
			backupDir := fmt.Sprintf("%s/%s/%s", backpath, app, timestamp)

			// 创建备份子目录
			fmt.Println("创建备份子目录" + backupDir)
			err := os.MkdirAll(backupDir, 0755)
			if err != nil {
				fmt.Println("创建备份子目录失败:", err)
				continue
			}

			// 改变当前工作目录
			err = os.Chdir(backupDir)
			if err != nil {
				fmt.Println("改变目录失败:", err)
				continue
			}
			pwd, _ := os.Getwd()
			fmt.Println("当前目录" + pwd)

			if strings.Contains(link, "&") {
				link = "'" + link + "'"
			}
			fmt.Println("下载文件" + link)
			exec_shell(transfer + " " + link)
			fmt.Println("解压文件")
			exec_shell(unzip)
			fmt.Println("停止服务")
			exec_shell(stop)
			fmt.Println("拷贝文件到对应目录")
			exec_shell("cp -rf" + " " + warname + " " + warpath)
			fmt.Println("启动服务")
			exec_shell(start)
			fmt.Println("完成本次发布")
			break
		}
	}
}

// 阻塞式的执行外部shell命令的函数,等待执行完毕并返回标准输出
func exec_shell(s string) (string, error) {
	cmd := exec.Command("/bin/bash", "-c", s)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	checkErr(err)
	return out.String(), err
}

// 错误处理函数
func checkErr(err error) {
	if err != nil {
		fmt.Println(err)
		panic(err)
	}
}

// 处理MQTT消息的函数
func handleMessage(client mqtt.Client, msg mqtt.Message) {
	fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())

	//读取发布配置,备份war包,替换war包,重启tomcat或者docker
	issuejson := string(msg.Payload())
	fmt.Println(issuejson)

	//读本地配置 war包路径 存储命令等
	localjson := readFile(baseDir + "/" + "jenkinsmqtt.json")
	//关于json的配置说明
	/*app: 应用的名称。
	warpath: 应用的部署路径。
	warname: 应用的 WAR 文件名。
	backpath: 备份路径。
	stop: 停止应用的命令。
	start: 启动应用的命令。
	restart: 重启应用的命令。
	transfer: 下载应用包的命令。
	unzip: 解压应用包的命令。*/
	fmt.Println(localjson)

	//发布模块解析
	app, link := readIssueModule(issuejson)
	fmt.Println(app)
	fmt.Println(link)

	//模块发布
	issueModuleLocalJson(app, link, localjson)
}

jenkinsmqtt.json示例

[
	{
		"app": "myapp",
		"warpath": "/data/app/myapp/webapps",
		"warname": "myapp.war",
		"backpath": "/data/app/cibak",
		"stop": "docker stop myapp",
		"start": "docker start myapp",
		"restart": "docker restart myapp",
		"transfer": "wget -O myapp.tgz ",
		"unzip": "tar -zxvf myapp.tgz"
	}
]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2230574.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【蔬菜识别】Python+深度学习+CNN卷积神经网络算法+TensorFlow+人工智能+模型训练

一、介绍 蔬菜识别系统&#xff0c;本系统使用Python作为主要编程语言&#xff0c;通过收集了8种常见的蔬菜图像数据集&#xff08;‘土豆’, ‘大白菜’, ‘大葱’, ‘莲藕’, ‘菠菜’, ‘西红柿’, ‘韭菜’, ‘黄瓜’&#xff09;&#xff0c;然后基于TensorFlow搭建卷积神…

安装Blender并使用

前言 该系列记录了如何用Blenderpro来构建自己的场景数据集&#xff0c;从环境搭建到后期构建数据集的整个流程 本文章是第一部分&#xff0c;BlenderPrc2的安装以及环境配置 部分参考https://blog.csdn.net/weixin_49521551/article/details/121573334 官方文档https://dlr…

ApsaraMQ Serverless 能力再升级,事件驱动架构赋能 AI 应用

本文整理于 2024 年云栖大会阿里云智能集团高级技术专家金吉祥&#xff08;牟羽&#xff09;带来的主题演讲《ApsaraMQ Serverless 能力再升级&#xff0c;事件驱动架构赋能 AI 应用》 云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;支持按量付费、自适应弹性、跨可…

栈虚拟机和寄存器虚拟机,有什么不同?

本来这节内容是打算直接讲字节码指令的&#xff0c;但讲之前又必须得先讲指令集架构&#xff0c;而指令集架构又分为两种&#xff0c;一种是基于栈的&#xff0c;一种是基于寄存器的。 那不妨我们这节就单独来讲讲栈虚拟机和寄存器虚拟机&#xff0c;它们有什么不同&#xff0…

Rust整合Elasticsearch

Elasticsearch是什么 Lucene&#xff1a;Java实现的搜索引擎类库 易扩展高性能仅限Java开发不支持水平扩展 Elasticsearch&#xff1a;基于Lucene开发的分布式搜索和分析引擎 支持分布式、水平扩展提高RestfulAPI&#xff0c;可被任何语言调用 Elastic Stack是什么 ELK&a…

【Apache Zookeeper】

一、简介 1、场景 如何让⼀个应⽤中多个独⽴的程序协同⼯作是⼀件⾮常困难的事情。开发这样的应⽤&#xff0c;很容易让很多开发⼈员陷⼊如何使多个程序协同⼯作的逻辑中&#xff0c;最后导致没有时间更好地思考和实现他们⾃⼰的应⽤程序逻辑&#xff1b;又或者开发⼈员对协同…

手把手写Linux第一个小程序 - 进度条(5种版本)

本专栏内容为&#xff1a;Linux学习专栏&#xff0c;分为系统和网络两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握Linux。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;linux &#x1f69a;代码仓库&#xff1a;小小unicorn的代…

TikTok如何用邮箱注册?用哪种邮箱比较好?

要在TikTok上创建一个账号&#xff0c;首先需要进行注册&#xff0c;这是一个简单但至关重要的步骤。在本篇文章中&#xff0c;我们将详细介绍如何用邮箱注册TikTok的整个过程&#xff0c;包括每个步骤的细节和注意事项。此外&#xff0c;我们还将讨论选择哪种邮箱比较好&#…

LabVIEW在Windows和Linux开发的差异

LabVIEW广泛应用于工程和科研领域的自动化和测量控制系统开发&#xff0c;其在Windows和Linux平台上的开发环境有所不同。这些差异主要体现在操作系统兼容性、硬件支持、软件库和驱动程序、实时系统开发以及部署选择上。以下从各个方面详细对比分析LabVIEW在Windows与Linux系统…

哪个牌子的宠物空气净化器好?口碑好的宠物空气净化器推荐!

哪个牌子的宠物空气净化器好&#xff1f;作为一名家电测评博主&#xff0c;我发现市面上宠物空气净化器的牌子越来越多了&#xff0c;很多厂家都看中了宠物行业的红利&#xff0c;想来分一杯羹&#xff0c;这就导致很多技术不成熟的产品流入了市场。今年我测试了50多台宠物空气…

ios 快捷指令扩展(Intents Extension)简单使用 swift语言

本文介绍使用Xcode15 建立快捷指令的Extension&#xff0c;并描述如何修改快捷指令的IntentHandler&#xff0c;带参数跳转主应用&#xff1b;以及展示多个选项的快捷指令弹框(配置intentdefinition文件)&#xff0c;点击选项带参数跳到主应用的方法 创建快捷指令 快捷指令是…

计算机的错误计算(一百四十一)

摘要 探讨 MATLAB中正弦、余弦的计算精度问题。当自变量为大数时&#xff0c;输出可能出错。 从 IEEE-754-2019 知&#xff0c;三角函数的定义域是实数域。 例1. 计算 直接贴图吧&#xff1a; 这样&#xff0c;MATLAB的输出均为错误结果&#xff0c;即没有正确有效数字。…

医院绩效考核管理系统源码,医院如何构建绩效考核体系?

医院绩效考核管理系统作为现代医院管理的重要组成部分&#xff0c;其核心功能旨在提高医院运营效率、优化资源配置、确保医疗服务质量&#xff0c;以及增强医院竞争力。 业务科室绩效考核体系的构建 临床医疗与医技科室绩效考核的设置 临床医疗的绩效考核采用百分制&#xff…

「C/C++」C/C++标准库之#include<cstdlib>通用工具库

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

Resnet代码实现

图2 18-layer、34-layer的残差结构 图3 50-layer、101-layer、102-layer的残差结构 import torch import torch.nn as nn#这个18或者34层网络的残差模块&#xff0c;根据ResNet的具体实现可以自动匹配 class BasicBlock(nn.Module):conv1 stride1对应的实线残差&#xff0c;因…

为什么大家都在学数字孪生呢?

随着物联网&#xff0c;大数据、人工智能等技术的发展&#xff0c;新一代信息技术与制造业正在深度融合&#xff0c;人们与物理世界的交互方式正在发生转折性的变化。数字化转型正在成为企业的重要战略&#xff0c;而数字孪生则成为全新的焦点。 当下&#xff0c;在数字技术和…

IDEA使用Maven Helper查看整个项目的jar冲突

在插件市场安装Maven Helper&#xff0c;安装好后&#xff0c;重启IDEA&#xff1b;双击打开可能存在jar冲突的pom文件&#xff1b;在右侧面板查看冲突,text是引入的依赖明细&#xff0c;点击Dependecy Analyzer选项卡即可查看冲突的jar。

「Pytorch」如何理解深度学习中的算子(operator)

在深度学习中&#xff0c;“算子”&#xff08;operator&#xff09;通常指的是在神经网络中进行的各种数学运算或函数。这些算子可以是基本的数学操作&#xff0c;如加法、乘法、卷积&#xff0c;也可以是更复杂的变换&#xff0c;如激活函数和池化操作。 主要类型的算子 线性…

Hbuilder html5+沉浸式状态栏

manifest.json源码视图添加 {"statusbar": {"immersed": true }如图&#xff1a; 2、plusready准备&#xff0c;将状态栏字体变黑&#xff0c;不然背景白色、状态栏白色看不到 //2.1 如果你用了mui&#xff0c; mui.plusReady(function(){plus.navigat…

windows/linux注册服务与阿里镜像仓库使用

这里写目录标题 启动Windows将jar注册服务Linux将jar设置开机启动 外网环境编译打包 启动 Windows将jar注册服务 将jar包导入到服务器上&#xff0c;将WinSW工具也放到服务器上。 winSw下载地址&#xff1a;https://github.com/winsw/winsw/releases 依据下图修改xml内容即可…