08 使用groovy函数

前面将所有的步骤及细节,全部放在了一个代码文件中,Jenkins支持使用load从其他文件导入函数来执行,这样,可以将部分公共内容(如编译打包或者发布)提取到一个文件中,然后运行流水线时只需要导入一下这个函数即可.

基础

固定格式

def function_name () {
	println "hello world!"
}
return this;

def : 定义一个函数
function_name : 函数名称
():如果需要传参则在此处描写
{}:代码段
return this;:返回一个对象

使用函数

新增文件build-docker.groovy

def buildDocker(dockerImage,DOCKER_PASSWORD,tag){
    sh "docker build -t ${dockerImage}:task_${tag} ."
    sh "docker login -u 528909316 -p \'${DOCKER_PASSWORD}\'"
    sh "docker push ${dockerImage}:task_${tag}"
    sh ''' sed -i "s#DOCKERIMAGE#${dockerImage}#g" deploy.yml'''
}
return this;

新增文件deploy.groovy

def deploy(ref){
    println "deploy function parameter: ${ref}"
    if ("${ref}" == "refs/heads/main") {
        println "update formal platform"
        kubernetesDeploy configs: 'deploy.yml', kubeconfigId: "ae92d8dc-053e-409e-ae1b-f6e3f3bbb9f4"
    } else if ("${ref}" == "refs/heads/test") {
        println "update test platform"
        kubernetesDeploy configs: 'deploy-test.yml', kubeconfigId: 'ae92d8dc-053e-409e-ae1b-f6e3f3bbb9f4'
    } else {
        println "update unknown platform"
    }
}
return this;

新增的两个文件在gitlab新建仓库存放,位于main分支,下面主文件会用到仓库地址来拉取函数文件

修改后的jenkins.groocy文件

// 直接在文件中定义的 作用域为全局
def GITLAB_SSH_URL = "ssh://git@20.88.9.34:222/my_group/one_project.git"
def BUILD_IMAGE = "528909316/jenkins"
// 预先声明一个变量 名称叫做tag 此处声明后作用域为整个文件内
def tag = "${ref}".split("/")[-1]

podTemplate(
  cloud: 'kubernetes',
  containers: [
    containerTemplate(name: 'code', image: "${BUILD_IMAGE}:jenkinscode_v1",, command: "sleep 99d", ttyEnabled: true, alwaysPullImage: true),
    containerTemplate(name: 'build', image: "${BUILD_IMAGE}:pyinstaller_v1", command: "sleep 99d", ttyEnabled: true, alwaysPullImage: true),
    containerTemplate(name: 'docker', image: "${BUILD_IMAGE}:rundocker_v1", command: "sleep 99d", ttyEnabled: true, alwaysPullImage: true)],
  volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')]
) {
  // 当前函数下的每个stage中都可调用此函数
  def GITLAB_ID = "d17b1091-fa2d-4310-8a4d-0b1d7f823ea9"

  node(POD_LABEL) {
  	// 首先拉取相关的函数文件 此处单独为其创建了一个仓库
  	// url为仓库地址 main为分支
    git branch: "main", credentialsId: "${GITLAB_ID}", url: "ssh://git@20.88.9.34:222/my_group/jenkins-function.git"
    // 仓库中有两个文件 deploy.groovy和build-docker.groovy文件
    // def 新对象 = load "文件名或文件地址" //实例化一个对象
    def deploy = load "deploy.groovy"
    def buildDocker = load "build-docker.groovy"

    stage('Before build execution'){
      // 更新gitlab状态
      updateGitlabCommitStatus name: 'jenkins', state: 'running'
      // 判断分支 如果是pipeline则使用main代码
      if ("${ref}" == "refs/heads/pipeline") {
        tag = "main"
      }
    }

    stage('pull code') {
      // 克隆代码 根据变量 tag作为拉取分支
      git branch: "${tag}", credentialsId: "${GITLAB_ID}", url: "${GITLAB_SSH_URL}"
      echo "The first stage end"
    }

    stage('build code') {
      container('build') {
        stage('Build a python project') {
          // 编译为文件
          sh '''
          python -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
          pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
          pyinstaller -F cpu.py
          '''
        }
      }
      echo "The second stage end."
    }

    stage("build image") {
      // 某个stage中定义的 作用域当前函数中,只能在当前stage中或者其子stage中调用
      def dockerImage = '528909316/jenkins'
      container("docker") {
        stage("build image") {
          // 某个stage中定义的 作用域当前函数中,只能在当前stage中或者其子stage中调用
          def DOCKER_PASSWORD = "*********"
          // 调用新生成的对象的.buildDocker函数,同时传递三个参数
          buildDocker.buildDocker("${dockerImage}","${DOCKER_PASSWORD}","${tag}")
        }
      }
      echo "push ${dockerImage} end."
    }

    stage("deploy image") {
    	// 调用实例化的deploy对象的deploy函数,传递一个参数
      deploy.deploy("${ref}")
    }
    // 返回给gitlab一个信号 表示流水线成功
    updateGitlabCommitStatus name: 'one_project', state: 'success'
  }
}

