Jenkinsfile说明

木木1年前技术文章550

当我们在使用jenkins进行CI/CD的时候,简单的内容我们可以通过jenkins页面来实现配置。但是如果有复杂的需求还是需要通过jenkinsfile来实现

jenkinsfile简单介绍

Jenkinsfile使用两种语法进行编写,分别是声明式和脚本式。下面我们会用声明式的写法来提供一个jenkinsfile,并进行说明

Jenkinsfile模板

pipeline {
    agent {
        kubernetes {
            yaml '''
        apiVersion: v1
        kind: Pod
        metadata:
          labels:
            jenkinsci: jenkins-golang
        spec:
          containers:
          - name: golang
            image: golang:1.18.3-bullseye
            tty: true
          - name: kaniko
            image: registry.cn-hangzhou.aliyuncs.com/cefso/kaniko-project.executor:debug
            command: ["/busybox/cat"]
            tty: true
          - name: kubelet
            image: registry.cn-hangzhou.aliyuncs.com/cefso/kubectl:v1.23.1
            command: ["cat"]
            tty: true
        '''
        }
    }

    environment {
        PROJECT_NAME = "${JOB_NAME.split('/')[0]}"
        VSERSION = "${BRANCH_NAME.replace('_', '-')}-${BUILD_ID}"
    }


    stages {
        stage('git clone') {
            steps {
                checkout scm
            }
        }
        stage('format & test') {
            steps {
                container('golang') {
                    sh 'go fmt $(go list ./... | grep -v /vendor/)'
                    sh 'go vet $(go list ./... | grep -v /vendor/)'
                    sh 'go test -race $(go list ./... | grep -v /vendor/)'
                }
            }
        }
        stage('build') {
            steps {
                container('golang') {
                    sh 'mkdir -p mybinaries'
                    sh 'go build -o mybinaries/mybin-${VSERSION}  ./...'
                }
            }
        }
        stage('archiveArtifacts') {
            steps {
                archiveArtifacts artifacts: 'mybinaries/*', followSymlinks: false
            }
        }
        stage('build images') {
            steps {
                container('kaniko') {
                    sh 'mkdir -p /kaniko/.docker'
                    sh 'export IFS=\'\''
                    withCredentials([usernamePassword(credentialsId: 'aliyunRegistry', usernameVariable: 'CI_REGISTRY_USER', passwordVariable: 'CI_REGISTRY_PASSWORD')]) {
                        sh '''
                            echo 'diable bash debug'
                            set +x
                            echo "{\\"auths\\":{\\"registry.cn-hangzhou.aliyuncs.com\\":{\\"auth\\":\\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d \'\\n\')\\"}}}" > /kaniko/.docker/config.json
                            set -x
                            echo 'enable bash debug'
                            '''
                    }
                    sh '''
                        /kaniko/executor \
                        --context "${WORKSPACE}" \
                        --build-arg "version=${VSERSION}" \
                        --dockerfile "${WORKSPACE}/Dockerfile" \
                        --destination "registry.cn-hangzhou.aliyuncs.com/cefso/${PROJECT_NAME}:${VSERSION}" \
                        --force
                        '''
                }
            }
        }
        stage('deploy') {
            steps {
                container('kubelet') {
                    withKubeConfig(credentialsId: 'jenkins-robot-secret', serverUrl: 'https://172.16.0.30:6443')  {
                        sh 'kubectl get pods -A'
                    }
                }
            }
        }
    }
}

jenkinsfile详解

agent部分和pod模板

jenkinsfile内容

        kubernetes {
            yaml '''
        apiVersion: v1
        kind: Pod
        metadata:
          labels:
            jenkinsci: jenkins-golang
        spec:
          containers:
          - name: golang
            image: golang:1.18.3-bullseye
            tty: true
          - name: kaniko
            image: registry.cn-hangzhou.aliyuncs.com/cefso/kaniko-project.executor:debug
            command: ["/busybox/cat"]
            tty: true
          - name: kubelet
            image: registry.cn-hangzhou.aliyuncs.com/cefso/kubectl:v1.23.1
            command: ["cat"]
            tty: true
        '''
        }
    }

我们这里使用了jenkins的kubernetes插件,并且jenkins是部署在k8s集群中的,所以无需额外配置即可将我们的构建放入到kubernetes集群中以pod的形式运行。如果jenkins没有安装到k8s集群中则需要手动配置才能以pod的形式进行构建。

kubernetes插件查考文档

https://plugins.jenkins.io/kubernetes/

配置的位置如下

系统管理-节点管理

configure clouds

在这里配置连接到k8s集群即可

这里我们通过yaml文件的形式定义了我们构建时使用的pod信息,pod包含3个容器

        apiVersion: v1
        kind: Pod
        metadata:
          labels:
            jenkinsci: jenkins-golang
        spec:
          containers:
          # 容器1,名称golang,镜像为golang:1.18.3-bullseye
          - name: golang
            image: golang:1.18.3-bullseye
            tty: true
          # 容器1,名称kaniko,镜像为registry.cn-hangzhou.aliyuncs.com/cefso/kaniko-project.executor:debug
          - name: kaniko
            image: registry.cn-hangzhou.aliyuncs.com/cefso/kaniko-project.executor:debug
            command: ["/busybox/cat"]
            tty: true
          # 容器1,名称kubelet,镜像为registry.cn-hangzhou.aliyuncs.com/cefso/kubectl:v1.23.1
          - name: kubelet
            image: registry.cn-hangzhou.aliyuncs.com/cefso/kubectl:v1.23.1
            command: ["cat"]
            tty: true

其中

  • golang的容器是用来进行代码的构建等操作的,如果后续需要构建java应用就可以调整为maven的镜像来使用

  • kaniko容器用来构建我们的docker镜像(这部分可以通用)

  • kubelet容器是用来做应用的部署的(这部分也可以通用)

这里需要注意我们的每个容器都有不同的名字,后续我们可以通过容器的名字来指定我们当前的pipeline步骤运行在那个容器中

环境变量配置

我们将后续常用的一些环境变量进行配置,方便后续的使用

    environment {
        PROJECT_NAME = "${JOB_NAME.split('/')[0]}"
        VSERSION = "${BRANCH_NAME.replace('_', '-')}-${BUILD_ID}"
    }

克隆代码

这里我们使用了jenkinsfile的一个语法,这里的checkout scm是在多分支流水线中最常用的一个语法。jenkins会根据我们的现在正在构建的分支来克隆相关代码。

        stage('git clone') {
            steps {
                // 克隆当前分支代码(即我们构建的是那个分支就克隆那个分支的代码)
                checkout scm
            }
        }

格式化代码和测试

这里是golang代码常用的一个步骤,对代码进行格式化和测试

        stage('format & test') {
            steps {
                container('golang') {
                    sh 'go fmt $(go list ./... | grep -v /vendor/)'
                    sh 'go vet $(go list ./... | grep -v /vendor/)'
                    sh 'go test -race $(go list ./... | grep -v /vendor/)'
                }
            }
        }

这里我们需要注意一段代码

                container('golang') {
                    // ***
                }

还记的我们上面说我们可以使用指定的容器来进行pipeline的操作,这里我们就通过container的语法来指定了当前操作的步骤是在golang的容器中运行

构建

这部分没什么好说的,正常的构建代码

        stage('build') {
            steps {
                container('golang') {
                    sh 'mkdir -p mybinaries'
                    sh 'go build -o mybinaries/mybin-${VSERSION}  ./...'
                }
            }
        }

产物

产物是经常被忽略的部分。但是通过产物功能,我们可以很方便的在页面上下载好构建的成品,无论是进行测试,还是部署问题排查都会很方便。尤其是当我们在pod中进行构建,构建完成后pod就会被销毁,此时产物就显得更加重要

        stage('archiveArtifacts') {
            steps {
                archiveArtifacts artifacts: 'mybinaries/*', followSymlinks: false
            }
        }

镜像构建和推送

        stage('build images') {
            steps {
                container('kaniko') {
                    sh 'mkdir -p /kaniko/.docker'
                    sh 'export IFS=\'\''
                    withCredentials([usernamePassword(credentialsId: 'aliyunRegistry', usernameVariable: 'CI_REGISTRY_USER', passwordVariable: 'CI_REGISTRY_PASSWORD')]) {
                        sh '''
                            echo 'diable bash debug'
                            set +x
                            echo "{\\"auths\\":{\\"registry.cn-hangzhou.aliyuncs.com\\":{\\"auth\\":\\"$(printf "%s:%s" "${CI_REGISTRY_USER}" "${CI_REGISTRY_PASSWORD}" | base64 | tr -d \'\\n\')\\"}}}" > /kaniko/.docker/config.json
                            set -x
                            echo 'enable bash debug'
                            '''
                    }
                    sh '''
                        /kaniko/executor \
                        --context "${WORKSPACE}" \
                        --build-arg "version=${VSERSION}" \
                        --dockerfile "${WORKSPACE}/Dockerfile" \
                        --destination "registry.cn-hangzhou.aliyuncs.com/cefso/${PROJECT_NAME}:${VSERSION}" \
                        --force
                        '''
                }
            }
        }

Kaniko

https://github.com/GoogleContainerTools/kaniko

