前言

写程序难免经历要很多调试,对于 K8S 开发,如果需要和集群内的其它服务进行交互,要么需要用 VPN 连接到集群内部,要么就需要打包 Docker 镜像,然后更新集群内的版本,就我来说,不是很喜欢前种方法,因为连到集群之后查资料就不是很方便,另外每次发版也是要走 CI 流程的,不妨做下 Golang 的 CI

公司技术栈是 Java + SpringBoot ,基本上没啥 Golang 的项目,自然也没有 Golang 的 CI 脚本,所以需要自己做,之前我弄过不少 CI ,不过是 Github Action 和 Gitea + Drone 之类的,需要写一个 yaml 文件,同时有很多可以用的组件 (use:xxx 这样的),是基于 Docker 的流水线,很方便,而公司使用的是 Jenkins ,而且是非常老版的 Jenkins ,所以只能写 Shell 脚本来打包

编写 Shell 脚本

虽然我很不喜欢 Shell 脚本,不愿意写这玩意儿,不过还好不需要从零开始,找隔壁组大佬要到了 Java 的 CI 脚本,可以在它的基础上简单改改就行

之前我做了套 Gitea + Drone 的 CI,那边主推是 Docker 流水线,不依赖宿主机环境,而 Jenkins 多是依赖宿主机环境,因为 Jenkins 太老装不上 Golang 插件,加上之前用的是 Docker 流水线,所以这次上 Jenkins 也仍然使用 Docker 来进行构建

来看脚本(部分敏感信息删改)

Jenkins 到 k8s 集群的 master 需要做 ssh 免密

#!/usr/bin/env bash
# @name: Golang 项目 jenkins 构建脚本
# @author: Luckykeeper
# @version: 1.0.0
# @description: 自动构建 code 仓库的 Golang 项目,并部署到开发集群
# @Email : luckykeeper@luckykeeper.site
# @Contact : luckykeeper@luckykeeper.site | http://luckykeeper.site | https://github.com/luckykeeper
# @date: 2023-11-08

# 代码提交或有新的标签提交时触发,构建 docker 镜像,推送到 开发镜像仓库 ,并部署到开发集群
# 最后一个提交上有标签时,会构建一个以此标签为tag的镜像,并推到公司生产仓,没有打标签时,镜像tag为"devp"

# 这里根据自己的项目来填写
# ------------ 变量开始,注意针对你的项目做修改 ------------ #
## docker镜像名(不带tag)
IMAGE=yunzainfo.com/project
## 服务器上的yaml所在目录
REMOTE_YAML_DIR=/opt/work/project/
# ------------ 变量结束 ------------ #

# --------------- 局部变量开始 --------------- #
# 打印日志前缀,方便查看
LOG_PREFIX="【MARS-Golang-Builder】---> "
LOG_SUCCESS="【SUCCESS】"
LOG_FAIL="【FAIL】"
# 开发仓的地址
DEVP_HARBOR="xxx"
# 生产仓的地址
PROD_HARBOR="yunzainfo.com"
# 使用 Oracle 数据库 k8s 集群的 Master 地址
ORACLE_SERVER="xxx.xxx.xxx.xxx"
# 使用 pgsql 数据库 k8s 集群的 Master 地址
POSTGRESQL_SERVER="xxx.xxx.xxx.xxx"
# docker镜像版本号,默认为devp,当前节点有标签(git tag)时,为标签名
VERSION_DEVP=devp
VERSION_TAG=${VERSION_DEVP}
# --------------- 局部变量结束 --------------- #


printVersion(){
echo "${LOG_PREFIX} Golang 项目 jenkins 构建脚本 (2023-11-08) Powered by Luckykeeper <luckykeeper@luckykeeper.site | https://luckykeeper.site | https://github.com/luckykeeper>"
}

printHelp(){
echo "${LOG_PREFIX}用法: /opt/tools/build-mars-go.sh <IMAGE> <REMOTE_YAML_DIR> [DEPLOY_TARGET]"
echo "${LOG_PREFIX}示例1: /opt/tools/build-mars-go.sh yunzainfo.com/cloud/project /opt/work/project/"
echo "${LOG_PREFIX}示例2: /opt/tools/build-mars-go.sh yunzainfo.com/cloud/project /opt/work/project/ oracle"
}

