长期以来,一些本地项目发版不是特别友好,需要在IDE里面打war包,然后远程客户电脑传的客户远程机上,远程机和服务器往往不是同一台机器,还需要多一步传输。所以有了下面的软件结构
jenkins+自建/公共mqtt服务器+文叔叔命令行工具+客户机监听消息执行shell
适用于公司和客户都有公网环境的情况。
本文系统使用Rocky Linux 8,命令同样适用于Centos 7/8
推荐配置 4核/4G内存/50G硬盘
对于Rocky Linux 8有4中安装方式,rpm在线离线安装、docker安装、jar包安装、war包安装,这里使用最通用的war包安装
war包安装先要安装jdk tomcat,具体可以参见Centos 7 安装tomcat并设置开机自启_gsls200808的专栏-CSDN博客
war包从Jenkins download and deployment这个网址下载最新的LTS版本即可
war包下载后放到tomcat的webapp目录,这样出来的路径带/jenkins,如果不想带,解压后放到ROOT目录下也可以
我这里的访问网址是
http://10.24.220.102:8080/jenkins/
初次安装可能会提示
Please wait while Jenkins is getting ready to work
等几分钟即可,等几分钟后如果还没有出现初始化界面就需要改配置了。
初始界面需要填入初始密码,使用cat命令可以查看。
cat /root/.jenkins/secrets/initialAdminPassword
2c259dcd73784792a256cb5c0198f971
之后安装插件的界面点击安装推荐的插件接口
管理员界面设置一个管理员账号。
这样jenkins基本就安装完成了。
jdk之前安jenkins安过了,这里不赘述
git安装
yum install git
git安装验证
git --version
maven安装
wget https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gz
cp apache-maven-3.5.4-bin.tar.gz /usr/local/
cd /usr/local/
tar -zxvf apache-maven-3.5.4-bin.tar.gz
rm apache-maven-3.5.4-bin.tar.gz
mv apache-maven-3.5.4 maven
maven环境变量配置
#编辑 /etc/profile 文件
vi /etc/profile
#末尾增加如下内容
# set maven environment
export M2_HOME=/usr/local/maven
export PATH=$M2_HOME/bin:$PATH
#使环境变量生效
source /etc/profile
maven安装验证
mvn -v
jenkins里的配置
Manage Jenkins-->Global Tool Configuration
点击jdk安装/新增jdk填入如下内容
点击maven安装/新增maven,填入如下内容
点击git安装/新增git,填入如下内容
我这里的git默认识别了就不用填git的了,最后点击下方的保存
需要注意的是,已经配置过的项目重新进入这个页面之后不会默认显示,需要点击安装jdk/maven/git按钮才会显示已经配置的信息
安装插件
Manage Jenkins-->Manage Plugins
在可选插件钟搜索GitLab,找到GitLab和Gitlab API Plugin,勾选这两项,然后点击Install without restart
gitlab获取api token配置
登录gitlab-->右上角-->setting-->Access Tokens
name填jenkins,socpe勾选api,然后点击Create personal access token 按钮
点击后生成的token字符串显示在上面,复制下来保存,这个token在这个界面只显示一次。
jenkins里配置token
登录jenkins-->Manage Jenkins-->Configure System
配置里面的Gitlab选项,勾选Enable authentication for '/project' end-point,name填jenkins,gitlab地址填你的gitlab地址,Credentials添加刚才在gitlab里获取的token
在弹出的添加凭据页面,类型选择 Gitlab AP token,API token填你从gitlab复制来的token。
添加凭据后在主页面点test connection,保存。
Manage Jenkins-->Manage Plugins
搜索Git Parameter安装
以git项目打包为例说明使用
新建item
任务名称 任意,类型选Freestyle project
填写内容分6块,分别是 General 、源码管理、构建触发器、构建环境、构建、构建后操作
General内容
1.勾选Discard old builds
设置 策略Loq Rotation
保持构建的天数=1
保持构建的最大个数=5
2.GitLab Connection
选择 jenkins
3.勾选This project is parameterized
添加参数 Git Parameter(这里用到的就是刚才的 Git Parameter插件)
名称 填 branch
参数类型 选择 分支
4.JDK(只有一个JDK时可能没有这个选项)
选择JDK1.8
源码管理内容
1.选择Git
Repositories
Repository URL 填git地址如http://git.aaa.com/bbb_projects/ccc.git
Credentials
这里添加 你的git账号 可以用gitlab的用户名密码,也可以用之前的全局配置的apitoken
Branches to build
指定分支(为空时代表any) 填 $branch
其他选项 默认
构建触发器
不填 这里可以配置一些比如push代码后自动构建的操作等
构建
增加构建步骤-Invoke top-level Maven targets
Maven 版本 选择 Maven3.5
目标 填 clean package -Pprod -U -Dmaven.test.skip (具体含义查看maven相关命令)
构建后操作
增加构建后操作步骤--E-mail Notification (这里一般用来做构建后的邮件通知 需要安装postfix)
Recipients 填邮箱 多个邮箱用空格分隔
勾选 每次不稳定的构建都发送邮件通知
关键命令
clean package -Pdev -U -Dmaven.test.skip
这个命令上一步已经出现了,用来打包的 -P可以指定参数,-Dmaven.test.skip用来跳过test类编译
下载地址:GitHub - Mikubill/transfer: 集合多个API的大文件传输工具.
安装命令
#下载,解压到/usr/local/transfer目录
wget https://github.com/Mikubill/transfer/releases/download/v0.4.14/transfer_0.4.14_linux_amd64.tar.gz
mkdir -p /usr/local/transfer
tar -zxvf transfer_0.4.14_linux_amd64.tar.gz -C /usr/local/transfer
#编辑配置环境变量
vi /etc/profile
#末尾添加如下内容
# set transfer env
export TRANSFER_HOME=/usr/local/transfer
export PATH=$TRANSFER_HOME:$PATH
#使环境变量生效
source /etc/profile
验证安装
transfer --version
安装命令
yum install epel-release
yum install mosquitto
完整命令如下
cd ./saas-wis-basic/target
/usr/local/transfer/transfer wss basic.war >wenshushu.txt
linklineNumber=$(sed -n '/Download\ Link/=' wenshushu.txt)
echo $linklineNumber
linklinestr=$(sed -n "${linklineNumber}p" wenshushu.txt)
echo $linklinestr
str=${linklinestr#*Link: }
mosquitto_pub -h mq.tongxinmao.com -t topic/sunwardpord -m "{\"module\":\"saas-wis-basic\",\"link\":\"${str}\"}"
近期发现transfer这个工具下载文叔叔的链接报错,建议上传命令换成奶牛快传
/usr/local/transfer/transfer cow basic.war >wenshushu.txt
transfer这个工具是用go写的,有时间我再看下源码改改给原作提个pr
shell命令如下
#删除下的第一行
sed -i '//{n;d}' pom.xml
#在 下添加 saas-wis-production
sed -i '//a\ saas-wis-production<\/module>\n' pom.xml
用go+go调用shell脚本实现。
完整代码在:gsls200808/jenkins-mqttt-client
实现如下
// test
package main
import (
"fmt"
"os"
"os/signal"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
//读取发布配置,备份war包,替换war包,重启tomcat或者docker
}
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() {
//合建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 = "mq.tongxinmao.com"
var port = 1883
opts := mqtt.NewClientOptions()
opts.AddBroker(fmt.Sprintf("tcp://%s:%d", broker, port))
opts.SetClientID("go_mqtt_client")
opts.SetUsername("emqx")
opts.SetPassword("public")
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 := "topic/sunwardpord"
token := client.Subscribe(topic, 1, nil)
token.Wait()
fmt.Printf("Subscribed to topic: %s\n", topic)
}
定义moudule名、war包目录、替换war前后执行的脚本,这个json放到go文件的同级目录。
jenkinsmqtt.json
[{
"module": "saas-wis-basic",
"warpath": "/data/webrv/tomcat/basic/webapps",
"warname": "basic.war",
"backpath": "/data/webrv/backwar",
"stop": "docker stop wis-basic",
"start": "docker start wis-basic",
"restart": "docker restart wis-basic",
"transfer": "/usr/local/transfer/transfer"
}]
定义读取文件,执行shell,解析json的几个方法
// 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)
fmt.Println(js)
var each_map = make(map[string]interface{})
each_map, _ = js.Map()
module := each_map["module"].(string)
link := each_map["link"].(string)
return module, link
}
//根据模块名和模块匹配本地json模块发布
func issueModuleLocalJson(imodule 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{})
module := each_map["module"].(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)
// restart := each_map["restart"].(string)
if module == imodule {
fmt.Println("找到对应模块")
exec_shell("cd " + backpath)
pwd, _ := os.Getwd()
fmt.Println("当前目录" + pwd)
exec_shell(transfer + " " + link)
exec_shell(stop)
exec_shell("cp -r" + " " + warname + " " + warpath)
exec_shell(start)
} else {
break
}
}
}
//阻塞式的执行外部shell命令的函数,等待执行完毕并返回标准输出
func exec_shell(s string) (string, error) {
//函数返回一个*Cmd,用于使用给出的参数执行name指定的程序
cmd := exec.Command("/bin/bash", "-c", s)
//读取io.Writer类型的cmd.Stdout,再通过bytes.Buffer(缓冲byte类型的缓冲器)将byte类型转化为string类型(out.String():这是bytes类型提供的接口)
var out bytes.Buffer
cmd.Stdout = &out
//Run执行c包含的命令,并阻塞直到完成。 这里stdout被取出,cmd.Wait()无法正确获取stdin,stdout,stderr,则阻塞在那了
err := cmd.Run()
checkErr(err)
return out.String(), err
}
//错误处理函数
func checkErr(err error) {
if err != nil {
fmt.Println(err)
panic(err)
}
}
接收消息的方法添加如下调用
//读取发布配置,备份war包,替换war包,重启tomcat或者docker
issuejson := string(msg.Payload())
fmt.Println(issuejson)
//读本地配置 war包路径 存储命令等
pwd, _ := os.Getwd()
localjson := readFile(pwd + "/" + "jenkinsmqtt.json")
fmt.Println(localjson)
//发布模块解析
module, link := readIssueModule(issuejson)
fmt.Println(module)
fmt.Println(link)
//模块发布
issueModuleLocalJson(module, link, localjson)
通常情况下,我们一般是windows开发,linux部署,所以有必要把go工程编译成linux下的可执行文件
安装TDM-GCC
下载地址:tdm-gcc
安装后进windows的cmd,进入go文件所在目录,输入以下命令
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build main.go
编译后的linux的可执行文件没有后缀,复制到linux改下权限就能使用。