learn-tech/专栏/Jenkins持续交付和持续部署/15.JenkinsKubernetesPlugin介绍与语法详解.md
2024-10-16 06:37:41 +08:00

19 KiB
Raw Blame History

                        因收到Google相关通知网站将会择期关闭。相关通知内容
                        
                        
                        15.Jenkins Kubernetes Plugin介绍与语法详解
                        在上一节中介绍了jenkins使用不同的安装方式配置连接kubernetes集群的方法以及简单的示例根据kubernetes插件用途的不同对于插件语法的介绍也会区分开来本节主要介绍一下使用kubernetes集群动态生成Jenkins slave pod的插件Kubernetes plugin。

kubernetes plugin

编写pipeline脚本集成kubernetes插件生成动态slave时对于启动agent代理部分的代码编写根据pipeline语法类型的不同会有所差异。但无论有什么差异有一个核心方法不变那就是PodTemplate顾名思义就是pod的模板。

PodTemplate是使用kubernetes插件生成动态slave节点的核心方法。用于配置启动的agent代理Pod的资源对象定义。熟悉kubernetes的应该都知道kubernetes资源对象pod的定义严格来说主要包含两部分Pod各项配置定义和容器各项配置定义。而在Jenkins中则通过kubernetes插件的PodTemplate()方法,对这两部分进行定义,并启动代理。

下面会根据不同的语法类型分别介绍PodTemplate的配置方法。

基本语法

脚本式语法

首先看一个在脚本式pipeline中使用kubernetes插件的基本语法。

podTemplate(label: 'xxx',cloud:'',<pod_option1>,<pod_option2>,...,containers: [ <containerTemplate(name: 'c1',<container_option1>,<container_option2>...)>, <containerTemplate(<name: 'c2',<container_option1>,<container_option2>...)>, .... ]){ node('xxx'){ stage('test'){ .... } } container('c1') { stage('c1'){ .... } } container('c2') { stage('c2'){ .... } } }

说明:

上面PodTemplate包含两部分

第一部分为对kubernetes资源对象Pod自身的一些定义包括pod的标签pod的名称使用的云cloud名称挂载的volume等。

第二部分container为对该pod下container的定义。container是一个列表可以包含一个或多个containerTemplate用于详细描述container的配置参数比如镜像地址容器名称镜像拉取策略等。

podTemplate()定义了一个label名称该lable用于在node()中引用用于生成一个唯一的pod名称。

containerTemplate()定义了该container的名称用于作为流水线执行的环境通过container('container_name')引用给容器。

声明式语法

相对于脚本式语法声明式的语法就显得相对比较混乱。是因为声明式最基础的配置是将kubernetes中资源对象pod的定义的内容通过yaml方式直接放到流水线脚本中如下所示(只展示了部分定义)。