# 打包,构建镜像,推送
build(){
# docker镜像名(不带tag)
A_IMAGE=$1

devp_image="${A_IMAGE/${PROD_HARBOR}/${DEVP_HARBOR}}"
echo "${LOG_PREFIX}docker开发版本构建开始... ($devp_image:$VERSION_DEVP)"
echo "${LOG_PREFIX}docker build -t $devp_image:$VERSION_DEVP ."
docker build -t "$devp_image:$VERSION_DEVP" . > /dev/null
# docker build -t "$devp_image:$VERSION_DEVP" .
if [ $? -ne 0 ]; then
echo "${LOG_PREFIX}${LOG_FAIL}docker开发版本构建失败!($devp_image:$VERSION_DEVP)"
exit 1
fi
echo "${LOG_PREFIX}docker开发版本构建完成. ($devp_image:$VERSION_DEVP)"
echo "${LOG_PREFIX}docker开发版本推送开始... ($devp_image:$VERSION_DEVP)"
docker push "$devp_image:$VERSION_DEVP" > /dev/null
if [ $? -ne 0 ]; then
echo "${LOG_PREFIX}${LOG_FAIL}docker开发版本推送失败!($devp_image:$VERSION_DEVP)"
exit 1
fi
echo "${LOG_PREFIX}${LOG_SUCCESS}docker开发版本推送完成. ($devp_image:$VERSION_DEVP)"

# 看当前提交是否有标签,如果有,则按此标签名构建镜像版本并推送
gitLastTag=$(git describe --tags $(git rev-list --tags --max-count=1))
if [[ ! -n ${gitLastTag} ]]; then
echo "${LOG_PREFIX}该项目尚未打过标签"
else
echo "${LOG_PREFIX}所有分支最后一个标签: ${gitLastTag}"
hashTag=$(git describe --tags "${gitLastTag}")
currentHeadTag=$(git describe --tags HEAD)
if [[ ${hashTag} == "${currentHeadTag}" ]]; then
echo "${LOG_PREFIX}当前节点标签: ${currentHeadTag}"
VERSION_TAG=$currentHeadTag
echo "${LOG_PREFIX}docker标签版本构建开始... ($A_IMAGE:$VERSION_TAG)"
echo "${LOG_PREFIX}docker build -t $A_IMAGE:$VERSION_TAG"
docker build -t "$A_IMAGE:$VERSION_TAG" . > /dev/null
# docker build -t "$A_IMAGE:$VERSION_TAG" .
if [ $? -ne 0 ]; then
echo "${LOG_PREFIX}${LOG_FAIL}docker标签版本构建失败!"
exit 1
fi
echo "${LOG_PREFIX}docker标签版本构建完成.($A_IMAGE:$VERSION_TAG)"
echo "${LOG_PREFIX}docker标签版本推送开始... ($A_IMAGE:$VERSION_TAG)"
docker push "$A_IMAGE:$VERSION_TAG" > /dev/null
if [ $? -ne 0 ]; then
echo "${LOG_PREFIX}${LOG_FAIL}docker标签版本推送失败!($A_IMAGE:$VERSION_TAG)"
exit 1
fi
echo "${LOG_PREFIX}${LOG_SUCCESS}docker标签版本推送完成.($A_IMAGE:$VERSION_TAG)"
else
echo "${LOG_PREFIX}当前节点未打标签"
fi
fi

}


# 部署到开发服务器(使用开发镜像仓库)
deployDevpServer() {
A_REMOTE_YAML_DIR=$1
host=$2
databaseType=$3
echo "${LOG_PREFIX}部署到 $host ..."
echo "${LOG_PREFIX}创建目录"
ssh root@$host << EOF
mkdir -p $A_REMOTE_YAML_DIR
EOF

echo "${LOG_PREFIX}拷贝istio配置文件"
scp istio/istio-*.yaml root@$host:$A_REMOTE_YAML_DIR
scp istio/configmap-$databaseType.yaml root@$host:$A_REMOTE_YAML_DIR

echo "${LOG_PREFIX}执行远程命令"
ssh root@$host << EOF
cd $A_REMOTE_YAML_DIR
# kubectl delete -f configmap-$databaseType.yaml
# kubectl delete -f istio-gateway.yaml
# kubectl delete -f istio-svc-dpt.yaml
kubectl apply -f configmap-$databaseType.yaml
kubectl apply -f istio-gateway.yaml
sed -i "s/${PROD_HARBOR}/${DEVP_HARBOR}/g" istio-svc-dpt.yaml
kubectl apply -f istio-svc-dpt.yaml
exit
EOF
echo "${LOG_PREFIX}${LOG_SUCCESS}部署到 $host 完成."
}

# 部署到开发服务器(使用开发镜像仓库)
deploy() {
A_REMOTE_YAML_DIR=$1
target=$2
if [[ "$target" ]];then
if [ "$target" = "oracle" ]; then
deployDevpServer "$A_REMOTE_YAML_DIR" $ORACLE_SERVER oracle
elif [ "$target" = "postgresql" ]; then
deployDevpServer "$A_REMOTE_YAML_DIR" $POSTGRESQL_SERVER postgresql
else
echo "${LOG_PREFIX}不进行部署."
fi
else
deployDevpServer "$A_REMOTE_YAML_DIR" $ORACLE_SERVER oracle
deployDevpServer "$A_REMOTE_YAML_DIR" $POSTGRESQL_SERVER postgresql
fi
}

# ------------ 变量开始,从脚本传入 ------------ #
if [[ ! "$1" ]];then
echo "${LOG_PREFIX}-----------------[ 参数错误 ]-----------------" 1>&2;
printHelp
exit 1;
fi
if [[ ! "$2" ]];then
echo "${LOG_PREFIX}-----------------[ 参数错误 ]-----------------" 1>&2;
printHelp
exit 1;
fi

# docker镜像名(不带tag)
A_IMAGE=$1
# 服务器上的yaml所在目录
A_REMOTE_YAML_DIR=$2
# 部署目标
A_TARGET=$3
# ----------------- 变量结束 ----------------- #

# -------- 开始调用方法 --------- #
printVersion
echo "调用方法: build ${A_IMAGE}"
build "${A_IMAGE}"
echo "调用方法: deploy ${A_REMOTE_YAML_DIR} ${A_TARGET}"
deploy "${A_REMOTE_YAML_DIR}" "${A_TARGET}"
echo "${LOG_PREFIX}脚本执行完毕."
# -------- 结束 --------- #

Jekins 配置

选择 freeStyle 项目,进行如下配置,下面第二张图里面没有特殊配置,之前有别的下面有特殊配置,需要执行的特殊 shell 脚本可以写在这里

image-20231209183422177 image-20231209183527669

效果

每次提交之后,自动触发构建,推送到开发仓并重启 pod,如果发版,git 打上 tag,能够自动推送到公司仓

image-20231209190057593