共计 6977 个字符,预计需要花费 18 分钟才能阅读完成。
之前也写过 jenkins 微服务打包的教程,可以打包单个模块,但是如果需要一次性打包全部就实现不了了,这次优化了一下脚本。
如果有不了解的,可以先看看这两篇文章 Jenkins 打包微服务教程-一个配置文件即可打包所有模块,Jenkins 打包微服务流程优化。
不过这次需要用到 Extended Choice Parameter
插件,因为需要在构建时传参,但是 jenkins 默认不支持传多选,需要通过这个插件。
插件的使用也比较简单,在添加参数时选择 Extended Choice Parameter。
然后按如下图填写即可。
接下来就可以按住 ctrl
键配合鼠标进行多选了,也可以按住 shift
选择一个区间。
接下来就是配置源码地址,maven 的打包可以不需要,如果实在需要可以设置命令为 mvn dependency:tree
,因为接下来会在脚本进行打包。
脚本如下,注意这里需要配置三个参数,分别是 all_module-候选打包模块,all_host-候选打包主机,branch-git分支,这个分支变量需要配置为 git 变量,其他两个使用上面的插件配置。
#!/bin/bash
# 0. 准备 1. 指定打包mvn路径 2. 获取打包的所有模块 3. 获取打包的所有主机
maven_command="/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven3.6/apache-maven-3.6.1/bin/mvn"
IFS=',' read -ra modules <<< "$all_module"
IFS=',' read -ra hosts <<< "$all_host"
echo "===============本次选择打包的模块 "$all_module"==============="
# 1. 打包
skip_tests="-Dmaven.test.skip=true"
for module in "${modules[@]}"
do
echo "===============模块 "$module" 执行 mvn install==============="
$maven_command clean install -pl ${module} -am $skip_tests
done
# 2. 构建镜像并保存
for module in "${modules[@]}"
do
## 构建镜像
cd "${WORKSPACE}/${module}"
serviceName="${module#*/}"
current=$(date -d "8 hours" +"%Y%m%d-%H%M")
branch_name=$(echo "${branch}" | sed 's/\//-/g')
#imageName="${serviceName}-${branch_name}:${current}"
imageName="${serviceName}:${branch_name}-${current}"
tarName="${serviceName}-${current}.tar"
jarFile=$(ls target/ | grep \.jar$)
mv "target/${jarFile}" .
docker build --build-arg JAR_FILE="${jarFile}" -t "${imageName}" .
## 保存镜像-保存在 jenkins 主目录下的 images 文件夹
imagesDir="${JENKINS_HOME}/images/$JOB_NAME/${serviceName}"
mkdir -p "${imagesDir}"
docker save -o "${imagesDir}/${tarName}" "${imageName}"
cp "${imagesDir}/${tarName}" target/
## 清理镜像
docker rmi -f $(docker images | grep "${serviceName}" | awk 'NR>0 {print $3}')
## tar包保留指定数量
cd "${imagesDir}"
retainNumber=3
rm -f $(ls -t | awk "NR>${retainNumber}")
done
# 3. 部署
# 准备工作 -> 1. 定义主机 2.获取工作目录 3. 连接新主机不询问是否添加到known_hosts
cd ${WORKSPACE}
cat > hosts.txt <<EOF
172.26.1.21 root xxx dev_test "-e ACTIVE=pro -e NACOS_URL=172.26.1.21"
EOF
grep -q 'StrictHostKeyChecking no' /etc/ssh/ssh_config || echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config
#==========定义远程执行脚本文件开始==========
cd ${WORKSPACE}
cat << 'EOF' > script.sh
#!/bin/bash
cd /tmp/robot-patrol-platform
tarName=$(ls *.tar -1t | head -n 1)
imageName=$(docker load -i ${tarName} | cut -d' ' -f3)
containerName=$(echo ${imageName} | cut -d: -f1)
# 删除原来的容器,并新建一个容器
if docker ps -a| grep "${containerName}" >/dev/null 2>&1; then docker rm -f ${containerName} ; fi
docker run -d --net host $1 --restart=unless-stopped --name ${containerName} ${imageName}
# 删除无用的镜像,只保留最新的镜像
serviceName=${containerName}
if docker images | grep "${serviceName}" >/dev/null 2>&1; then docker rmi -f $(docker images | grep ${serviceName} |awk 'NR>1 {print $3}'); fi
# 删除临时文件夹
rm -rf /tmp/robot-patrol-platform/${tarName}
rm -rf /tmp/robot-patrol-platform/script.sh
echo "The script has been executed successfully."
EOF
#==========定义远程执行脚本文件结束==========
#==========定义任务函数开始==========
dotask () {
echo "===============远程主机 "$ip" 开始执行任务==============="
for module in "${modules[@]}"
do
echo "===============远程主机 "$ip" 正在部署 "$module" ==============="
ip=$1; username=$2; password=$3; environment=$4; param=$5
sshpass -p $password ssh $username@$ip "mkdir -p /tmp/robot-patrol-platform"
sshpass -p $password scp ${WORKSPACE}/${module}/target/*.tar $username@$ip:/tmp/robot-patrol-platform
sshpass -p $password scp ${WORKSPACE}/script.sh $username@$ip:/tmp/robot-patrol-platform
sshpass -p $password ssh $username@$ip "chmod +x /tmp/robot-patrol-platform/script.sh && /tmp/robot-patrol-platform/script.sh $param"
done
echo "===============远程主机 "$ip" 脚本执行完成==============="
}
#==========定义任务函数结束==========
while read -r ip username password environment param; do
for host in "${hosts[@]}"; do
if [ "$host" = "$environment" ] || [ "$host" = "$ip" ]; then
dotask "$ip" "$username" "$password" "$environment" "$param"
fi
done
done < hosts.txt
echo "===============所有任务已完成==============="
当然,这样的方式有个弊端,就是 idea 插件并不支持多选参数,
还有一种方式,需要配置 single_module、host 都为单选,并且提供 all 这个选项,意思是打包全部模块或发送到全部主机。然后配置一个 all_module 字符变量,这个变量是模块以逗号分隔,另外一个就是分支变量了。
脚本如下:
#!/bin/bash
modules=${single_module}
# 如果选择该项目,则全部进行打包
maven_command="/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven3.6/apache-maven-3.6.1/bin/mvn"
skip_tests="-Dmaven.test.skip=true"
if [ ${single_module} == "all" ]; then
IFS=',' read -ra modules <<< "$all_module"
echo "===============全部模块执行 mvn install==============="
$maven_command clean install $skip_tests
else
echo "===============${single_module}模块执行 mvn install==============="
$maven_command clean install -pl ${single_module} -am $skip_tests
fi
for module in "${modules[@]}"
do
echo $module
## 构建镜像
cd "${WORKSPACE}/${module}"
serviceName="${module#*/}"
current=$(date -d "8 hours" +"%Y%m%d-%H%M")
branch_name=$(echo "${branch}" | sed 's/\//-/g')
#imageName="${serviceName}-${branch_name}:${current}"
imageName="${serviceName}:${branch_name}-${current}"
tarName="${serviceName}-${current}.tar"
jarFile=$(ls target/ | grep \.jar$)
mv "target/${jarFile}" .
docker build --build-arg JAR_FILE="${jarFile}" -t "${imageName}" .
## 保存镜像-保存在 jenkins 主目录下的 images 文件夹
imagesDir="${JENKINS_HOME}/images/$JOB_NAME/${serviceName}"
mkdir -p "${imagesDir}"
docker save -o "${imagesDir}/${tarName}" "${imageName}"
cp "${imagesDir}/${tarName}" target/
## 清理镜像
docker rmi -f $(docker images | grep "${serviceName}" | awk 'NR>0 {print $3}')
## tar包保留指定数量
cd "${imagesDir}"
retainNumber=3
rm -f $(ls -t | awk "NR>${retainNumber}")
done
# 准备工作 -> 1. 定义主机 2.获取工作目录 3. 连接新主机不询问是否添加到known_hosts
cd ${WORKSPACE}
cat > hosts.txt <<EOF
172.26.1.21 root xxx dev_test "-e ACTIVE=pro -e NACOS_URL=172.26.1.21"
EOF
grep -q 'StrictHostKeyChecking no' /etc/ssh/ssh_config || echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config
#==========定义远程执行脚本文件开始==========
cd ${WORKSPACE}
cat << 'EOF' > script.sh
#!/bin/bash
cd /tmp/robot-patrol-platform
tarName=$(ls *.tar -1t | head -n 1)
imageName=$(docker load -i ${tarName} | cut -d' ' -f3)
containerName=$(echo ${imageName} | cut -d: -f1)
# 删除原来的容器,并新建一个容器
if docker ps -a| grep "${containerName}" >/dev/null 2>&1; then docker rm -f ${containerName} ; fi
docker run -d --net host $1 --restart=unless-stopped --name ${containerName} ${imageName}
# 删除无用的镜像,只保留最新的镜像
serviceName=${containerName}
if docker images | grep "${serviceName}" >/dev/null 2>&1; then docker rmi -f $(docker images | grep ${serviceName} |awk 'NR>1 {print $3}'); fi
# 删除临时文件夹
rm -rf /tmp/robot-patrol-platform/${tarName}
rm -rf /tmp/robot-patrol-platform/script.sh
echo "The script has been executed successfully."
EOF
#==========定义远程执行脚本文件结束==========
#==========定义任务函数开始==========
dotask () {
echo "===============远程主机 "$ip" 开始执行任务==============="
for module in "${modules[@]}"
do
echo "===============远程主机 "$ip" 正在部署 "$module" ==============="
ip=$1; username=$2; password=$3; environment=$4; param=$5
sshpass -p $password ssh $username@$ip "mkdir -p /tmp/robot-patrol-platform"
sshpass -p $password scp ${WORKSPACE}/${module}/target/*.tar $username@$ip:/tmp/robot-patrol-platform
sshpass -p $password scp ${WORKSPACE}/script.sh $username@$ip:/tmp/robot-patrol-platform
sshpass -p $password ssh $username@$ip "chmod +x /tmp/robot-patrol-platform/script.sh && /tmp/robot-patrol-platform/script.sh $param"
done
echo "===============远程主机 "$ip" 脚本执行完成==============="
}
#==========定义任务函数结束==========
while read -r ip username password environment param; do
if [ "$host" = "all" ]; then
dotask $ip $username $password $environment "$param"
elif [ "$host" = "$environment" ]; then
dotask $ip $username $password $environment "$param"
fi
done < hosts.txt
echo "===============所有任务已完成==============="
提醒:本文发布于434天前,文中所关联的信息可能已发生改变,请知悉!