kaniko是谷歌开源的一款用来构建容器镜像的工具。与docker不同,Kaniko 并不依赖于Docker daemon进程,完全是在用户空间根据Dockerfile的内容逐行执行命令来构建镜像,这就使得在一些无法获取 docker daemon 进程的环境下也能够构建镜像,比如在标准的Kubernetes Cluster上。

Kaniko 以容器镜像的方式来运行的,同时需要三个参数: Dockerfile,上下文,以及远端镜像仓库的地址。

Kaniko会先提取基础镜像(Dockerfile FROM 之后的镜像)的文件系统,然后根据Dockerfile中所描述的,一条条执行命令,每一条命令执行完以后会在用户空间下面创建一个snapshot,并与存储与内存中的上一个状态进行比对,如果有变化,就将新的修改生成一个镜像层添加在基础镜像上,并且将相关的修改信息写入镜像元数据中。等所有命令执行完,kaniko会将最终镜像推送到指定的远端镜像仓库。

需要说明几点:

  • args 部分

这部分就是上面所讲的,kaniko运行时需要三个参数: Dockerfile(--dockerfile),上下文(--context),远端镜像仓库(--destination)

  • secret 部分

推送至指定远端镜像仓库需要credential的支持,所以需要将credential以secret的方式挂载到/kaniko/.docker/这个目录下,文件名称为config.json,内容如下:

{   
    "auths": {
        "https://index.docker.io/v1/": {
            "auth": "AbcdEdfgEdggds="
       }
    }
    
}

其中auth的值为: echo"docker_registry_username:docker_registry_password"|base64

部署

这里我们又多了一个语法withKubeConfig,通过这个语法我们可以实现在容器中使用kubectl命令时的鉴权。该语法由Kubernetes CLI插件提供

        stage('deploy') {
            steps {
                container('kubelet') {
                    withKubeConfig(credentialsId: 'jenkins-robot-secret', serverUrl: 'https://172.16.0.30:6443')  {
                        sh 'kubectl set image deployment/${PROJECT_NAME} ${PROJECT_NAME}=registry.cn-hangzhou.aliyuncs.com/cefso/${PROJECT_NAME}:${VSERSION}'
                    }
                }
            }
        }

Kubernetes CLI 参考链接

https://plugins.jenkins.io/kubernetes-cli/

创建jenkins访问集群凭证

创建serviceaccount

kubectl -n default create serviceaccount jenkins-robot

创建clusterrolebinding,我们将权限绑定到cluster-admin上

kubectl -n default create clusterrolebinding jenkins-robot-binding --clusterrole=cluster-admin --serviceaccount=default:jenkins-robot

1.22以上版本集群并不会自动为serviceaccount创建token,所以我们需要手动创建token

kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: jenkins-robot-secret
  annotations:
    kubernetes.io/service-account.name: jenkins-robot
type: kubernetes.io/service-account-token
EOF

获取我们创建的token

kubectl -n default get secrets jenkins-robot-secret -o go-template --template '{{index .data "token"}}' | base64 -d

将token配置到jenkins上

类型选择Secret text,将我们上面获取的token填写到Secret中,后续通过ID调用即可

// 这里credentialsId填写我们上面的ID,serverUrl填写集群api server地址即可
withKubeConfig(credentialsId: 'jenkins-robot-secret', serverUrl: 'https://172.16.0.30:6443')  {
                        // ***
                    }


标签: 运维

相关文章

单节点Kafka部署并开启Kerberos配置

安装Kerberosserver节点安装kerberos相关软件yum install -y krb5-server krb5-workstation krb5-libs修改配置文件krb5.conf...

寻找CPU使用率高进程方法

寻找CPU使用率高进程方法

背景节点报CPU使用率高,需要定位是什么进程占用CPU使用率高。CPU使用率持续较高在对应节点使用 “top”命令,然后键盘输入“P”,即按照CPU使用率排序进程。执行ps -ef | grep &l...

hive创建hbase映射表

hive创建hbase映射表

hbase创建表,导入数据/opt/app/hbase-2.1.0/bin/hbase shell查看已有表,创建新表,查看表结构listcreate 'student', 'info', 'scor...

chengying-6.0登入接口逆向

chengying-6.0登入接口逆向

版本更新首先是登入的加密url:http://172.16.121.70/login参数1. username:admin@dtstack.com2. password:614bb9438210c69...

HBase使用snappy压缩

HBase使用snappy压缩

安装编译环境依赖yum install -y automake autoconf gcc-c++ cmake libedit libtool openssl-devel ncurses-devel安装...

EMR-flinksql运行失败问题

EMR-flinksql运行失败问题

运行flinksqlsql-client.sh报错:[root@emr1 bin]# ./sql-client.shSLF4J: Class path contains multiple SLF4J...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。