Skip to content

Latest commit

 

History

History
352 lines (321 loc) · 12.1 KB

动态感知部署.md

File metadata and controls

352 lines (321 loc) · 12.1 KB

在一个大型 Java 项目中, 通常整个项目会被划分为很多个小模块, 正常的 Jenkins 流水线无法针对某一个模块改动进行针对性的部署。

以下配置文件为动态感知部署

k8s/kubernetes-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: D_NAME
  namespace: jzdata-<namespace>
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 5
  selector:
    matchLabels:
      app: D_NAME
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: D_NAME
    spec:
      containers:
        - env:
            - name: version
              value: "D_TAG"
            - name: TZ
              value: Asia/Shanghai
          envFrom:
            - configMapRef:
                name: D_NAME
          image: D_HARBOR/D_IMG/D_NAME:D_TAG
          imagePullPolicy: Always
          livenessProbe:
            failureThreshold: 3
            initialDelaySeconds: 60
            periodSeconds: 30
            successThreshold: 1
            tcpSocket:
              port: web
            timeoutSeconds: 1
          name: D_NAME
          ports:
            - containerPort: D_PORT
              name: web
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            tcpSocket:
              port: web
            timeoutSeconds: 1
            initialDelaySeconds: 60
            periodSeconds: 30
            successThreshold: 1
          resources:
            limits:
              cpu: "1"
              memory: 2Gi
            requests:
              cpu: 125m
              memory: 2Gi
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /opt/log/stash
              name: log-volume
            - mountPath: /var/tmp
              name: tmp-volume
            - mountPath: /tmp
              name: tmp-volume
      dnsPolicy: ClusterFirst
      imagePullSecrets:
        - name: jz-registry
      restartPolicy: Always
      schedulerName: default-scheduler
      volumes:
        - hostPath:
            path: /opt/log/stash
            type: DirectoryOrCreate
          name: log-volume
        - hostPath:
            path: /opt/tmp
            type: DirectoryOrCreate
          name: tmp-volume

Dockerfile

FROM registry.9zdata.cn/common/centos-jdk:1.8.1

WORKDIR /opt/

# P_JAR: jar 的名字(含.jar)
# P_SNAME: 服务名称
ENV WAR=P_JAR \
    ENV=dev \
    SERVICE_NAME=P_SNAME

# COPY libs /opt/libs/
COPY start.sh* P_PATH/target/${WAR} /opt/
ENV LC_ALL zh_CN.UTF-8
RUN chmod +x start.sh

CMD ["./start.sh"]

Jenkinsfile

