What is Jenkins shared library
With the increase of microservices, pipeline files are required for each project. In this way, pipeline code redundancy is high, and pipeline functions become more and more complex.
jenkins can use Shared Lib to abstract some public pipelines into module code and reuse them among various project pipelines to reduce redundancy.
Shared library directory structure
Shared library root |-- vars |-- test1.groovy |-- src |-- test2.groovy |-- resources
vars: Groovy script that depends on Jenkins running environment. The Groovy script is called a global variable.
src: the standard Java source directory structure in which Groovy scripts are called library classes.
resources: the directory allows the use of the libraryResource step from an external library to load relevant non Groovy files.
How to reference a shared library
#!/usr/bin/env groovy // Reference shared libraries configured by default @Library('demo-shared-library') _ // Reference the specified branch tag Shared library code for @Library('demo-shared-library@1.0') _ // Reference multiple specified branches tag Shared library for @Library('demo-shared-library@$Branch/Tag','demo-shared-library-test@$Branch/Tag') _ @Library('utils') import org.foo.Utilities @Library('utils') import static org.foo.Utilities.*
Global variables under vars
/Global variables under vars must be all lowercase or camel cased
/If vars/*.groovy implements the call() method, the method will be executed by default when it is referenced directly
Implement one line of code to deploy. NET programs to K8S
Install Jenkins Master
# master docker run --name jenkins-blueocean -u root --privileged -d -p 8080:8080 -p 50000:50000 -v D:/architecture/jenkins/data:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock jenkinsci/blueocean # Visit: http://ip:8080/ # jenkins password, check the container log: 7285ced325a24483bfdaab227415fdac # Install recommended plug-ins
Install Jenkins Agent
- Name: agent2/agent3
- Labels: agentnode
- Launch method: Launch agent by connecting it to the master
Build Agent Docker Image
# slave # Dockerfile FROM jenkins/inbound-agent:latest USER root RUN apt-get update RUN apt-get -y install ca-certificates curl gnupg lsb-release RUN curl -fsSL https://get.docker.com -o get-docker.sh RUN sh get-docker.sh RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" RUN install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl RUN kubectl version --client ENV JMETER_VERSION=5.4.1 ENV JMETER_HOME=/jmeter/apache-jmeter-${JMETER_VERSION} ENV JMETER_PATH=${JMETER_HOME}/bin:${PATH} ENV PATH=${JMETER_HOME}/bin:${PATH} RUN mkdir /jmeter COPY apache-jmeter-${JMETER_VERSION}.tgz /jmeter RUN cd /jmeter && tar xvf apache-jmeter-${JMETER_VERSION}.tgz #Please go to the official website to download the tgz files RUN sed -i 's/#jmeter.save.saveservice.output_format=csv/jmeter.save.saveservice.output_format=xml/g' /jmeter/apache-jmeter-5.4.1/bin/jmeter.properties
docker build -t chesterjenkinsagent . docker tag chesterjenkinsagent:latest 192.168.43.95/jenkins/chesterjenkinsagent:v1 docker login --username=admin --password=123456 192.168.43.95 docker push 192.168.43.95/jenkins/chesterjenkinsagent:v1
Run the agent, and the key is obtained through jenkins's agent information
# agent4 docker run -v /var/run/docker.sock:/var/run/docker.sock --name agent4 -d --init 192.168.43.95/jenkins/chesterjenkinsagent:v1 -url http://192.168.43.94:8080 1e84c896dbffc0c325587eedb6301ab0ae66d3f4b49c4628dbb05714e382d7a2 agent4
Add K8S credentials
- Export the k8s cluster configuration file to ~ /. kube/config
- Mange Jenkins -> Manage Credentials -> Add Credentials -> Secret File
- Select the exported kubeconfig and set the id to kubeconfig
Add Harbor credentials
- Mange Jenkins -> Manage Credentials -> Add Credentials -> Username with password
- Enter the user name and password of Harbor
Add Gitee credentials
- Mange Jenkins -> Manage Credentials -> Add Credentials -> Username with password
- Enter Gitee's username and password
Install plug-ins
Manage Jenkins -> Manage Plugins -> Search "Performance" -> install
Manage shared libraries

Add the following code to the shared library
vars/run.groovy
#!/usr/bin/env groovy def call(String nameSpaceName, String serviceName, String servicePath, String servicePort, String nodePort, Map envInfo) { def devBranch = envInfo['dev'] def prodBranch = envInfo['prod'] pipeline { agent { label 'agentnode' } environment { DEV_MY_KUBECONFIG = credentials('kubeconfig') PROD_MY_KUBECONFIG = credentials('kubeconfig') HARBOR = credentials('harbor') } stages { stage('Dev - GitPull') { steps { deleteDir() gitCheckOut devBranch, env.GIT_URL } post { success { script { echo 'pull done' } } } } stage('Dev - DockerBuild') { steps { dockerImageBuild serviceName, "${servicePath}Dockerfile" } } stage('Dev - DockerTag') { steps { dockerTag serviceName, 'dev' } } stage('Dev - DockerLogin') { steps { dockerLogin 'dev' } } stage('Dev - DockerPush') { steps { dockerPush serviceName, 'dev' } } stage('Dev - GenerateHarborSecretYAML') { steps { harborSecret nameSpaceName, serviceName, 'dev' } } stage('Dev - GenerateK8SYAML') { steps { k8sGenerateYaml nameSpaceName, serviceName, servicePath, 'dev', servicePort, nodePort } } stage('Dev - DeployToK8S') { steps { k8sDeploy servicePath, 'dev' } } stage('Dev - CheckDeployStatus') { steps { k8sCheckDeployStatus nameSpaceName, serviceName, 'dev' } } stage('Dev - Jmeter Test') { steps { jmeterTest servicePath } } stage('DeployToProd?') { steps { input 'Deploy production?' } } stage('Prod - GitPull') { steps { gitCheckOut prodBranch, env.GIT_URL } } stage('Prod - DockerBuild') { steps { dockerImageBuild serviceName, "${servicePath}Dockerfile" } } stage('Prod - DockerTag') { steps { dockerTag serviceName, 'prod' } } stage('Prod - DockerLogin') { steps { dockerLogin 'prod' } } stage('Prod - DockerPush') { steps { dockerPush serviceName, 'prod' } } stage('Prod - GenerateHarborSecretYAML') { steps { harborSecret nameSpaceName, serviceName, 'prod' } } stage('Prod - GenerateK8SYAML') { steps { k8sGenerateYaml nameSpaceName, serviceName, servicePath, 'prod', servicePort, nodePort } } stage('Prod - DeployToK8S') { steps { k8sDeploy servicePath, 'prod' } } stage('Prod - CheckDeployStatus') { steps { k8sCheckDeployStatus nameSpaceName, serviceName, 'prod' } } } } }
vars/dockerImageBuild.groovy
#!/usr/bin/env groovy def call(String serviceName, String dockerfilePath) { echo "serviceName:${serviceName} dockerfilePath:${dockerfilePath}" sh "docker build -t ${serviceName} -f ${dockerfilePath} ." }
vars/dockerLogin.groovy
#!/usr/bin/env groovy def call(String envName) { sh 'docker login --username=$HARBOR_USR --password=$HARBOR_PSW 192.168.43.95' }
vars/dockerPush.groovy
#!/usr/bin/env groovy def call(String serviceName,String envName) { sh "docker push 192.168.43.95/dapr/${serviceName}:${envName}-${BUILD_NUMBER}" }
vars/dockerTag.groovy
#!/usr/bin/env groovy def call(String serviceName, String envName) { sh "docker tag ${serviceName}:latest 192.168.43.95/dapr/${serviceName}:${envName}-${BUILD_NUMBER}" }
vars/gitCheckOut.groovy
#!/usr/bin/env groovy def call(String branchName, String gitUrl) { echo "branchName:${branchName} gitUrl:${gitUrl}" checkout([$class: 'GitSCM', branches: [[name: branchName]], extensions: [], userRemoteConfigs: [[credentialsId: 'gitee', url: gitUrl]]]) }
vars/harborSecret.groovy
def call(String namespaceName, String serviceName, String envName) { dir('harborsecret') { checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitee', url: 'https://gitee.com/chesterdotchen/jenkins-demo-secrets.git']]]) sh """sed -i 's/{{ServiceName}}/${serviceName}/g' secrets.yaml""" sh """sed -i 's/{{NameSpaceName}}/${namespaceName}/g' secrets.yaml""" if (envName == 'dev') { sh("kubectl --kubeconfig ${DEV_MY_KUBECONFIG} apply -f secrets.yaml") } if (envName == 'prod') { sh("kubectl --kubeconfig ${PROD_MY_KUBECONFIG} apply -f secrets.yaml") } } }
vars/jmeterTest.groovy
#!/usr/bin/env groovy def call(String servicePath) { sh "jmeter -j jmeter.save.saveservice.output_format=xml -n -t ${servicePath}jmeter.jmx -l ${servicePath}jmeter.report.jtl" sh "cp ${servicePath}jmeter.report.jtl ${servicePath}jmeter.report.${BUILD_NUMBER}.jtl" perfReport errorFailedThreshold:5, sourceDataFiles:"${servicePath}jmeter.report.jtl" sh "cat ${servicePath}jmeter.report.${BUILD_NUMBER}.jtl" sh """#!/bin/sh grep '<failure>true</failure>' ${servicePath}jmeter.report.${BUILD_NUMBER}.jtl if [ \$? = 0 ] then exit 1 else exit 0 fi """ }
vars/k8sCheckDeployStatus.groovy
#!/usr/bin/env groovy def call(String nameSpaceName, String serviceName, String envName) { if (envName == 'dev') { sh(""" ATTEMPTS=0 ROLLOUT_STATUS_CMD='kubectl --kubeconfig ${DEV_MY_KUBECONFIG} rollout status deployment/${serviceName} -n ${nameSpaceName}-ns' until \$ROLLOUT_STATUS_CMD || [ \$ATTEMPTS -eq 60 ]; do \$ROLLOUT_STATUS_CMD ATTEMPTS=\$((attempts + 1)) sleep 10 done """) } if (envName == 'prod') { sh(""" ATTEMPTS=0 ROLLOUT_STATUS_CMD='kubectl --kubeconfig ${PROD_MY_KUBECONFIG} rollout status deployment/${serviceName} -n ${nameSpaceName}-ns' until \$ROLLOUT_STATUS_CMD || [ \$ATTEMPTS -eq 60 ]; do \$ROLLOUT_STATUS_CMD ATTEMPTS=\$((attempts + 1)) sleep 10 done """) } }
vars/k8sDeploy.groovy
#!/usr/bin/env groovy def call(String servicePath, String envName) { if (envName == 'dev') { sh("kubectl --kubeconfig ${DEV_MY_KUBECONFIG} apply -f ${servicePath}deployment.yaml") } if (envName == 'prod') { sh("kubectl --kubeconfig ${PROD_MY_KUBECONFIG} apply -f ${servicePath}deployment.yaml") } }
vars/k8sGenerateYaml.groovy
#!/usr/bin/env groovy def call(String namespaceName, String serviceName, String servicePath, String envName, String servicePort, String nodePort) { sh """sed "s/{{tagversion}}/${envName}-${BUILD_NUMBER}/g" ${servicePath}deployment.yaml.tpl > ${servicePath}deployment.yaml """ sh """sed -i 's/{{ServiceName}}/${serviceName}/g' ${servicePath}deployment.yaml""" sh """sed -i 's/{{ServicePort}}/${servicePort}/g' ${servicePath}deployment.yaml""" sh """sed -i 's/{{NodePort}}/${nodePort}/g' ${servicePath}deployment.yaml""" sh """sed -i 's/{{NameSpaceName}}/${namespaceName}/g' ${servicePath}deployment.yaml""" }
The code in Jenkins demo secrets is as follows
apiVersion: v1 kind: Namespace metadata: name: {{NameSpaceName}}-ns --- apiVersion: v1 kind: Secret metadata: name: harbor-key namespace: {{NameSpaceName}}-ns type: kubernetes.io/dockerconfigjson data: .dockerconfigjson: ewoJImF1dGhzIjogewoJCSIxOTIuMTY4LjQzLjk1IjogewoJCQkiYXV0aCI6ICJZV1J0YVc0Nk1USXpORFUyIgoJCX0sCgkJInJlZ2lzdHJ5LmNuLWJlaWppbmcuYWxpeXVuY3MuY29tIjogewoJCQkiYXV0aCI6ICI2Wm1JNUxpQTU0dXVPbU5vWlc1NWFYTm9hVEV5TXc9PSIKCQl9Cgl9Cn0=
Dockerconfig JSON can be obtained in the following ways
docker login --username=admin --password=123456 192.168.43.95 cat ~/.docker/config.json | base64
Shared libraries referenced in Jenkinsfile
Dockerfile, Jenkinsfile, deployment.yaml.tpl, jmeter.jmx need to be written in advance in the project library
Dockerfile
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base WORKDIR /app EXPOSE 5001 FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build WORKDIR /src COPY ["FrontEnd/FrontEnd.csproj", "FrontEnd/"] COPY ["Common/Common.csproj", "Common/"] RUN dotnet restore "FrontEnd/FrontEnd.csproj" COPY . . WORKDIR "/src/FrontEnd" RUN dotnet build "FrontEnd.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "FrontEnd.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "FrontEnd.dll"]
Jenkinsfile
#!/usr/bin/env groovy @Library('share@master') _ run 'daprtest', 'frontend', './FrontEnd/', '5001', '31111', ['dev':'*/master', 'prod':'*/master']
deployment.yaml.tpl
apiVersion: v1 kind: Namespace metadata: name: {{NameSpaceName}}-ns --- apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: statestore namespace: {{NameSpaceName}}-ns spec: type: state.redis version: v1 metadata: - name: redisHost value: 192.168.43.102:6379 - name: redisPassword value: "123456" - name: actorStateStore value: "true" --- apiVersion: apps/v1 kind: Deployment metadata: name: {{ServiceName}} namespace: {{NameSpaceName}}-ns labels: app: {{ServiceName}} spec: replicas: 1 selector: matchLabels: app: {{ServiceName}} template: metadata: namespace: {{NameSpaceName}}-ns labels: app: {{ServiceName}} annotations: dapr.io/enabled: "true" dapr.io/app-id: "{{ServiceName}}" dapr.io/app-port: "{{ServicePort}}" spec: imagePullSecrets: - name: harbor-key containers: - name: {{ServiceName}} image: 192.168.43.95/dapr/{{ServiceName}}:{{tagversion}} ports: - containerPort: {{ServicePort}} imagePullPolicy: Always --- apiVersion: v1 kind: Service metadata: namespace: {{NameSpaceName}}-ns name: {{ServiceName}}-svc spec: type: NodePort selector: app: {{ServiceName}} ports: - port: {{ServicePort}} targetPort: {{ServicePort}} nodePort: {{NodePort}}
jmter.jmx is written as needed
New pipline
Where the URL points to the git address of your project
Building pipline
So far, we have completed a line of code in Jenkinsfile to deploy our project. If there is a new service, on the premise of writing Dockerfile, deployment.yaml.tpl (consistent) and jmeter.jmx, we only need to reference the run method through the shared library in Jenkinsfile