使用jenkins中的Pipeline写一个特殊的流水线

avatar 2023年11月4日18:36:38 评论 143 次浏览

使用jenkins中的Pipeline写一个特殊的流水线,先说一下,我们的一个仓库中包含了多个微服务,为何这样做,这个先不管为什么这样做。现在要实现的问题是我在一个Pipeline里实现整个job的运行,并且在发布过程中可用进行选择性的发布。原来的方案是,让开发在仓库中创建一个文件,然后根据我定义的规则,如果发布那个服务,就把服务名添加到文件中,在Pipeline里我会读取文件内容,然后根据文件内容进行循环操作。这种方式虽然还不错,但是开发习惯了用手点击,不想每次提交的时候修改文件。没办法,我需要在jenkins上下功夫。经过多次测试,发现在jenkins中可用通过两个插件,Extended Choice Parameter Name和git参数两个参见也可以实现。
利用这两个插件,把开发要修改文件的操作,放到jenkins里,只需要在jenkins中每次发布的服务进行循环操作即可,看一下我的样式。

先添加一个分支参数,每次发布的时候,需要根据分支拉取代码,不通环境的编译参数还不一样,所以需要获取分支名称,并把分支作为变量传递给Pipeline,后面会用到。另外,为了避免分支过多,可以进行快速过滤,列表数量就是build的时候显示的分支数量。

这里是把服务名称也作为变量传递,并且服务之间使用逗号分隔,这里可以的6是build的时候可以查看的服务数量。

到此,jenkin的操作替换了文件操作,后面就都一样了,每次发布时需要分支,服务名称选择,然后开始构建就完成了,下面看一下我的Pipeline内容。

def dockerbuild(item) {   #镜像生成函数
    JAVA_START="java -XX:+UseContainerSupport  -javaagent:/opt/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=${K8S_NAMESPACE}::${item} -Dskywalking.collector.backend_service=skywalking.skywalking:11800 -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=50.0 -XX:MinRAMPercentage=50.0 -Dlog4j2.formatMsgNoLookups=true -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai -jar /apps/works/server/${item}.jar"
    //JAVA_START="java \${JAVA_OPTS} -javaagent:/opt/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=${K8S_NAMESPACE}::${item} -Dskywalking.collector.backend_service=skywalking.skywalking:11800 -XX:+UseContainerSupport -XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=50.0 -XX:MinRAMPercentage=50.0 -Dlog4j2.formatMsgNoLookups=true -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai -jar /apps/works/server/${item}.jar"   
    sh "echo -e '#!/bin/bash \n${JAVA_START}' > enpoint.sh"
    sh """
    cat>Dockerfile<<EOF
FROM ${DOCKER_IMAGE}
COPY target/${item}.jar /apps/works/server/
COPY enpoint.sh /usr/bin/enpoint
WORKDIR /apps/works
RUN chmod +x /usr/bin/enpoint
CMD  ["/bin/bash","enpoint"]
EOF
"""
    sh "docker build -t ${item}-${ENV} . "
    sh "docker tag ${item}-${ENV}:latest ${SVC_IMAGE}/${SVC_IMAGENAME}/${item}-${ENV}:${BUILD_NUMBER}"
    sh "docker tag ${item}-${ENV}:latest ${SVC_IMAGE}/${SVC_IMAGENAME}/${item}-${ENV}:latest"
    sh "docker push ${SVC_IMAGE}/${SVC_IMAGENAME}/${item}-${ENV}:${BUILD_NUMBER}"
    sh "docker push ${SVC_IMAGE}/${SVC_IMAGENAME}/${item}-${ENV}:latest"
    sh "docker rmi ${item}-${ENV}:latest || true"
    sh "docker rmi ${SVC_IMAGE}/${SVC_IMAGENAME}/${item}-${ENV}:latest  || true"
    sh "docker rmi ${SVC_IMAGE}/${SVC_IMAGENAME}/${item}-${ENV}:${BUILD_NUMBER}  || true"
}

def portserver(SERVER) { #判断服务名称,并添加服务的端口
    //sh "echo ${PROJECT} ${SERVER}"
    if (SERVER == "module-system") {
        eftFunction(6000,SERVER)
    } else if (SERVER == "auth") {
        eftFunction(8030,SERVER)
    } else if (SERVER == "gateway") {
        gateFunction(8000,SERVER)
    } else if (SERVER == "service-oss") {
        eftFunction(6060,SERVER)
    } else if (SERVER == "service-job") {
        eftFunction(7020,SERVER)
    }  else if (SERVER == "module-telegram") {
        eftFunction(6030,SERVER)
    }  else if (SERVER == "module-data-system-can") {
        eftFunction(6020,SERVER)
    }
}