需要注意的是,load的时候默认是在jnlp容器执行的.即便指定了container也是无效的,jnlp是Jenkins默认创建的工作节点容器,没有特殊指定的话任务都会在这个容器中运行(唯独load例外).
也可以将这些代码文件放进一个新的pod里,但是那样需要移动一下位置,同一个pod内所有容器的/home/jenkins/agent目录都是同一个(类似于nfs的挂载目录),放在这个目录下,jnlp容器中即可正常访问到这个文件.

将所有步骤提取到函数中

完成了一个步骤后,接下来将所有内容全部提取为一个个的函数文件,这样如果是Python代码我可以直接调用Python build的文件,如果是Java则调用Java build文件,实现更好的通用性.

规划:

创建一个仓库叫做jenkins-function ,单独存放提取出的代码文件
创建一个仓库叫做one_project ,用于模拟代码仓库,存放代码片段.

jenkins-function仓库目录层级

.
└── jenkins-function
    ├── before_build.groovy
    ├── build-docker.groovy
    ├── deploy.groovy
    ├── pull_code.groovy
    ├── python_build.groovy
    └── README.md

before_build.groovy

def before_build(branch)
{
    // 判断分支 如果是pipeline则使用main代码
    println "brfore build function."
}
return this;

build-docker.groovy

def buildDocker(dockerImage,tag){
    // def DOCKER_PASSWORD = "MyNewPass4!"
    def DOCKER_PASSWORD = "MyNewPass4!"
    sh "docker build -t ${dockerImage}:task_${tag} ."
    sh "docker login -u 528909316 -p \'${DOCKER_PASSWORD}\'"
    sh "docker push ${dockerImage}:task_${tag}"
    // sh ''' sed -i "s#DOCKERIMAGE#${dockerImage}#g" pipeline/deploy.yml'''
}
return this;

deploy.groovy

def deploy(ref,filePath,id,dockerImage){
    println "deploy function parameter: ${ref}"
    // 替换全局id版本
    sh("sed -i 's@DEPLOY_VERSION@${id}@g' ${filePath}")
    sh("sed -i 's@DOCKERIMAGE@${dockerImage}@g' ${filePath}")

    if ("${ref}" == "refs/heads/main") {
        println "update formal platform"
        sh ("sed -i 's#NAMESPACE#prod#g' ${filePath}")
        kubernetesDeploy configs: "${filePath}", kubeconfigId: "ae92d8dc-053e-409e-ae1b-f6e3f3bbb9f4"
    } else if ("${ref}" == "refs/heads/test") {
        println "update test platform"
        sh ("sed -i 's#NAMESPACE#test#g' ${filePath}")
        kubernetesDeploy configs: "${filePath}", kubeconfigId: 'ae92d8dc-053e-409e-ae1b-f6e3f3bbb9f4'
    } else {
        println "update unknown platform"
    }
    sh("cat ${filePath}")
}
return this;

pull_code.groovy

def pull_code(tag,GITLAB_ID,GITLAB_SSH_URL)
{
    git branch: "${tag}", credentialsId: "${GITLAB_ID}", url: "${GITLAB_SSH_URL}" 
}

python_build.groovy

def build(fileName){
    sh '''
    python -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple
    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple flask
    ''' 
    sh "pyinstaller -F ${fileName}"
}
return this;

one_project仓库内容

单独创建分支pipeline,存放代码构建文件
jenkins.groovy文件内容:

// 直接在文件中定义的 作用域为全局
def GITLAB_SSH_URL = "ssh://git@20.88.9.34:222/my_group/one_project.git"
def BUILD_IMAGE = "528909316/jenkins"
// 预先声明一个变量 名称叫做tag 此处声明后作用域为整个文件内
// static Integer tag
def tag = "${branch}".split("/")[-1]
// def tag = "${branch}".split("/")[-1]

