正文:
之前我们分享了关于如何使用 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 "===============所有任务已完成==============="
转载请注明:汇站网 » Jenkins 微服务打包再优化的探索