pipeline {
    agent any

    environment {
        // 获取提交代码的用户
        author = sh(returnStdout: true, script: 'git log --pretty=format:"%an" -1').trim()
        // harbor 的地址
        HARBOR_URL = 'registry.9zdata.cn'
        // 镜像存在 harbor 的哪个 project 中
        HARBOR_PROJECT = 'ninestone'
        // 这个微服务需要部署的所有子服务名称
        PROJECT_NAME_0 = "ninestone-common"
        PROJECT_NAME_1 = 'ninestone-dynamic-page-service'
        PROJECT_NAME_2 = 'ninestone-goods-service'
        PROJECT_NAME_3 = 'ninestone-platform-service'
        PROJECT_NAME_4 = 'ninestone-point-service'
        PROJECT_NAME_5 = 'ninestone-tenant-service'
        PROJECT_NAME_6 = 'ninestone-user-service'
        PROJECT_NAME_7 = 'ninestone-web-api'
        // 公共的 k8s-deployment 文件
        K8S_DEPLOY_NAME = 'kubernetes-deployment.yaml'

        //  需要打包的服务
        ORIGIN_BUILD_PROJECT = ''
    }

    triggers {
        // 配置 gitlab 的 webhook 信息
        gitlab(triggerOnPush: true, triggerOnMergeRequest: false, branchFilterType: 'All', secretToken:"bf4c7a2bc847cc4e8438af7c2f4a3520")
    }

    stages {
        stage('Prepare') {
            steps {
                script {
                    sh "echo 开始构建, 当前分支 : ${env.BRANCH_NAME}"
                    // 只允许 master、dev、sit 分支进行构建
                    if(env.BRANCH_NAME != 'master' && env.BRANCH_NAME != 'dev' && env.BRANCH_NAME != 'sit') {
                        error("自动构建只能是 master、dev、sit 分支")
                    }
                    // 获取本次的 commitId
                    build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                    // 根据不同分支发布到不同的 k8s 的 namespace
                    branch = ""
                    if (env.BRANCH_NAME == 'master') {
                        branch = "uat"
                    }
                    if (env.BRANCH_NAME == 'dev') {
                        branch = "dev"
                    }
                    if (env.BRANCH_NAME == 'sit') {
                        branch = "sit"
                    }
                    tag = tag_input ?: build_tag
                    echo "tag: ${tag}"
                }
            }
        }
        stage('env explain') {
            steps {
                script{
                    def diffFiles = sh(returnStdout: true, script: "git show HEAD | grep diff | awk '{print \$3}' | awk '{print substr(\$0,3)}' | tr '\\n' ','").trim()
                    def splits = diffFiles.split(',')
                    def modulePaths = new HashSet<String>();
                    for(def filePath in splits){
                        int index = filePath.indexOf('/')
                        if(index >= 0 && !filePath.contains('k8s') && !filePath.contains('sql')){
                            modulePaths.add(filePath.substring(0, index))
                        }
                    }
                    println 'modulePaths:' + modulePaths
                    ORIGIN_BUILD_PROJECT = modulePaths
                }
            }
        }
        stage('mvn package') {
            steps {
                sh '''
                    source /home/.bashrc
                    mvn clean && mvn package -Dmaven.test.skip=true
                '''
            }
        }
        stage('make image & kube apply') {
            parallel {
                stage('ninestone-dynamic-page-service') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-dynamic-page-service') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_1}')
                        kubeApply('${PROJECT_NAME_1}', '19010')
                    }
                }
                stage('ninestone-goods-service') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-goods-service') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_2}')
                        kubeApply('${PROJECT_NAME_2}', '19015')
                    }
                }
                stage('ninestone-platform-service') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-platform-service') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_3}')
                        kubeApply('${PROJECT_NAME_1}', '19003')
                    }
                }
                stage('ninestone-point-service') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-point-service') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_4}')
                        kubeApply('${PROJECT_NAME_1}', '19014')
                    }
                }
                stage('ninestone-tenant-service') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-tenant-service') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_5}')
                        kubeApply('${PROJECT_NAME_1}', '19004')
                    }
                }
                stage('ninestone-user-service') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-user-service') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_6}')
                        kubeApply('${PROJECT_NAME_1}', '19005')
                    }
                }
                stage('ninestone-web-api') {
                    when {
                        expression {
                            return ORIGIN_BUILD_PROJECT.contains('ninestone-web-api') || ORIGIN_BUILD_PROJECT.contains('ninestone-common')
                        }
                    }
                    steps {
                        buildImages('${PROJECT_NAME_7}')
                        kubeApply('${PROJECT_NAME_1}', '19012')
                    }
                }
            }
        }
    }
    parameters {
        string(name: 'tag_input', defaultValue: '', description: '部署的服务的镜像标签')
        booleanParam(name: 'origin_build_all', defaultValue: false, description: '是否打包整个服务')
    }

    post {
        always {
            dingtalk(
                    robot: '通知机器人',
                    type: 'ACTION_CARD',
                    title: '你有新的消息, 请注意查收',
                    text: [
                            "# [钉钉通知工具人~](${env.JOB_URL}) ",
                            "---",
                            "- 项目: ${JOB_NAME}",
                            "- 分支: ${currentBuild.projectName}",
                            "- 编号: [#${currentBuild.number}](${env.BUILD_URL})",
                            "- 状态: ${currentBuild.currentResult}",
                            "- 持续时间: ${currentBuild.durationString}",
                            "- 提交人: ${author}",
                            "- 消息: 你的任务已经部署, 请注意",
                            "- 部署服务: ${ORIGIN_BUILD_PROJECT}"
                    ]
            )
        }
    }
}

def buildImages(server_name) {
    sh """
        rm -f ./Dockerfile_tmp_${server_name}
        cp ./Dockerfile ./Dockerfile_tmp_${server_name}
        sed -i \"s/P_JAR/${server_name}.jar/g\" ./Dockerfile_tmp_${server_name}
        sed -i \"s/P_SNAME/${server_name}/g\" ./Dockerfile_tmp_${server_name}
        sed -i \"s#P_PATH#${server_name}#g\" ./Dockerfile_tmp_${server_name}
        cat ./Dockerfile_tmp_${server_name}
        docker build -t ${HARBOR_URL}/${HARBOR_PROJECT}/${server_name}:${tag} -f Dockerfile_tmp_${server_name} .
        docker push ${HARBOR_URL}/${HARBOR_PROJECT}/${server_name}:${tag}
        docker rmi ${HARBOR_URL}/${HARBOR_PROJECT}/${server_name}:${tag}
    """
}
def kubeApply(server_name, port) {
    sh """
        cp ./k8s/${K8S_DEPLOY_NAME} ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        sed -i \"s/D_NAME/${server_name}/g\" ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        sed -i \"s/<namespace>/${branch}/g\" ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        sed -i \"s/D_HARBOR/${HARBOR_URL}/g\" ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        sed -i \"s/D_IMG/${HARBOR_PROJECT}/g\" ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        sed -i \"s/D_TAG/${tag}/g\" ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        sed -i \"s/D_PORT/${port}/g\" ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        cat ./k8s/${server_name}/${K8S_DEPLOY_NAME}
        kubectl apply -f ./k8s/${server_name}/${K8S_DEPLOY_NAME}
    """
}