[kubernetes]step7-创建pipline

准备步骤

准备一个jenkins

我这里代码在本地机房编译,通过一台阿里云跳板机,再发布到k8s-op-m01

这里并没有采用configmap来挂载配置文件,是套用了一个统配的配置文件,通过构建前的shell脚本去实现替换。因为没有生产环境,也没有强制分离namespace

遇到的问题

1 可用pod的数量

deployment 更新的时候虽然pod显示2个都已经running,但是由于服务注册等延迟,会有一段时间eureka上没有一个可用的服务 。 这里采用了lifecycle里的postStart,让容器在启动的时候sleep 30,让pod先注册,等到30秒之后,deployment里才会变为ready这样就会有3个pod在eureka上,确保之前的deployment和新的deployment的rs在交替时,有服务可用。

2 优雅退出

在运行1个replicas的deployment的时候,明明deployment已经更换镜像,原有的pod也已经销毁,但是eureka上迟迟不更新状态。这个问题也是采用了lifecycle里的preStop,让容器在退出之前先执行一下退出java进程的命令,告诉eureka,我下线了。这样之后基本容器销毁前eureka上的注册信息已经更新掉了。

下图是在更新拥有2个replicas的镜像的时候 出现3个pod的情况,确保服务可用

其余的没啥好说。直接丢一个部署过程的截图吧

大概就是 下代码 > 编译 > 拷贝代码 > 创建Dockerfile > 打镜像并push > 部署k8s > 健康检查

pipline的脚本
node {
    env.PRO_NAME = "ac"
    env.PRO_TYPE = "core"
   stage('Vars') { 
       sh "echo ${WORKSPACE} "
       sh "echo ${Branch} "
       sh "echo ${deploy_step} "
       sh "echo ${env.JOB_NAME} "
       //sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version}   " 
   }
      stage('Pull Coding') { // for display purposes
      // Get some code from a GitHub repository
      git credentialsId: '', url: '[email protected]:jiaminxu/java-ac-core-course.git'
      // Get the Maven tool.
      // ** NOTE: This 'M3' Maven tool must be configured
      // **       in the global configuration.           
   }
   stage('Maven Build') {
       //sh "mvn -pl ${MODULE} -am clean package"
       sh "echo Maven Build"
       sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version} func_compile  " 
   }
   stage('Scp Jar') {
       sh "echo build image"
       sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version} func_scp  " 
   }
   stage('Create Dockerfile') {
       sh "echo build image"
       sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version} func_docker  " 
   }
   stage('Image Push') {
       sh "echo build image"
       sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version} func_push  " 
   }  
   stage('Deploy') {
       sh "echo build image"
       sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version} func_deploy   " 
   }    
   
      stage('Health Check') {
       //sh "/root/script/deploy.sh"
       sh "echo Health Check"
       sh "sh /ops/java_scripts/pipline-deploy.sh ${env.PRO_NAME} ${env.PRO_TYPE} ${Branch}    ${env.JOB_NAME}    ${deploy_step} ${BUILD_NUMBER} ${Version} func_health  " 
   }

}
deployment模版
apiVersion: apps/v1
kind: Deployment
metadata:
# deployment名字 和svc 和ingress绑定没关系
  name: pre-demojob-dp
  namespace: default
spec:
  replicas: 2
  # 在定义模板的时候必须定义labels,因为Deployment.spec.selector是必须字段,而他又必须和template.labels对应
  selector:
    matchLabels:
      app: pre-demojob
  # template里面定义的内容会应用到下面所有的副本集里面(例如depolyment下的pod),在template.spec.containers里面不能定义labels标签。可以kubectl get pods --show-labels查看
  template:
    metadata:
      labels:
        app: pre-demojob
        env: pre
    spec:
      containers:
      # containers名字 和svc 和ingress绑定没关系
      - name: pre-demojob
        image: harbor.aircourses.com/kubernetes/demojob:vversion
        #image: harbor.aircourses.com/kubernetes/wehub:v7.80
        lifecycle:
          # sleep 30用于确保原有的pod 不是全部马上退出 造成eureka上服务一个pod都没有
          postStart:
            exec:
              command: ["/bin/sleep", "30"]
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sh /data/module/demojob/bin/start.sh stop"]
        ports:
        - name: http
          containerPort: 80
      imagePullSecrets:
        - name: myregistrykey

部署用的shell脚本 仅做参考 也是第一次尝试 没什么经验