def eftFunction(SVC_PORT,SERVER) { #发布函数
    sh "echo ${SVC_PORT}  ${SERVER}"
    sh """
    ansible-playbook -i /etc/ansible/inventory/hosts /etc/ansible/book/deploy_k8s.yml -e  "host=k8s SVC_NAME=${SERVER} SVC_NS=${K8S_NAMESPACE} SVC_ENV=${ENV} SVC_PORT=${SVC_PORT} SVC_REPLICAS=${REPLICAS} SVC_CPU=1 SVC_MEM=2 BUILD_NUMBER=${BUILD_NUMBER} SVC_NODE=application SVC_IMAGE=${SVC_IMAGE} SVC_IMAGENAME=${SVC_IMAGENAME}"
       
    """
}
def gateFunction(SVC_PORT,SERVER) {  #发布函数
    sh "echo ${SVC_PORT}  ${SERVER}"
    sh """
    ansible-playbook -i /etc/ansible/inventory/hosts /etc/ansible/book/deploy_k8s.yml -e  "host=k8s SVC_NAME=${SERVER} SVC_NS=${K8S_NAMESPACE} SVC_ENV=${ENV} SVC_PORT=${SVC_PORT} SVC_REPLICAS=${REPLICAS} SVC_CPU=1 SVC_MEM=2 BUILD_NUMBER=${BUILD_NUMBER} SVC_NODE=application SVC_IMAGE=${SVC_IMAGE} SVC_IMAGENAME=${SVC_IMAGENAME}"
       
    """
}


pipeline {
    agent any
    options {
        timeout(time: 60, unit: 'MINUTES') //SECONDS, MINUTES, HOURS
        timestamps () 
    }
    stages {
        stage('Preparation environment variables') {
            steps {
                script {      #基础变量
                    SOURCE_CODE_REPO = '仓库地址'
                    SOURCE_CODE_REPO_CREDENTIALS = '授权jenkin的id'
                    ENV = 'qa'                 //环境也是分支
                    SVC_IMAGE = '镜像仓库地址'              //镜像地址
                    SVC_IMAGENAME = '镜像仓库项目名称'         //镜像地址命名空间
                    REPLICAS = '1'             //副本数
                    K8S_NAMESPACE = 'k8s中的namespaces'        //命名空间
                    SVC_NOD = 'application'  //节点标签
                    DOCKER_IMAGE = '基础镜像地址'
                }
            }


        }
        stage('Preparation source code') {
            steps {
                checkout([$class: 'GitSCM', 
                branches: [[name: "${BRANCH_TAG}"]], #这里的BRANCH_TAG就是git参数中定义的分支
                doGenerateSubmoduleConfigurations: false, 
                extensions: [
                      [$class: 'CheckoutOption', timeout: 40], 
                      [$class: 'CloneOption', noTags: false, reference: '', shallow: false, timeout: 40]
                  ], 
                gitTool: 'Default', 
                submoduleCfg: [], 
                userRemoteConfigs: [[url: "$SOURCE_CODE_REPO", credentialsId: "$SOURCE_CODE_REPO_CREDENTIALS",]]
                ])
                script {
                    sh "set LESSCHARSET=utf-8"
                    env.GIT_COMMIT_MSG = sh (script: "git log -n 4 --oneline --no-merges --pretty=format:'%s %cn'", returnStdout: true).trim()
                }
            }
        }
        stage('Maven build') {
            steps {
                sh "echo maven"
                sh 'mvn -Dmaven.test.skip=true -Djacoco.skip=true -Dmaven.test.failure.ignore clean package -P test'
            }
        }
        stage('Docker build') {
            steps {
                script { #这里的DEPLOY_MODULES就是定义的服务名称,会循环选择的服务
                    for (item in "$DEPLOY_MODULES".tokenize(',')){ #因为有多个微服务,所以需要判断服务名称在进入目录,然后在调研dockerfile函数生成镜像
                        if ( item.contains("module") == true ) {
                            dir("${env.WORKSPACE}/modules/${item}"){
                                dockerbuild(item)
                            }
                        } else if ( item.contains("service") == true ) {
                            dir("${env.WORKSPACE}/services/${item}"){
                                dockerbuild(item)
                            }
                        } else {
                            dir("${env.WORKSPACE}/${item}"){
                                dockerbuild(item)
                            }
                        }
                        
                    }
                }
            }
        }
        stage('k8s deploy') {
            steps {
                sh 'echo "k8s yml"'
                script {
                    for (item in "$DEPLOY_MODULES".tokenize(',')){ #根据服务选择的服务进行循环,然后进行发布操作。
                        portserver(item)
                        //sh 'echo $item'
                    }
                }
            }
        }
    }
}

这里写的很简单,就是需要一个判断不同服务编译后的jar包路径,根据选择的服务进行生产镜像,然后在根据选择的服务进行发布操作。是不是很简单,相比原来的发布方式更简单了,

avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: