learn-tech/专栏/Jenkins持续交付和持续部署/16.使用Kubernetes编排JenkinsSlave节点持续交付项目.md
2024-10-16 06:37:41 +08:00

27 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        16.使用Kubernetes编排Jenkins Slave节点持续交付项目
                        在上一节的内容中简单介绍了一下使用kubernetes插件动态生成slave节点的基本语法和使用示例本节会根据上节介绍到的一些语法知识进行一个基础的实践并继续补充一些使用该插件时的一些配置细节。

为了方便读者理解本小节内容会分多个版本以由浅入深的方式尽量将之前的pipeline语法融会贯通。

基础版

本次版本说明:

1、 PodTemplate 配置以pipeline script的方式放到pipeline脚本里没有在Jenkins 系统配置里进行定义。

2、 Jenkins默认的Jenkins slave镜像为jnlp-slave:3.35-5-alpine这是一个Jnlp方式的agent镜像该镜像没有拉取/编译代码以及docker命令需要基于此镜像自定义一个新的镜像。

3、 构建应用镜像时的Dockerfile文件通过挂载nfs的方式引用。

4、 使用最基础的shell命令实现一个简单的持续交付脚本以方便了解该持续交付的流程。

基于上面条件用脚本式语法编写的pipeline脚本如下

podTemplate(cloud: 'kubernetes',namespace: 'default', label: 'pre-CICD', serviceAccount: 'default', containers: [ containerTemplate( name: 'jnlp', image: "192.168.176.155/library/jenkins-slave:latest", args: '${computer.jnlpmac} ${computer.name}', ttyEnabled: true, privileged: true, alwaysPullImage: false, ), ], volumes: [ nfsVolume(mountPath: '/tmp', serverAddress: '192.168.177.43', serverPath: '/data/nfs', readOnly: true), hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
], ){ node('pre-CICD') { stage('build') {

    container('jnlp') {
        stage('git-clone') {
            checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'c33d60bd-67c6-4182-b52c-d7aeebfab772', url: 'http://192.168.176.154/root/base-nop.git']]])
        }

        stage('Build a Maven project') {
            sh 'cd base-nop/fw-base-nop && mvn clean install -DskipTests -Denv=beta'
        }

        stage('build docker image'){
            sh 'cp /tmp/Dockerfile base-nop/fw-base-nop/target/'
            sh '/usr/bin/docker build -t 192.168.176.155/library/fw-base-nop:xxxx --build-arg jar_name="fw-base-nop.jar" base-nop/fw-base-nop/target/'
        }    

        stage('push registry') {
            sh '''
                docker login -u admin -p da88e43d88722c2c9ca09da644eeb015 192.168.176.155
                docker push  192.168.176.155/library/fw-base-nop:xxxx
                docker rmi 192.168.176.155/library/fw-base-nop:xxxx
            '''
        }
    }

}

} }

说明:

PodTemplate(….)配置的Pod模板配置参数以及相关说明在语法章节有过介绍不再过多赘述不过有一点需要注意的是containerTemplate 下的name参数和image参数的设定。

Jenkins的Agent大概分两种 一是基于SSH的由master主动连接slave/Agent节点 二是基于JNLP的使用的是HTTP协议由Agent/slave节点主动连接master节点每个Agent需要配置一个独特的secret。 可以参考官方说明。

1、 如果name参数配置的值为jnlp就表示使用基于Jnlp方式的jnlp-agent自启动连接Jenkins master。这就需要保证image参数指定的镜像里包含启动jnlp-agent的命令官方提供的镜像启动命令为jenkins-slave旧版本或者jenkins-agent新版本命令同时需要指定启动参数${computer.jnlpmac} ${computer.name如果指定的镜像里没有这些命令或者没有启动参数动态pod就会创建失败。

2、 如果name参数配置的值不是jnlp而image参数指定的镜像为jnlp agent镜像时动态pod也会生成失败。这是因为当该参数设置的值不是jnlp时动态生成的pod默认会启动两个容器使用的镜像一个是连接jenkins master默认的jnlp-agent镜像也就是jnlp-slave:3.35-5-alpine另一个就是通过image参数自定义的镜像。这两个jnlp-agent镜像启动时都会去连接jenkins master而基于jnlp方式使用agent时每个客户端只能有一个agent和一个secret所以同时启动多个jnlp-agent就会导致Pod启动失败。

3、 如果name参数配置的值不是jnlp并且image参数指定的镜像为非jnlp agent镜像时需要注意此时启动容器时的参数应该去掉同上面一样动态生成的pod包含两个容器一个名称是jnlp根据默认的jnlp agent镜像默认在后台启动一个名称是通过name参数设置的值同时两个容器都能作为pipeline脚本执行的环境使用时都是通过container('container_name')引用。

4、 如果Pod内有多个容器并且只要有一个容器为jnlp容器其他容器的名称和镜像使用没有限制也就是说容器名称可以不是jnlp但是镜像可以jnlp agent镜像。

5、上面示例里的image参数配置的镜像为根据默认的jnlp-agent镜像自定义的镜像dockerfile如下

FROM jenkins/jnlp-slave:3.35-5-alpine

USER root

RUN apk add maven git

COPY settings.xml /usr/share/java/maven-3/conf/settings.xml COPY docker/docker /usr/bin/docker

其中settings.xml文件为maven配置文件这里需要根据实际情况考虑要不要添加。

执行结果如下:

声明式脚本

对于该pipeline脚本相应的声明式语法如下

pipeline { agent { kubernetes { yaml """ apiVersion: v1 kind: Pod metadata: labels: some-label: some-label-value namespace: 'default' spec: containers:

  • name: jnlp image: 192.168.176.155/library/jenkins-slave:latest args: ['$(JENKINS_SECRET)', '$(JENKINS_NAME)'] tty: true privileged: true alwaysPullImage: false volumeMounts:

    • name: mount-nfs mountPath: /tmp
    • name: mount-docker mountPath: /var/run/docker.sock volumes:
  • name: mount-nfs nfs: path: /data/nfs server: 192.168.177.43

  • name: mount-docker hostPath: path: /var/run/docker.sock """ } } stages { stage('Run maven') { steps { container('jnlp') { checkout([$class: 'GitSCM', branches: name: '*/master', doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: credentialsId: 'c33d60bd-67c6-4182-b52c-d7aeebfab772', url: 'http://192.168.176.154/root/base-nop.git'])" } } } stage('build code') { steps { container('jnlp') { sh 'cd base-nop/fw-base-nop && mvn clean install -DskipTests -Denv=beta' } }

    }

    stage('build image'){ steps{ container('jnlp') { sh 'cp /tmp/Dockerfile base-nop/fw-base-nop/target/' sh '/usr/bin/docker build -t 192.168.176.155/library/fw-base-nop:xxxx --build-arg jar_name="fw-base-nop.jar" base-nop/fw-base-nop/target/' } } }

    stage('push to registry') { steps { container('jnlp') { sh ''' docker login -u admin -p da88e43d88722c2c9ca09da644eeb015 192.168.176.155 docker push 192.168.176.155/library/fw-base-nop:xxxx docker rmi 192.168.176.155/library/fw-base-nop:xxxx ''' } } } } }

说明:

声明式pipeline语法对于格式有严格要求所以如果遇到有语法错误的情况需要有耐心排查。

使用kubernetes插件时使用脚本式流水线语法相对于声明式语法要更加简单所以建议使用脚本式语法。

Config File Provider Plugin

关于maven配置文件settings.xml的使用还有另一种方式就是通过jenkins的Config File Provider Plugin插件。这个插件的作用就是在 Jenkins 中存储以properties、xml、json、Groovy结尾的文件以及Maven settings.xml内容。下面演示一下如何使用该插件。

点击”系统管理—>Managed files—>Add a new Config—>Global Maven settings.xml“将上面setting.xml文件的内容放到”Content”对应的输入框里如下所示

编辑好提交即可。

然后使用片段生成器configfileProvider:...根据配置的maven settings.xml文件生成语法片段比如

配置好后就可以编辑pipeline脚本了为了测试该插件的作用我直接使用docker hub官方的maven镜像脚本如下

podTemplate(cloud: 'kubernetes', label: 'pre-CICD', containers: [ containerTemplate( name: 'maven', image: "maven:latest", command: 'cat', ttyEnabled: true, privileged: true, alwaysPullImage: false) ], volumes: [ nfsVolume(mountPath: '/tmp', serverAddress: '192.168.177.43', serverPath: '/data/nfs', readOnly: false), hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), ], ){ node('pre-CICD') {

stage('build') {
    container('maven') {
        stage('clone code') {
            sh "git clone http://root:[email protected]/root/base-nop.git"
        }
        configFileProvider([configFile(fileId: 'f67fdaf1-4b17-4caa-86ad-e841f387ac7a', targetLocation: 'settings.xml')]) {
            stage('Build project') {
                sh 'cd base-nop/fw-base-nop && mvn clean install -DskipTests -Denv=beta --settings ${WORKSPACE}/settings.xml'
            }
        }

    }
}

}

}

说明:

通过mvn命令编译代码时加上--settings参数用于指定该文件。上面示例可以看到在指定settings.xml文件时添加了该job的workspace路径这是因为在使用configFileProvider插件时该插件默认会将指定的settings.xml文件拷贝到job的workspace目录下如果不添加路径有可能会报该文件找不到的错误。

基础版的持续交付脚本就算是完成了。此版本的脚本只是为了让大家熟悉一下代码编译和镜像构建的一个基本流程,下面的版本将会该该版本进行一个简单的优化。继续往下看。

进阶版

说明(相对上一个版本):

1、 本次版本开始引入变量,以提高灵活性。需要注意的是,引用变量的时候要使用双引号(“”)。- 2、 将脚本内部分命令通过kubernetes插件和Docker插件内的相关方法实现。- 3、 挂载共享目录用于挂载maven的.m2仓库提高代码编译效率。

首先,用代码片段生成器生成部分命令的相关语法片段:

checkoutCheck out from version control生成拉取代码的片段前面有介绍过不在过多说明。

使用docker pipeline插件的withDockerRegistry片段生成器生成对docker Registry认证的语法片段如下所示

pipeline脚本如下

def project_name = 'fw-base-nop' def registry_url = '192.168.176.155'

podTemplate(cloud: 'kubernetes',namespace: 'default', label: 'pre-CICD', , containers: [ containerTemplate( name: 'jnlp', image: "192.168.176.155/library/jenkins-slave:latest", args: '${computer.jnlpmac} ${computer.name}', ttyEnabled: true, privileged: true, alwaysPullImage: false, ), ], volumes: [ nfsVolume(mountPath: '/tmp', serverAddress: '192.168.177.43', serverPath: '/data/nfs', readOnly: false), nfsVolume(mountPath: '/root/.m2', serverAddress: '192.168.177.43', serverPath: '/data/nfs/.m2', readOnly: false), hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
], nodeSelector: 'kubernetes.io/hostname=192.168.176.160', ){ node('pre-CICD') { stage('build') { container('jnlp') { stage('clone code') { checkout([$class: 'GitSCM', branches: name: '*/master', doGenerateSubmoduleConfigurations: false, userRemoteConfigs: credentialsId: 'c33d60bd-67c6-4182-b52c-d7aeebfab772', url: 'http://192.168.176.154/root/base-nop.git'])

                script {
                    imageTag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                }
                echo "${imageTag}"
            }

            stage('Build a Maven project') {
                sh "cd ${project_name} && mvn clean install -DskipTests -Denv=beta"
            }

            withDockerRegistry(credentialsId: 'auth_harbor', url: 'http://192.168.176.155') {
                stage('build and push docker image') {
                    sh "cp /tmp/Dockerfile ${project_name}/target/"
                    def customImage = docker.build("${registry_url}/library/${project_name}-${BUILD_NUMBER}:${imageTag}","--build-arg jar_name=${project_name}.jar ${project_name}/target/")
                    echo "推送镜像"
                    customImage.push()
                }
                stage('delete image') {
                    echo "删除本地镜像"
                    sh "docker rmi -f ${registry_url}/library/${project_name}-${BUILD_NUMBER}:${imageTag}"
                }   
            }
        }
    }

} }

说明

volumes配置中挂载maven的.m2仓库到nfs server上以提高代码编译速度。

clone code阶段获取应用代码最后提交时的commit short id作为镜像构建时的tag。

使用docker pipeline语法进行镜像的构建和推送到仓库操作。

nodeSelector 用来选择一台固定的节点专门用来进行构建工作以防止在拉取基础镜像时生成pod过慢影响效率这里我使用了node节点默认自带的标签如果不想用这个标签也可以自定义一个标签。

该版本同样使用pipeline script的方式将脚本代码直接放到了job中。实际工作中我们也可以将上面的代码放到Jenkinsfile文件中并将该文件放到应用代码仓库的根目录也可以单独放置在配置pipeline job时使用pipeline script from SCM的方式配置该Jenkinsfile的仓库地址拉取后会自动进行构建。比如

执行后会自动拉取该文件并执行。需要说明的是如果该文件放到了应用代码仓库的根目录拉取该文件时并不会拉取代码所以在Jenkinsfile中拉取代码的操作是不能去掉的。

对应的声明式脚本只需要在版本一的基础上替换做了更改的部分并将用到的docker pipeline插件的方法加上script{}块即可。

在Cloud中定义PodTemplate

版本说明:

前两个版本的PodTemplate配置均通过在pipeline中使用代码的方式进行配置的本次版本将PodTemplate配置通过Jenkins UI放到了全局配置里。

编辑最开始“配置Jenkins连接kubernetes”时创建的cloud增加PodTemplate和container的配置。如下所示

上面配置的参数说明应该不用再重复介绍了有不懂的参数可以参考之前的文章即可。配置保存后修改pipeline只需要将PodTemplate方法配置的部分去掉即可。

pipeline如下

def project_name = 'fw-base-nop' //项目名称 def registry_url = '192.168.176.155' //镜像仓库地址

//node 这里依旧是填写podtemplate设置的标签的名称 node('pre-CICD') { stage('build') {

        container('jnlp') {
            stage('git-clone') {
                checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, userRemoteConfigs: [[credentialsId: 'c33d60bd-67c6-4182-b52c-d7aeebfab772', url: 'http://192.168.176.154/root/base-nop.git']]])

                script {
                    imageTag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                }
                echo "${imageTag}"
            }

            stage('Build a Maven project') {
                sh "cd ${project_name} && mvn clean install -DskipTests -Denv=beta"
            }

            withDockerRegistry(credentialsId: 'auth_harbor', url: 'http://192.168.176.155') {
                stage('build and push docker image') {
                    sh "cp /tmp/Dockerfile ${project_name}/target/"
                    def customImage = docker.build("${registry_url}/library/${project_name}-${BUILD_NUMBER}:${imageTag}","--build-arg jar_name=${project_name}.jar ${project_name}/target/")
                    echo "推送镜像"
                    customImage.push()
                }
                stage('delete image') {
                    echo "删除本地镜像"
                    sh "docker rmi -f ${registry_url}/library/${project_name}-${BUILD_NUMBER}:${imageTag}"
                }
            }
        }
    }

}

同版本2一样在配置pipeline类型的job时该脚本既可以通过Pipeline script的方式使用也可以通过Pipeline script from SCM的方式使用。

同时,在使用其他类型(比如 自由风格类型、maven类型的job时也能够使用该PodTemplate方法用于动态生成slave。比如创建一个自由风格类型的job配置job时勾选 Restrict where this project can be run 在显示的Label Expression 输入框里输入我们上边配置PodTemplate时设定的标签Labels 名称 pre-CICD即可。

构建job时就会自动启动这个代理如下所示

需要注意的是如果使用这种方式的话pipeline中的代码就不在适合此job需要通过编写shell脚本或者其他方式比如ansible实现持续交付。

sonarqube

既然是持续交付那么肯定少不了代码分析。上面一系列版本只是将代码进行了编译和构建正常流程还需要进行代码质量分析这就用到了之前搭建的sonarqube平台。关于sonarqube在前面的文章有详细介绍这里不重复说明接下来主要看一下如何在pod中使用sonar-scanner命令。

使用sonar-scanner命令既可以使用在Jenkins UI中配置的sonar-scanner命令工具也可以通过自定义sonar-scanner容器镜像的方式引用此命令。下面对这两种方法分别进行介绍。

首先看一下使用jenkins系统内配置的sonar-scanner工具PodTemplate配置同上实现代码质量分析。

def project_name = 'fw-base-nop' //项目名称 def registry_url = '192.168.176.155' //镜像仓库地址

node('pre-CICD') { stage('build') {
stage('git-clone') { container('jnlp'){ stage('clone code'){ checkout([$class: 'GitSCM', branches: name: '*/master', doGenerateSubmoduleConfigurations: false, userRemoteConfigs: credentialsId: 'c33d60bd-67c6-4182-b52c-d7aeebfab772', url: 'http://192.168.176.154/root/base-nop.git']) script { imageTag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim() } echo "${imageTag}" } stage('Build a Maven project') { echo "${project_name}" sh "cd ${project_name} && mvn clean install -DskipTests -Pproduct -U" } } }

    stage('sonar'){
        def sonarqubeScannerHome = tool name: 'sonar-scanner-4.2.0'
        withSonarQubeEnv(credentialsId: 'sonarqube') {
            sh "${sonarqubeScannerHome}/bin/sonar-scanner -X "+
            "-Dsonar.login=admin " +
            "-Dsonar.language=java " + 
            "-Dsonar.projectKey=${JOB_NAME} " + 
            "-Dsonar.projectName=${JOB_NAME} " + 
            "-Dsonar.projectVersion=${BUILD_NUMBER} " + 
            "-Dsonar.sources=${WORKSPACE}/fw-base-nop " + 
            "-Dsonar.sourceEncoding=UTF-8 " + 
            "-Dsonar.java.binaries=${WORKSPACE}/fw-base-nop/target/classes " + 
            "-Dsonar.password=admin " 
        }
    }
    withDockerRegistry(credentialsId: 'auth_harbor', url: 'http://192.168.176.155') {
        stage('build and push docker image') {
            sh "cp /tmp/Dockerfile ${project_name}/target/"
            def customImage = docker.build("${registry_url}/library/${project_name}-${BUILD_NUMBER}:${imageTag}","--build-arg jar_name=${project_name}.jar ${project_name}/target/")
            echo "推送镜像"
            customImage.push()
        }
        stage('delete image') {
            echo "删除本地镜像"
            sh "docker rmi -f ${registry_url}/library/${project_name}-${BUILD_NUMBER}:${imageTag}"
        }
    }
}

}

该示例通过tool指令指定了在jenkins的global tool configuration里配置的sonar-scanner环境变量并赋给一个变量通过withSonarQubeEnv片段生成器对sonar认证并进行代码分析操作。有关sonar-scanner命令各参数的说明在”基础工具配置”章节有做介绍这里不在过多说明。

使用sonar-scanner自定义镜像

除了使用jenkins系统配置sonar-scanner工具也可以根据sonar-scanner工具自定义一个sonar-scanner镜像并使用该镜像启动一个容器来进行代码分析工作。

sonar-scanner镜像默认可以从docker hub上获取但是为了杜绝不必要的错误测试中曾经遇到过我选择了自定义。可以使用之前定义好的jnlp-agent镜像作为基础镜像这样在持续交付步骤使用一个镜像就可以完成所有工作有些人觉得这样会使镜像臃肿也可以使用一个包含jdk的小体积镜像作为基础镜像当然也可以根据自己的实际情况自定义。

无论使用哪种镜像,都需要修改${SONAR-SCANER_HOME}/bin/sonar-scanner文件下的use_embedded_jre参数的值默认为true需要改成fasle如下

use_embedded_jre=false

为什么要修改此参数呢是因为use_embedded_jre参数为true时sonar-scanner命令默认会使用自己提供的jre路径为$sonar_scanner_home/jre而不会使用系统环境下的jre所以需要将此参数改为false否则会报找不到java环境变量的错误如下所示

sonar-scanner:exec: line 73: xxx/sonar-scanner-4.2.0-linux/jre/bin/java: not foun

修改好后编辑dockerfile比如使用上面构建的jnlp-agent镜像作为基础镜像。

FROM 192.168.176.155/library/jenkins-slave:latest COPY sonar-scanner-4.2.0/ /opt/sonar-scanner-4.2.0/

ENV SONAR_SCANNER_HOME /opt/sonar-scanner-4.2.0/ ENV SONAR_RUNNER_HOME ${SONAR_SCANNER_HOME} ENV PATH $PATH:${SONAR_SCANNER_HOME}/bin

如果想使用openjdlk镜像作为基础镜像可以将基础镜像修改为openjdk:8-jre-alpine3.7,编辑好构建即可。

使用docker命令测试一下。

docker run -it --rm 192.168.176.155/library/jenkins-slave:sonar sonar-scanner

输出如下信息表示镜像构建成功 。

$ docker run -it --rm a9592584d82d sonar-scanner INFO: Scanner configuration file: /opt/sonar-scanner-4.2.0/conf/sonar-scanner.properties INFO: Project root configuration file: NONE INFO: SonarQube Scanner 4.2.0.1873 INFO: Java 1.8.0_212 IcedTea (64-bit) INFO: Linux 5.4.13-1.el7.elrepo.x86_64 amd64 INFO: User cache: /root/.sonar/cache INFO: SonarQube server 6.7.5

......

构建好镜像对pipeline脚本进行简单修改为了区分显示又新添加一个containerTemplate配置用于定义sonar镜像同时在引用镜像时新增了一个container指令用于引用新镜像。如下示例

def project_name = 'fw-base-nop' //项目名称 def registry_url = '192.168.176.155' //镜像仓库地址

podTemplate(cloud: 'kubernetes',namespace: 'default', label: 'pre-CICD', serviceAccount: 'default', containers: [ containerTemplate( name: 'jnlp', image: "192.168.176.155/library/jenkins-slave:latest", args: '${computer.jnlpmac} ${computer.name}', ttyEnabled: true, privileged: true, alwaysPullImage: false, ), containerTemplate( name: 'sonar', image: "192.168.176.155/library/jenkins-slave:sonar", ttyEnabled: true, privileged: true, command: 'cat', alwaysPullImage: false, ), ], volumes: [ nfsVolume(mountPath: '/tmp', serverAddress: '192.168.177.43', serverPath: '/data/nfs', readOnly: false), hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'), nfsVolume(mountPath: '/root/.m2', serverAddress: '192.168.177.43', serverPath: '/data/nfs/.m2', readOnly: false), ], ){ node('pre-CICD') { stage('build') { container('jnlp'){ stage('clone code'){ checkout([$class: 'GitSCM', branches: name: '*/master', doGenerateSubmoduleConfigurations: false, userRemoteConfigs: credentialsId: 'c33d60bd-67c6-4182-b52c-d7aeebfab772', url: 'http://192.168.176.154/root/base-nop.git']) script { imageTag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim() } echo "${imageTag}" } stage('Build a Maven project') { echo "${project_name}" sh "cd ${project_name} && mvn clean install -DskipTests -Pproduct -U" } }

    container('sonar'){
        stage('sonar test'){
            withSonarQubeEnv(credentialsId: 'sonarqube') {
                sh "sonar-scanner -X "+
                "-Dsonar.login=admin " +
                "-Dsonar.language=java " + 
                "-Dsonar.projectKey=${JOB_NAME} " + 
                "-Dsonar.projectName=${JOB_NAME} " + 
                "-Dsonar.projectVersion=${BUILD_NUMBER} " + 
                "-Dsonar.sources=${WORKSPACE}/fw-base-nop " + 
                "-Dsonar.sourceEncoding=UTF-8 " + 
                "-Dsonar.java.binaries=${WORKSPACE}/fw-base-nop/target/classes " + 
                "-Dsonar.password=admin " 
            }
        }
   }
   withDockerRegistry(credentialsId: 'auth_harbor', url: 'http://192.168.176.155') {
        stage('build and push docker image') {
            sh "cp /tmp/Dockerfile ${project_name}/target/"
            def customImage = docker.build("${registry_url}/library/${project_name}:${imageTag}-${BUILD_NUMBER}","--build-arg jar_name=${project_name}.jar ${project_name}/target/")
            echo "推送镜像"
            customImage.push()
        }
        stage('delete image') {
            echo "删除本地镜像"
            sh "docker rmi -f ${registry_url}/library/${project_name}:${imageTag}-${BUILD_NUMBER}"
        }
    }
}

}
}

有关jenkins与kubernetes集成持续交付的配置就简单的介绍到这里下一章节内容介绍一下将代码持续部署到kubernetes集群中。