#!/bin/sh
# @Time    : 2020-02-04
# @Author  : jiaminxu
# @Description  : 用于jenkins部署kubernetes
#--------------------------------------------
##########  shell脚本传入的参数  ##########
##########  shell脚本传入的参数  ##########
##########  shell脚本传入的参数  ##########
# 项目名称
pro_name=${1}           #{pd|ac|sc|..}
# 项目类型
pro_type=${2}           #{api|core}
# 部署环境
pro_env=${3}            #{dev|pre|master|test|test2}
# jenkins的job名称
job_name=${4}           #{ac-client|ac-core-assist}
# 此次部署步骤
deploy_step=${5}        #{Compile|Deploy|Build|..}
# 此次部署的非0构建号
build_number=${6}       #{1|2|3}
# 需要回滚的非0构建号
rollback_version=${7}   #{1|2|3}
# 此次执行的函数名称
name_func=${8}
# docker_var
docker_var=`echo ${job_name} | sed "s/.*${pro_name}-//g " | sed "s/.*${pro_type}-//g"`
# cut_job_name
cut_job_name=`echo ${job_name} | sed "s/.*k8s-//g "`

echo "$pro_name $pro_type $pro_env $job_name $deploy_step $build_number $rollback_version $docker_var  $cut_job_name"
jenkins_result_file="/root/.jenkins/workspace/${job_name}/jenkins_result_${job_name}.txt"
deploy_ip="192.168.12.21"
# 定义远程部署文件夹 即Dockerfile文件所在的路径
module_dir=/data/module/kubernetes/${pro_env}/${pro_name}/${pro_type}/${job_name}
echo "[tags] module_dir: $module_dir"
# 定义上传jar包的远端文件夹 即Dockerfile编译的lib包路径
target_dir="${module_dir}/lib"
version=${build_number}
func_user()
{
#--------------------------------------------
##########  判断执行的用户是否有权限执行生产  ##########
##########  判断执行的用户是否有权限执行生产  ##########
##########  判断执行的用户是否有权限执行生产  ##########
# jenkins_result_file
jenkins_result_file="/root/.jenkins/workspace/${job_name}/jenkins_result_${job_name}.txt"
echo "[tags] jenkins_result_file :$jenkins_result_file"
echo $jenkins_result_file #用于判断部署脚本是否异常退出 1为异常,如果启动成功会在脚本最后输入0
# 用于判断部署脚本是否异常退出 1为异常,如果启动成功会在脚本最后输入0
echo 1 >$jenkins_result_file
echo "[tags] 判断执行用户权限"
# 只有admin 和 jiaminxu 或者api调用时用户名为空 可以部署master
if [ "$user" != "admin" ] && [ "$user" != "jiaminxu" ] && [ "$user" != "" ] && [ "$pro_env" == "master" ]; then
	echo "[ERROR] 当前用户:${user},没有构建生产项目权限 !!"
	echo 1 >$jenkins_result_file
	exit 1
fi
echo [tags] 当前用户:${user}
}
func_base()
{
#--------------------------------------------
##########  判断 [ac|pd|sc|hp] 参数内容正确性  ##########
##########  判断 [ac|pd|sc|hp] 参数内容正确性  ##########
##########  判断 [ac|pd|sc|hp] 参数内容正确性  ##########
if [[ ${pro_name} != "ac" ]] && [[ ${pro_name} != "pd" ]] && [[ ${pro_name} != "sc" ]] && [[ ${pro_name} != "hp" ]]; then
	echo "[ERROR] 请输入正确的项目参数 [pd,ac,sc,hp]: 当前是:"${pro_name}
	echo 1 >$jenkins_result_file
	exit 1
fi
}
func_compile()
{
#--------------------------------------------
##########  编译  ##########
##########  编译  ##########
##########  编译  ##########
# 申明jenkins WORKSPACE
module_path="/root/.jenkins/workspace/${job_name}"
echo build_number: $build_number rollback_version: $rollback_version # 暂时没有设计回滚功能
echo 1 >$jenkins_result_file
#--------------------------------------------
##########  进入WORKSPACE编译  ##########
##########  进入WORKSPACE编译  ##########
##########  进入WORKSPACE编译  ##########
if [ "$pro_env" == "master" -a "$deploy_step" == "Deploy" ] || [ "$pro_env" == "master" -a "$deploy_step" == "Rollback" ] || [ "$pro_env" == "master" -a "$deploy_step" == "Restart" ]; then  # 暂时没有设计好需要哪些功能 暂定部署 伸缩 [重启|回滚]? 非生产不允许伸缩 回滚可能用得上这个判断
	echo "[tags] 生产直接部署 不进行mvn编译"
else
	echo "[tags] 执行clean_deploy"
	cd ${module_path}
	echo "[tags] module_path:${module_path}"
	return_value=$(mvn clean install -N && mvn clean deploy)
  # 输出编译过程
	echo -e "[tags] 编译输出:\n${return_value}"
	# 判断是否出现编译错误
	num=$(echo "${return_value}" | grep "ERROR" | wc -l)
	[ $num -ne 0 ] && {
		date +'%Y-%m-%d %H:%M:%S'
		echo "[ERROR] 编译报错"
		echo 1 >$jenkins_result_file
		exit 7
	}
	echo "[tags] 删除spring-boot-devtools-*.jar 避免出现因为远程调试造成的性能问题"
	echo "[tags] rm -rf ${module_path}/target/lib/spring-boot-devtools-*.jar"
	rm -rf ${module_path}/target/lib/spring-boot-devtools-*.jar
	# 输出版本号
	version=$(echo -e "编译输出:\n${return_value}" | grep "[INFO]" | grep "Building" | grep ${cut_job_name} | grep -v jar | head -n 1 | awk -F" " '{print $4}')
	echo "[tags] version : $version"
	echo ${version} > /ops/java_scripts/deploy_version/$Branch_$JOB_NAME.txt
  echo "echo ${version} > /ops/java_scripts/deploy_version/$Branch_$JOB_NAME.txt"
fi
}
func_scp()
{
#--------------------------------------------
##########  编译完成,上传至跳板服务器,进行编译  ##########
##########  编译完成,上传至跳板服务器,进行编译  ##########
##########  编译完成,上传至跳板服务器,进行编译  ##########
# 判断是不是core服务 core服务和api服务编译生产的lib包位置不太一样
if [ ${pro_type} == "core" ]; then
	jar_path="/root/.jenkins/workspace/${job_name}/boot"
else
	jar_path="/root/.jenkins/workspace/${job_name}"
fi
echo "[tags] ---------------------------------------------------------------------"
echo "[tags] 本地项目存放路径 --> "${module_path}
echo "[tags] 本地Jar包存放路径--> "${jar_path}
echo "[tags] ---------------------------------------------------------------------"
# 定义远程部署文件夹 即Dockerfile文件所在的路径
module_dir=/data/module/kubernetes/${pro_env}/${pro_name}/${pro_type}/${job_name}
echo "[tags] module_dir: $module_dir"
# 定义上传jar包的远端文件夹 即Dockerfile编译的lib包路径
target_dir="${module_dir}/lib"
echo "[INFO] ----------------------<          DIR          >----------------------"
echo "[INFO] kubernetes路径   ----> "${module_dir}
echo "[INFO] Jar包存放路径  ----> "${target_dir}
# 部署跳板机的ip 用于编译镜像 打tag上传 本地带宽限制 可能导致上传太慢
deploy_ip="192.168.12.21"
echo "[tags] 部署地址为${deploy_ip}"
ssh root@${deploy_ip} "\
                        [ ! -d ${module_dir} ]&& mkdir -p ${module_dir};\
                        rm -rf ${module_dir}/* && mkdir -p ${module_dir}/lib"
echo "[tags] 拷贝代码至${deploy_ip}${module_dir}下"
scp ${jar_path}/target/*.jar root@${deploy_ip}:${module_dir}/lib
echo "[tags] scp ${jar_path}/target/*.jar root@${deploy_ip}:${module_dir}/lib"
scp ${jar_path}/target/lib/*.jar root@${deploy_ip}:${module_dir}/lib
echo "[tags] scp ${jar_path}/target/lib/*.jar root@${deploy_ip}:${module_dir}/lib"
#--------------------------------------------
##########  复制指定环境指定类型的模版文件夹bin和conf到部署文件夹中  ##########
##########  复制指定环境指定类型的模版文件夹bin和conf到部署文件夹中  ##########
##########  复制指定环境指定类型的模版文件夹bin和conf到部署文件夹中  ##########
# 拷贝对应的demo配置文件
ssh root@${deploy_ip} "cp -r /data/module/kubernetes/demo/${Branch}_${pro_type}_demo/bin ${module_dir}/"
ssh root@${deploy_ip} "cp -r /data/module/kubernetes/demo/${Branch}_${pro_type}_demo/conf ${module_dir}/"
ssh root@${deploy_ip} "ls -l ${module_dir}"
ssh root@${deploy_ip} "ls -l ${module_dir}/conf"
# 替换demo里的关键字
ssh root@${deploy_ip} "cd ${module_dir};for i in bin/start.sh conf/application.properties conf/logback.xml ;do sed -i  's/demojob/$docker_var/g' \$i;done"
echo ssh root@${deploy_ip} "cd ${module_dir};for i in bin/start.sh conf/application.properties conf/logback.xml ;do sed -i  's/demojob/$docker_var/g' \$i;done"
}
func_docker()
{
#--------------------------------------------
##########  生成Dockerfile到部署文件夹中  ##########
##########  生成Dockerfile到部署文件夹中  ##########
##########  生成Dockerfile到部署文件夹中  ##########
ssh root@${deploy_ip} "echo FROM harbor.aircourses.com/kubernetes/jdk-1.8.0_161:v1 > ${module_dir}/Dockerfile "
ssh root@${deploy_ip} "echo 'MAINTAINER PDABC Enterprise Container Images <[email protected]>' >> ${module_dir}/Dockerfile"
ssh root@${deploy_ip} "echo COPY  lib  /data/module/${cut_job_name}/lib >> ${module_dir}/Dockerfile"
ssh root@${deploy_ip} "echo COPY  bin  /data/module/${cut_job_name}/bin >> ${module_dir}/Dockerfile"
ssh root@${deploy_ip} "echo COPY  conf  /data/module/${cut_job_name}/conf >> ${module_dir}/Dockerfile"
ssh root@${deploy_ip} "echo ENTRYPOINT [\\\"sh\\\", \\\"/data/module/${cut_job_name}/bin/start.sh\\\", \\\"start\\\"]  >> ${module_dir}/Dockerfile"
}
func_push()
{
#--------------------------------------------
##########  docker build 生成镜像 并上传harbor  ##########
##########  docker build 生成镜像 并上传harbor  ##########
##########  docker build 生成镜像 并上传harbor  ##########
version=${build_number}
ssh root@${deploy_ip} " cd ${module_dir};docker  build  -t harbor.aircourses.com/kubernetes/${cut_job_name}:v${version} . "
ssh root@${deploy_ip} " docker push harbor.aircourses.com/kubernetes/${cut_job_name}:v${version}"
}
func_deploy()
{
#--------------------------------------------
##########  更新deployment  ##########
##########  更新deployment  ##########
##########  更新deployment  ##########
echo  cp  /data/module/kubernetes/demo/deployment/${Branch}/deployment.yaml  ${module_dir}/deployment.yaml
ssh root@${deploy_ip} "  yes|cp  /data/module/kubernetes/demo/deployment/${Branch}/deployment.yaml  ${module_dir}/deployment.yaml "
ssh root@${deploy_ip} " sed -i \"s/demojob/${cut_job_name}/g\" ${module_dir}/deployment.yaml "
ssh root@${deploy_ip} " sed -i \"s/version/${version}/g\" ${module_dir}/deployment.yaml "
ssh root@${deploy_ip} " sed -i \"s/version/${version}/g\" ${module_dir}/deployment.yaml "
echo "[tags] 输出即将部署的deployment.yaml"
echo "[tags] 输出即将部署的deployment.yaml"
echo "[tags] 输出即将部署的deployment.yaml"
ssh root@${deploy_ip} " cat  ${module_dir}/deployment.yaml "
ssh root@${deploy_ip} " ssh root@k8s-op-m01 \"[ ! -d ${module_dir} ]&& mkdir -p ${module_dir};rm -rf  ${module_dir}/* \" "
echo "[tags] mkdir -p ${module_dir}"
ssh root@${deploy_ip} " scp   ${module_dir}/deployment.yaml k8s-op-m01:${module_dir}/ "
echo  "[tags] kubectl apply -f ${module_dir}/deployment.yaml"
ssh root@${deploy_ip} " ssh  root@k8s-op-m01  \"kubectl apply -f ${module_dir}/deployment.yaml \""
}
func_health()
{
#--------------------------------------------
##########  健康检查deployment  ##########
##########  健康检查deployment  ##########
##########  健康检查deployment  ##########
success=0
count=60
name="$Branch-$cut_job_name-dp"
# fen ge de shi hou zi dong sheng cheng su zhu
IFS=","
sleep 5
while [ ${count} -gt 0 ]
do
    replicas=$(ssh 192.168.12.21 "ssh 192.168.12.58  \"kubectl get deploy $name  -o go-template='{{.status.replicas}},{{.status.updatedReplicas}},{{.status.readyReplicas}},{{.status.availableReplicas}}'\"")
    echo "replicas: ${replicas}"
    arr=(${replicas})
    echo status.replicas: ${arr[0]}
    echo status.updatedReplicas: ${arr[1]}
    echo status.readyReplicas: ${arr[2]}
    echo status.availableReplicas: ${arr[3]}
    if [ "${arr[0]}" == "${arr[1]}" -a "${arr[1]}" == "${arr[2]}" -a "${arr[2]}" == "${arr[3]}" ];then
        echo "health check success!"
        success=1
        break
    fi
    ((count--))
    sleep 2
done
if [ ${success} -ne 1 ];then
    echo "health check failed!"
    exit 1
fi
echo "count剩余${count}"
echo 0 >$jenkins_result_file # 这里暂时写0 否则jenkins构建完会显示失败
}
# 部署kubernetes进程的默认用户
# deploy_user="root"
${name_func}
发布了300 篇原创文章 · 获赞 25 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/xujiamin0022016/article/details/104204702