podTemplate(
    cloud: 'kubernetes',
    containers: [
        containerTemplate(name: 'code', image: "${BUILD_IMAGE}:jenkinscode_v1",, command: "sleep 99d", ttyEnabled: true, alwaysPullImage: true),
        containerTemplate(name: 'build', image: "${BUILD_IMAGE}:pyinstaller_v1", command: "sleep 99d", ttyEnabled: true, alwaysPullImage: true),
        containerTemplate(name: 'docker', image: "${BUILD_IMAGE}:rundocker_v1", command: "sleep 99d", ttyEnabled: true, alwaysPullImage: true)],
    volumes: [hostPathVolume(hostPath: '/var/run/docker.sock', mountPath: '/var/run/docker.sock')]
) {
    // 当前函数下的每个stage中都可调用此函数
    def GITLAB_ID = "d17b1091-fa2d-4310-8a4d-0b1d7f823ea9"
    def filePath = "pipeline/deploy.yml"

    node(POD_LABEL) {
        git branch: "main", credentialsId: "${GITLAB_ID}", url: "ssh://git@20.88.9.34:222/my_group/jenkins-function.git"
        def deploy = load "deploy.groovy"
        def buildDocker = load "build-docker.groovy"
        def build = load "python_build.groovy"
        def pull_code = load "pull_code.groovy"
        def before_build = load "before_build.groovy"

        def dockerImage = '528909316/jenkins'

        stage('Before build execution'){
            // 更新gitlab状态
            updateGitlabCommitStatus name: 'one_project', state: 'running'
            before_build.before_build("${branch}")
            // 更新tag
            if ("${branch}" == "refs/heads/pipeline") {
                tag = "main"
            }
        }

        stage('pull code') {
            // 克隆代码 根据变量 tag作为拉取分支
            pull_code.pull_code("${tag}","${GITLAB_ID}","${GITLAB_SSH_URL}")
            // git branch: "${tag}", credentialsId: "${GITLAB_ID}", url: "${GITLAB_SSH_URL}"
            echo "The first stage end"
        }

        stage('build code') {
            container('build') {
                stage('Build a python project') {
                    build.build("cpu.py")
                }
            }
            echo "The second stage end."
        }

        stage("build image") {
            container("docker") {
                stage("build image") {
                    // 某个stage中定义的 作用域当前函数中,只能在当前stage中或者其子stage中调用
                    buildDocker.buildDocker("${dockerImage}","${tag}")
                }
            }
            echo "push ${dockerImage} end."
        }

        stage("deploy image") {
            deploy.deploy("${branch}","${filePath}","${id}","${dockerImage}")
        }
        // 返回给gitlab一个信号 表示流水线成功
        updateGitlabCommitStatus name: 'one_project', state: 'success'
    }
}
main分支:

目录结构

.
├── cpu.py
├── Dockerfile
├── pipeline
│   └── deploy.yml
└── README.md

cpu.py

from flask import Flask
from time import strftime
app = Flask(__name__)

@app.route("/")
def main():
    print("[{}] start calculate task.".format(strftime("%Y-%m-%d %H:%M:%S")))
    number = 0
    for i in range(0,100000000):
        number+=i
    print("[{}] calculate task end,return results.".format(strftime("%Y-%m-%d %H:%M:%S")))
    return {"key":number}

if __name__ == '__main__':
    app.run(host='0.0.0.0',port="8000")

Dockerfile

FROM python:3.6.15-slim
ADD dist/cpu cpu
CMD ["./cpu"]

pipeline/deploy.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-cpu
  namespace: NAMESPACE
spec:
  selector:
    matchLabels:
      run: python-cpu
  replicas: 3
  template:
    metadata:
      labels:
        run: python-cpu
        version: DEPLOY_VERSION
    spec:
      containers:
      - name: python-cpu
        imagePullPolicy: Always
        image: DOCKERIMAGE:task_main
        ports:
        - containerPort: 8000
        resources:
          limits:
            cpu: 500m
          requests:
            cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
  name: python-cpu
  labels:
    run: python-cpu
spec:
  ports:
  - port: 8000
  selector:
    run: python-cpu
  type: LoadBalancer

jenkins 触发构建配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值