基于jenkins+kubernetes的cicd流程实践二:微服务迁移脚本

5.api层服务迁移:

​ (1)项目启动脚本:start.sh

#!/bin/bash

srv_name="goods_web_main"
chmod +x ./${srv_name} 

if pgrep -x ${srv_name}; then
  echo "${srv_name} is running"
  echo "shutting down ${srv_name}"

  if ps -A | grep ${srv_name} | awk '{print $1}' | xargs kill $1; then
    echo "starting ${srv_name}"
    ./${srv_name}
    if [ $? -ne 0 ]; then
      echo "start ${srv_name} fail"
      exit 1
    fi
    echo "start ${srv_name} success"
  fi
else
  echo "starting ${srv_name}"
  ./${srv_name}
  if [ $? -ne 0 ]; then
    echo "start ${srv_name} fail"
    exit 1
  fi
  echo "start ${srv_name} success"
fi

​ (2)Dockerfile

FROM myhub.com/devops-tools/alpine:3.16
COPY target  /root/goods_web

LABEL service=goods-web-test

WORKDIR  /root/goods_web

# 由于前期项目未考虑容器化部署,为防止生产环境端口冲突,项目中开发环境端口固定,生产环境自动获取端口
# 有了容器后,不存在端口冲突的问题,端口固定后,更适合制作镜像和部署到k8s中
ENV MXSHOP_DEBUG=true

EXPOSE 8022

ENTRYPOINT ["sh","start.sh"]

​ (3)go build脚本:/script/go-build-web.sh

#!/bin/bash

echo "go build beginning"

echo "configure go environment variables"
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin

echo "start go module"
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy,https://goproxy.io,direct

echo "prepare directory structure"
# MODULE 项目名/目录名:agent pod添加的全局环境变量,会自动注入到每个容器中
JENKINS_DIR=${WORKSPACE}/${MODULE}
echo "jenkins workspace:${JENKINS_DIR}"
#ls ${JENKINS_DIR}


BUILD_DIR=${JENKINS_DIR}/target
echo "build workspace:${BUILD_DIR}"
if [ ! -d ${BUILD_DIR}/${MODULE} ]; then
  mkdir -p ${BUILD_DIR}/${MODULE}
  chmod 777 -R ${BUILD_DIR}
fi

if [ ! -f ${JENKINS_DIR}/config-debug.yaml ]; then
  echo "source config file not fount  ${JENKINS_DIR}/config-debug.yaml"
  exit 1
fi
cp ${JENKINS_DIR}/config-debug.yaml ${BUILD_DIR}/${MODULE}

if [ ! -f ${JENKINS_DIR}/start.sh ]; then
  echo "source start file not fount  ${JENKINS_DIR}/start.sh"
  exit 1
fi
cp ${JENKINS_DIR}/start.sh ${BUILD_DIR}

echo "execute go build, generate executable files"
if [ ! -f ${JENKINS_DIR}/main.go ]; then
  echo "source main file not fount  ${JENKINS_DIR}/main.go"
  exit 1
fi
go build -o ${BUILD_DIR}/${MODULE}_main ${JENKINS_DIR}/main.go

ls ${BUILD_DIR}
ls ${BUILD_DIR}/${MODULE}

echo "go build finished"

​ (4)docker build脚本:/script/build-image-web.sh

​ 容器间变量获取:

​ (a)全局变量可以在pod模板的环境变量中设置每个容器可以直接获取

​ (b)容器中生成的变量可以以文件的形式保存在jenkins工作目录中供其他容器获取

#!/bin/bash

echo "build image beginning"

BUILD_DIR=${WORKSPACE}/${MODULE}
if [ ! -d ${BUILD_DIR} ]; then
  echo "build image workspace not fount ${BUILD_DIR}"
  exit 1
fi

if [ ! -f ${BUILD_DIR}/Dockerfile ]; then
  echo "dockerfile not fount ${BUILD_DIR}/Dockerfile"
  exit 1
fi

VERSION=$(date +%y%m%d%H%M%s)
IMAGE_NAME=myhub.com/${JOB_NAME}/${MODULE}:${VERSION}
echo "${IMAGE_NAME}" > ${WORKSPACE}/IMAGE
echo "building image: ${IMAGE_NAME}"
docker build -t ${IMAGE_NAME} ${BUILD_DIR} || exit 1

echo "push image beginning"
docker push ${IMAGE_NAME} || exit 1
echo "push image finished"

​ (5)k8s deployment 部署:

​ (a)模板:/script/template/web.yaml

k8s中服务发现和健康检查功能,七层代理代如:master分支goods-web访问地址:http://master.com/g/v1/

#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{name}}
  namespace: {{namespace}}
spec:
  selector:
    matchLabels:
      app: {{name}}
  replicas: 1
  template:
    metadata:
      labels:
        app: {{name}}
    spec:
      containers:
        - name: {{name}}
          image: {{image}}
          ports:
            - containerPort: 8022
          livenessProbe:
            tcpSocket:
              port: 8022
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 2
            successThreshold: 1
            timeoutSeconds: 5
          readinessProbe:
            httpGet:
              path: /health
              port: 8022
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 2
            successThreshold: 1
            timeoutSeconds: 5
---
#service
apiVersion: v1
kind: Service
metadata:
  name: {{name}}
  namespace: {{namespace}}
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 8022
  selector:
    app: {{name}}
  type: ClusterIP
---
#ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{name}}
  namespace: {{namespace}}
spec:
  rules:
    - host: {{branch}}.com
      http:
        paths:
          - path: {{urlpath}}
            pathType: Prefix
            backend:
              service:
                name: {{name}}
                port:
                  number: 80

(b)脚本:/script/deploy.sh

健康检查:利用k8s健康检查结果,通知jenkins用户服务是否可用

#!/bin/bash

echo "k8s deploy beginning"

name=${JOB_NAME}
namespace=${BRANCH}
image=$(cat ${WORKSPACE}/IMAGE)
branch=${BRANCH}
urlpath=${urlpath}

echo "deploying ... name:${name},namespace:${namespace},image:${image},branch:${branch}"

prevision=$(kubectl get deployment.apps/${name} -n ${branch} -o go-template='{{index .metadata.annotations "deployment.kubernetes.io/revision"}}' 2>/dev/null || echo 0)
echo "deployment prevision:${prevision}"

rm -f web.yaml

cp $(dirname "${BASH_SOURCE[0]}")/template/web.yaml .

sed -i "s,{{name}},${name},g" web.yaml
sed -i "s,{{namespace}},${namespace},g" web.yaml
sed -i "s,{{image}},${image},g" web.yaml
sed -i "s,{{branch}},${branch},g" web.yaml
sed -i "s,{{urlpath}},${urlpath},g" web.yaml

kubectl apply -f web.yaml || exit 1

vision=$(kubectl get deployment.apps/${name} -n ${branch} -o go-template='{{index .metadata.annotations "deployment.kubernetes.io/revision"}}' 2>/dev/null || echo 0)
echo "deployment current vision:${vision}"

echo "k8s deploy finished"

cat web.yaml
echo ""

# 健康检查
success=0
count=60
IFS=","
#sleep=5
while [ ${count} -gt 0 ]; do
  if [ ${vision} == $((${prevision} + 1)) ]; then
    replicas=$(kubectl get deployment.apps/${name} -n ${branch} -o go-template='{{.status.replicas}},{{.status.updatedReplicas}},{{.status.readyReplicas}},{{.status.availableReplicas}}')
    echo "replicas: ${replicas}"
    arr=(${replicas})
    if [ "${arr[0]}" == "${arr[1]}" -a "${arr[1]}" == "${arr[2]}" -a "${arr[2]}" == "${arr[3]}" ]; then
      echo "health check success!"
      success=1
      break
    fi
    else
      echo "waiting deployment ..."     
  fi
  ((count--))
  sleep 2
done
if [ ${success} -ne 1 ]; then
  echo "health check failed!"
  exit 1
fi

​ (6)Jenkinsfile:

jenkins控制台获取变量:sh(returnStdout: true, script:'echo ${xxx}')

def label = "golang1.19.1"
def kube_credential = "global-kubernetes-credential"
def gitee_credential = "global-gitee-credentials"

timeout(time: 600, unit: 'SECONDS') {
    podTemplate(label: label,cloud: 'kubernetes'){
        node (label) {
            stage('pull code'){
                sh '''echo "pull code beginning"'''
                def branch = sh(returnStdout: true, script:'echo ${BRANCH}')
                git branch: branch, credentialsId: gitee_credential, url: '${url}'
                sh ''' echo "pull code finished"'''
            }
            stage('build project'){
                container('golang') {  
                    sh 'sh script/go-build-web.sh'
                }
            }
            stage('build image'){
                sh 'sh script/build-image-web.sh'
            }
            stage('deploy project'){
                container('kubectl') {
                    withKubeConfig([credentialsId: kube_credential,serverUrl: "https://kubernetes.default.svc.cluster.local"]) {
                        sh 'sh script/deploy.sh'
                    }
                }
            }
        }
    }
}
posted @ 2022-12-04 09:47  JN-SHao  阅读(181)  评论(0编辑  收藏  举报