pipeline { agent { kubernetes { label <label_name> yaml """ kind: Pod metadata: name: <pod_name> spec: containers: - name: <container_name> image: <image_name> imagePullPolicy: IfNotPresent command: - xxxx tty: true volumeMounts: .... restartPolicy: Never volumes: ...... """ } } stages { stage('one') { steps { container('container_name') { } container('container_name') { } } steps { sh 'hostname' } }
}

说明

agent{}代理配置使用kubernetes关键字通过yaml指令将yaml文件内容直接放到PodTemplate中。

在不同的stage中引用容器的方式也是通过container('container_name')语法格式。

以上便是使用脚本式与声明式流水线集成kubernetes插件动态生成jenkins slave节点的基础语法。需要说明的是对于PodTemplage方法中Pod Template和Container Tempalte的配置既可以在常规的Jenkins UI中配置也可以在pipeline script中通过脚本定义配置信息。本节主要介绍在pipeline script中使用脚本的方式定义PodTemplate在Jenkins UI中配置PodTemplate的方法将在以后介绍并且如果会使用脚本定义PodTemplate后在Jenkins UI中配置相对会简单一些。

参数说明

PodTemplate()既然是方法那么肯定会涉及到参数配置所以接下来先了解一下PodTemplate方法的参数配置为了区分pod配置和container配置下面会将PodTemplate()总体配置拆分为Pod Template配置和container Template配置分别进行说明。

Pod Template 配置部分参数说明- cloud 用来指定在jenkins的系统配置中设置的云名称默认为kubernetes。在上一节中对于该设置已经做个说明这里不在重复介绍。

name pod名称。

namespace pod运行的namespace命名空间

label pod的标签. 可以自己定义,也可以使用插件内置的 POD_LABEL 变量。

yaml Pod定义的yaml表现形式可参考kubernetes官网。

yamlMergeStrategy 包含merge() 和 override()属性。控制yaml定义是覆盖还是与从声明或者继承的pod模板的yaml定义合并。默认为override()。

containers Pod内容器模板的定义。

serviceAccount Pod使用的服务账户。

nodeSelector 生成的Pod绑定到的node节点以keyvalue的形式表现。

nodeUsageMode 包括NORMAL和EXCLUSIVE两个值它控制Jenkins在选择到这个代理的方式是只有指定该节点标签时使用这个节点还是尽可能多地使用该节点。

volumes 定义的数据卷用于pod和所有容器。

envVars应用于所有容器的环境变量。

envVar 可以理解为在pipeline内定义的环境变量。

secretEnvVar secret变量其值是从Kubernetes 的secret获取的。

imagePullSecrets 一个存放私有仓库认证信息的secret用于从私有仓库拉取镜像时对私有仓库认证。

annotationsPod的注解。

InheritFrom继承的一个或多个Pod模板的列表。

slaveConnectTimeout 代理pod连接jenkins的超时时间以秒为单位__。

podRetention 控制保留Pod的行为用户设置在agent执行完毕后是否保留该pod。有多个选项可以是never()onFailure()always()或default()。如果为空则默认为在经过activeDeadlineSeconds指定的时间之后删除pod 。

activeDeadlineSeconds :如果 podRetention 参数设置为never() 或者 onFailure()pod经过该参数设置的时间后会自动删除。

idleMinutes 允许Pod保持活动状态以供重用直到时间达到从开始执行到经过该值设置时间为止默认为分钟。

showRawYaml 启用或禁用原始yaml文件的输出。默认为true。

runAsUser 用于设置Pod中所有容器运行的用户ID。

runAsGroup 用于设置Pod中所有容器运行的组ID。

hostNetwork 使用宿主机网络类似docker中的network=host。

workspaceVolume 用于工作空间的卷的类型。也就是kubernetes中volume的挂载类型可以是

emptyDirWorkspaceVolume (default)- dynamicPVC()- hostPathWorkspaceVolume()- nfsWorkspaceVolume()- persistentVolumeClaimWorkspaceVolume()

container Template配置部分参数说明

name :容器名称。- image :容器使用的镜像。- envVars应用于容器的环境变量补充和覆盖在pod级别设置的envvar。- envVar :同上。- secretEnvVar :同上。- command :容器要执行的命令。- args :执行命令要传的参数。- ttyEnabled 标记容器开启tty。- livenessProbe :容器探针。- ports :容器端口。- alwaysPullImage :拉取镜像策略- runAsUser 用于运行容器的用户ID。- runAsGroup 用于运行容器的用户组ID。.

上面的参数对于脚本式和声明式pipeline都是适用的。对于声明式的语法也可以通过在前面介绍的片段生成器生成相应的PodTemplate语法片段。

有关Pod Template和Container Template的更多参数可以参考kubernetes中资源对象pod的yaml定义默认情况下Pod中支持的参数在pipeline中都是可以使用的。

了解了基本语法,下面通过一些基本的示例来加深一下理解。

语法示例

针对脚本式语法和声明式语法的不同,对于示例也会分开介绍。

脚本式语法

基础示例如下:

podTemplate { node(POD_LABEL) { stage('Run shell') { sh 'echo hello world' } } }

说明

对于脚本式语法node()块是被包含在PodTemplate方法里的。

该示例会启动一个kubernetes Pod并输出hello world。

node(POD_LABEL) POD_LABEL用于给pipeline的agent代理(kubernetes pod)指定一个标签确保pod名称的唯一性这个标签可以自定义通过podTemplate 的label参数指定也可以像上面示例一样使用POD_LABEL这个是在kubernetes plugin插件的1.17及以后版本添加的功能用于自动生成pod 标签,标签的格式为${JOB_NAME)-${BUILD_NUMBER}-hash_number。

通过上面的示例会发现PodTemplate既没有定义Pod参数配置也没有定义container的参数配置。在没有配置这些参数的情况下pipeline会使用默认的PodTemplate配置在执行上面的pipeline后Jenkins的构建日志中会列出该Pod的yaml定义可参考上面最初的示例包括镜像版本jenkins的环境变量等。由于是默认的配置对我们编写pipeline 持续交付脚本帮助不大我们需要自己定义Pod运行参数所以这里就不在重复介绍默认的pod定义。有兴趣的可以执行上面的示例结果会通过jenkins的console日志显示出来。

对于上面的基础示例可以添加container参数用来自定义pod内容器的启动参数比如

podTemplate(containers: […]) { node(POD_LABEL) { stage('Run shell') { container('mycontainer') { sh 'echo hello world' } } } }

该示例中container参数定义了启动容器用到的镜像配置模板在不填写container参数的情况默认的jnlp代理(container)的配置参数如下所示:

containerTemplate(name: 'jnlp', image: 'jenkins/jnlp-slave:3.35-5-alpine', args: '${computer.jnlpmac} ${computer.name}')

需要注意的是:

对于${computer.jnlpmac} ${computer.name}这两个参数是jnlp-agent该示例为jnlp-slave:3.35-5-alpine镜像运行必须的参数如果不写或少写一个都会导致slave pod生成失败。

另一个要说明的点是该contianer的名称实际工作中我们可能需要使用自己定义的一些镜像这些镜像如果是jnlp-agent类型启动时通过slave agent包启动并连接Jenkins master节点的镜像则容器名称就必须为jnlp否则有可能会导致pod生成失败至于原因将在下一章节进行说明。

对于默认的jnlp代理(container)相应的声明式语法如下:

apiVersion: v1 kind: Pod spec: containers:

  • name: jnlp image: 'jenkins/jnlp-slave:3.35-5-alpine' args: ['$(JENKINS_SECRET)', '$(JENKINS_NAME)']

通过该示例可以知道上面脚本式语法中的两个参数是做什么用的了吧。如果还不知道可参考jenkins的docker-jnlp-slave

默认的container配置就只包含上面的三个参数nameimageargs除了这些参数外还有一些经常用到的比如用于分配伪终端的ttyEnabled参数、设置拉取镜像策略的alwaysPullImage参数、配置是否使用privileged特权模式的参数、设置容器启动内存和cpu等。

更多与容器相关的参数配置可参考如下示例:

containerTemplate( name: 'mariadb', image: 'mariadb:10.1', ttyEnabled: true, privileged: false, alwaysPullImage: false, workingDir: '/home/jenkins/agent', resourceRequestCpu: '50m', resourceLimitCpu: '100m', resourceRequestMemory: '100Mi', resourceLimitMemory: '200Mi', envVars: [ envVar(key: 'MYSQL_ALLOW_EMPTY_PASSWORD', value: 'true'), secretEnvVar(key: 'MYSQL_PASSWORD', secretName: 'mysql-secret', secretKey: 'password'), ... ], ports: [portMapping(name: 'mysql', containerPort: 3306, hostPort: 3306)] ),

与pod Template相关的参数配置如下

podTemplate(cloud: 'kubernetes', label: 'my-defined', containers: [.... ], volumes: [ emptyDirVolume(mountPath: '/etc/mount1', memory: false), secretVolume(mountPath: '/etc/mount2', secretName: 'my-secret'), configMapVolume(mountPath: '/etc/mount3', configMapName: 'my-config'), hostPathVolume(mountPath: '/etc/mount4', hostPath: '/mnt/my-mount'), nfsVolume(mountPath: '/etc/mount5', serverAddress: '127.0.0.1', serverPath: '/', readOnly: true), persistentVolumeClaim(mountPath: '/etc/mount6', claimName: 'myClaim', readOnly: true) ], namesapce: default, serviceaccount: default, imagePullSecrets: [ 'pull-secret' ], //用于在启动容器时从私有仓库拉取镜像,而无需在宿主机对私有仓库进行认证登录 annotations: [ podAnnotation(key: "my-key", value: "my-value") ... ])

编写pipeline脚本时对于PodTemplate方法中的某个参数如果不知道如何定义都可以参考上面展示的模版范例或者通过在前面的介绍的片段生成器通过jenkins ui定义来生成语法片段。

podTemplate方法的配置除了直接使用key:value方式定义外也可以通过以yamlkubernetes中资源对象文件的默认后缀文件的方式定义比如下面示例

podTemplate(yaml: """ apiVersion: v1 kind: Pod metadata: labels: some-label: some-label-value spec: containers:

  • name: busybox image: busybox command:
    • cat tty: true """ ) { node(POD_LABEL) { container('busybox') { sh "hostname" } } }

除了使用yaml关键字外也可以使用yamlFile关键字用于指定一个yaml文件该文件通常与jenkinsfile文件一起存在于源码仓库中。通过从源码仓库中拉取Jenkinsfile文件和该参数指定的文件下载后会自动执行。这种方式需要改变pipeline job中脚本定义的类型默认使用Pipeline script使用yamlFile的方式就该使用Pipeline script from SCM前面章节有介绍的方式了。

运行多个容器

对于不同的代码要是使用不同的构建环境怎么办在container参数中可以定义多个containerTemplate来满足此需求。也就是在一个pod中运行多个容器熟悉kubernetes的应该都知道同一个pod内的容器共享主机名、网络、vloume等信息所以在pod内运行一个或者多个容器它们之间并没有什么区别。如下示例

podTemplate(label:'test', containers: [ containerTemplate(name: 'maven', image: 'maven:3.3.9-jdk-8-alpine', ttyEnabled: true, command: 'cat'), containerTemplate(name: 'golang', image: 'golang:1.8.0', ttyEnabled: true, command: 'cat') ]) {

node('test') {
    stage('Get a Maven project') {
        git 'https://github.com/jenkinsci/kubernetes-plugin.git'
        container('maven') {
            stage('Build a Maven project') {
                sh 'echo build maven'
            }
        }
    }

    stage('Get a Golang project') {
        git url: 'https://github.com/hashicorp/terraform.git'
        container('golang') {
            stage('Build a Go project') {
                sh 'echo build go'
            }
        }
    }

}

}

说明:

该示例定义多个容器在不同的stage通过定义的容器的名称来使用该容器作为流水线执行的环境。

声明式语法

在声明式语法中使用PodTemplate方法与在脚本式语法中使用该方法的方式基本一致。主要区别在于agent的定义方式上。

首先看一个在声明式脚本中使用PodTemplate的基础示例

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

  • name: maven image: maven:alpine command:
    • cat tty: true
  • name: busybox image: busybox command:
    • cat tty: true """ } } stages { stage('Run maven') { steps { container('maven') { sh 'mvn -version' } container('busybox') { sh '/bin/busybox' } } } } }

说明:

使用声明式脚本agent的type必须是”any, docker, dockerfile, kubernetes, label, none”中的一种本节为kubernetes插件的使用所以agent的type为kubernetes。

kubernetes使用yaml方式定义Pod和container模板配置信息在stage阶段使用container指令指定运行的容器提供流水线执行的环境。

该pod定义未指定pod工作的namespace命名空间这里需要说明一下的是如果yaml定义没有指定namespace则默认使用在jenkins系统配置中添加kubernetes云时指定的namespace如果这里也没设定namespace的名称则默认使用default namespace如果都指定了则默认使用在pipeline脚本中定义的namespace。

上面示例 stage阶段对容器的引用方式与脚本式流水线引用容器的方式一样。

有关yaml更全面的定义可以参考kubernetes中对资源对象pod的定义参考kubernetes官网

除了可以在脚本式语法中使用yamlFile指令外在声明式语法中也可以使用yamlFile指令。如下示例

pipeline { agent { kubernetes { yamlFile 'KubernetesPod.yaml' } } stages { ... } }

说明

示例中指定KubernetesPod.yaml文件与jenkinsfile文件放在同一源码仓库的同级目录下配置job pipeline时使用Pipeline script from SCM。如果指定的kubernetesPod.yaml文件与Jenkinsfile文件没在同一级目录指定该文件时需要加上相对路径。

使用多个容器

默认情况下声明式脚本的模板不会从父模板继承。所以即便在定义了全局agent代理的情况下也可以在指定的stage单独定义agent。

如下示例定义了全局agent也可以在stage定义agent互不影响。

pipeline { agent { kubernetes { label 'parent-pod' yaml """ spec: containers:

  • name: golang image: golang:1.6.3-alpine command:
    • cat tty: true """ } } stages { stage('Run maven') { agent { kubernetes { label 'nested-pod' yaml """ spec: containers:
  • name: maven image: maven:3.3.9-jdk-8-alpine command:
    • cat tty: true """ } } steps { container('maven') { sh 'mvn -version' } } } stage('run go'){ steps { container('golang') { sh 'go --version' } } } } }

以上就是使用kubernetes插件动态生成jenkins slave节点时用到的一些语法示例。在学会了前面jenkins与docker pipeline插件集成的语法及示例后对于本章节的内容学习应该相对简单很多。

有关在jenkins ui中定义PodTemplate以及自定义image镜像等内容会在下一章以实际案例的方式说明。