今天是「基于K8s的DevOps平台实践」的最后一篇,前两篇地址如下:
上面两篇均排在云原生领域榜第一
插件官方文档
[系统管理] -> [插件管理] -> [搜索kubernetes] -> 直接安装
若安装失败,请先更新 bouncycastle API Plugin 并重新启动Jenkins
[系统管理] -> [系统配置] -> [Add a new cloud]
配置地址信息
https://kubernetes.defaulthttp://jenkins:8080jenkins:50000配置 Pod Template
名称:jnlp-slave
命名空间:jenkins
标签列表:jnlp-slave,作为 agent 的 label 选择用
连接 Jenkins 的超时时间(秒):300,设置连接 jenkins 超时时间
工作空间卷:选择 hostpath,设置 /opt/jenkins,注意需要设置目录权限,否则 Pod 没有权限

$ chown -R 1000:1000 /opt/jenkins
$ chmod 700 /opt/jenkins
# 为准备运行jnlp-slave-agent的pod的节点打上label
$ kubectl label node k8s-slave1 agent=true### 回放一次多分支流水线develop分支
agent { label 'jnlp-slave'}
执行任务,会下载默认的 jnlp-slave 镜像,地址为 jenkins/inbound-agent:4.3-4,我们可以先在 k8s-master 节点拉取下来该镜像:
$ docker pull jenkins/inbound-agent:4.3-4
保存 jenkinsfile 提交后,会出现报错,因为我们的 agent 已经不再是宿主机,而是 Pod 中的容器内,报错如下:

因此我们需要将用到的命令行工具集成到 Pod 的容器内,但是思考如下问题:
为解决上述问题,我们制作一个 tools 镜像,集成常用的工具,来完成常见的构建任务,需要注意的几点:
.kube 目录及 config 文件$ mkdir tools;
$ cd tools;
$ cp `which kubectl` .
$ cp ~/.kube/config .
Dockerfile
jenkins/custom-images/tools/Dockerfile
FROM alpine:3.13.4
LABEL maintainer="inspur_lyx@hotmail.com"
USER rootRUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \apk update && \apk add --no-cache openrc docker git curl tar gcc g++ make \bash shadow openjdk8 python2 python2-dev py-pip python3-dev openssl-dev libffi-dev \libstdc++ harfbuzz nss freetype ttf-freefont && \mkdir -p /root/.kube && \usermod -a -G docker rootCOPY config /root/.kube/RUN rm -rf /var/cache/apk/*
#-----------------安装 kubectl--------------------#
COPY kubectl /usr/local/bin/
RUN chmod +x /usr/local/bin/kubectl
# ------------------------------------------------#
执行镜像构建并推送到仓库中:
$ docker build . -t 172.21.51.143:5000/devops/tools:v1
$ docker push 172.21.51.143:5000/devops/tools:v1
我们可以直接使用该镜像做测试:
## 启动临时镜像做测试
$ docker run --rm -ti 172.21.51.143:5000/devops/tools:v1 bash
# / git clone http://xxxxxx.git
# / kubectl get no
# / python3
#/ docker## 重新挂载docker的sock文件
docker run -v /var/run/docker.sock:/var/run/docker.sock --rm -ti 172.21.51.143:5000/devops/tools:v1 bash
实践通过 Jenkinsfile 实现 demo 项目自动发布到 kubenetes 环境

在卷栏目,添加卷,Host Path Volume,不然在容器中使用 docker 会提示 docker 服务未启动

tools 容器做好后,我们需要对 Jenkinsfile 做如下调整:
jenkins/pipelines/p8.yaml
pipeline {agent { label 'jnlp-slave'}options {buildDiscarder(logRotator(numToKeepStr: '10'))disableConcurrentBuilds()timeout(time: 20, unit: 'MINUTES')gitLabConnection('gitlab')}environment {IMAGE_REPO = "172.21.51.143:5000/myblog"DINGTALK_CREDS = credentials('dingTalk')TAB_STR = "\n \n "}stages {stage('printenv') {steps {script{sh "git log --oneline -n 1 > gitlog.file"env.GIT_LOG = readFile("gitlog.file").trim()}sh 'printenv'}}stage('checkout') {steps {container('tools') {checkout scm}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('build-image') {steps {container('tools') {retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('push-image') {steps {container('tools') {retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('deploy') {steps {container('tools') {sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"timeout(time: 1, unit: 'MINUTES') {sh "kubectl apply -f manifests/"}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}}post {success { echo 'Congratulations!'sh """curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"title":"myblog","text": "😄👍 构建成功 👍😄 \n**项目名称**:luffy \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"}}'""" }failure {echo 'Oh no!'sh """curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"title":"myblog","text": "😖❌ 构建失败 ❌😖 \n**项目名称**:luffy \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"}}'"""}always { echo 'I will always say Hello again!'}}
}
集成 sonarQube 实现代码扫描
Sonar 可以从以下七个维度检测代码质量,而作为开发人员至少需要处理前 5 种代码质量问题。
如图所示:

sonar/sonar.yaml
sonar.luffy.com 进行访问apiVersion: v1
kind: Service
metadata:name: sonarqubenamespace: jenkinslabels:app: sonarqube
spec:ports:- name: sonarqubeport: 9000targetPort: 9000protocol: TCPselector:app: sonarqube
---
apiVersion: apps/v1
kind: Deployment
metadata:namespace: jenkinsname: sonarqubelabels:app: sonarqube
spec:replicas: 1selector:matchLabels:app: sonarqubetemplate:metadata:labels:app: sonarqubespec:initContainers:- command:- /sbin/sysctl- -w- vm.max_map_count=262144image: alpine:3.6imagePullPolicy: IfNotPresentname: elasticsearch-logging-initresources: {}securityContext:privileged: truecontainers:- name: sonarqubeimage: sonarqube:7.9-communityports:- containerPort: 9000env:- name: SONARQUBE_JDBC_USERNAMEvalueFrom:secretKeyRef:name: gitlab-secretkey: postgres.user.root- name: SONARQUBE_JDBC_PASSWORDvalueFrom:secretKeyRef:name: gitlab-secretkey: postgres.pwd.root- name: SONARQUBE_JDBC_URLvalue: "jdbc:postgresql://postgres:5432/sonar"livenessProbe:httpGet:path: /sessions/newport: 9000initialDelaySeconds: 60periodSeconds: 30readinessProbe:httpGet:path: /sessions/newport: 9000initialDelaySeconds: 60periodSeconds: 30failureThreshold: 6resources:limits:cpu: 2000mmemory: 4096Mirequests:cpu: 300mmemory: 512Mi
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: sonarqubenamespace: jenkins
spec:rules:- host: sonar.luffy.comhttp:paths:- path: /pathType: Prefixbackend:service: name: sonarqubeport:number: 9000
# 创建sonar数据库
$ kubectl -n jenkins exec -ti postgres-5859dc6f58-mgqz9 bash
#/ psql
# create database sonar;## 创建sonarqube服务器
$ kubectl create -f sonar.yaml## 配置本地hosts解析
172.21.51.143 sonar.luffy.com## 访问sonarqube,初始用户名密码为 admin/admin
$ curl http://sonar.luffy.com
sonar-scanner的安装
下载地址: sonar
演示sonar代码扫描功能
sonar.projectKey=myblog
sonar.projectName=myblog
# if you want disabled the DTD verification for a proxy problem for example, true by default
sonar.coverage.dtdVerification=false
# JUnit like test report, default value is test.xml
sonar.sources=blog,myblog
配置 sonarqube 服务器地址
由于sonar-scanner 需要将扫描结果上报给 sonarqube 服务器做质量分析,因此我们需要在 sonar-scanner 中配置 sonarqube 的服务器地址:
在集群宿主机中测试,先配置一下 hosts 文件,然后配置 sonar 的地址:
$ cat /etc/hosts
172.21.51.143 sonar.luffy.com$ cat sonar-scanner/conf/sonar-scanner.properties
#----- Default SonarQube server
#sonar.host.url=http://localhost:9000
sonar.host.url=http://sonar.luffy.com
#----- Default source code encoding
#sonar.sourceEncoding=UTF-8
sonar.luffy.com访问,可以配置 coredns 的静态解析# 静态解析
$ kubectl -n kube-system edit cm coredns
...hosts {172.21.51.143 jenkins.luffy.com gitlab.luffy.com sonar.luffy.comfallthrough}
## 在项目的根目录下执行
$ /opt/sonar-scanner-4.2.0.1873-linux/bin/sonar-scanner -X
sonarqube 界面查看结果
java 项目的配置文件通常格式为:
sonar.projectKey=eureka-cluster
sonar.projectName=eureka-cluster
# if you want disabled the DTD verification for a proxy problem for example, true by default
# JUnit like test report, default value is test.xml
sonar.sources=src/main/java
sonar.language=java
sonar.tests=src/test/java
sonar.java.binaries=target/classes
集成到 tools 容器中
由于我们的代码拉取、构建任务均是在 tools 容器中进行,因此我们需要把 scanner 集成到我们的 tools 容器中,又因为 scanner 是一个 cli 客户端,因此我们直接把包解压好,拷贝到 tools 容器内部,配置一下 PATH 路径即可,注意两点:
直接在 tools 镜像中配置 http://sonar.luffy.com
由于 tools 已经集成了 java 环境,因此可以直接剔除 scanner 自带的 jre
删掉 sonar-scanner/jre 目录
修改 sonar-scanner/bin/sonar-scanner
use_embedded_jre=false
$ cd tools
$ cp -r /opt/sonar-scanner-4.2.0.1873-linux/ sonar-scanner
## sonar配置,由于我们是在Pod中使用,也可以直接配置:sonar.host.url=http://sonarqube:9000
$ cat sonar-scanner/conf/sonar-scanner.properties
#----- Default SonarQube server
sonar.host.url=http://sonar.luffy.com#----- Default source code encoding
#sonar.sourceEncoding=UTF-8$ rm -rf sonar-scanner/jre
$ vi sonar-scanner/bin/sonar-scanner
...
use_embedded_jre=false
...
Dockerfile
jenkins/custom-images/tools/Dockerfile2
FROM alpine:3.13.4
LABEL maintainer="inspur_lyx@hotmail.com"
USER rootRUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \apk update && \apk add --no-cache openrc docker git curl tar gcc g++ make \bash shadow openjdk8 python2 python2-dev py-pip python3-dev openssl-dev libffi-dev \libstdc++ harfbuzz nss freetype ttf-freefont && \mkdir -p /root/.kube && \usermod -a -G docker rootCOPY config /root/.kube/RUN rm -rf /var/cache/apk/*#-----------------安装 kubectl--------------------#
COPY kubectl /usr/local/bin/
RUN chmod +x /usr/local/bin/kubectl
# ------------------------------------------------##---------------安装 sonar-scanner-----------------#
COPY sonar-scanner /usr/lib/sonar-scanner
RUN ln -s /usr/lib/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner && chmod +x /usr/local/bin/sonar-scanner
ENV SONAR_RUNNER_HOME=/usr/lib/sonar-scanner
# ------------------------------------------------#
重新构建镜像,并推送到仓库:
$ docker build . -t 172.21.51.143:5000/devops/tools:v2
$ docker push 172.21.51.143:5000/devops/tools:v2
修改 Jenkins PodTemplate
为了在新的构建任务中可以拉取 v2 版本的 tools 镜像,需要更新 PodTemplate
安装并配置 sonar 插件
由于 sonarqube 的扫描的结果需要进行 Quality Gates 的检测,那么我们在容器中执行完代码扫描任务后,如何知道本次扫描是否通过了 Quality Gates,那么就需要借助于 sonarqube 实现的 jenkins 的插件。
安装插件
插件中心搜索 sonarqube,直接安装
配置插件
系统管理 -> 系统配置 -> SonarQube servers -> Add SonarQube
Name:sonarqube
Server URL:http://sonar.luffy.com
Server authentication token
① 登录 sonarqube -> My Account -> Security -> Generate Token
② 登录 Jenkins,添加全局凭据,类型为 Secret text
如何在 jenkinsfile 中使用
我们在 官方介绍 中可以看到:
jenkins/pipelines/p9.yaml
pipeline {agent { label 'jnlp-slave'}options {buildDiscarder(logRotator(numToKeepStr: '10'))disableConcurrentBuilds()timeout(time: 20, unit: 'MINUTES')gitLabConnection('gitlab')}environment {IMAGE_REPO = "172.21.51.143:5000/myblog"DINGTALK_CREDS = credentials('dingTalk')TAB_STR = "\n \n "}stages {stage('git-log') {steps {script{sh "git log --oneline -n 1 > gitlog.file"env.GIT_LOG = readFile("gitlog.file").trim()}sh 'printenv'}} stage('checkout') {steps {container('tools') {checkout scm}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('CI'){failFast trueparallel {stage('Unit Test') {steps {echo "Unit Test Stage Skip..."}}stage('Code Scan') {steps {container('tools') {withSonarQubeEnv('sonarqube') {sh 'sonar-scanner -X'sleep 3}script {timeout(1) {def qg = waitForQualityGate('sonarqube')if (qg.status != 'OK') {error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"}}}}}}}}stage('build-image') {steps {container('tools') {retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('push-image') {steps {container('tools') {retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('deploy') {steps {container('tools') {sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"timeout(time: 1, unit: 'MINUTES') {sh "kubectl apply -f manifests/"}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}}post {success { echo 'Congratulations!'sh """curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"title":"myblog","text": "😄👍 构建成功 👍😄 \n**项目名称**:luffy \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"}}'""" }failure {echo 'Oh no!'sh """curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"title":"myblog","text": "😖❌ 构建失败 ❌😖 \n**项目名称**:luffy \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"}}'"""}always { echo 'I will always say Hello again!'}}
}
若 Jenkins 执行任务过程中 sonarqube 端报类似下图的错:

则需要在 sonarqube 服务端进行如下配置,添加一个 webhook:

集成 RobotFramework 实现验收测试
一个基于 Python 语言,用于验收测试和验收测试驱动开发(ATDD)的通用测试自动化框架,提供了一套特定的语法,并且有非常丰富的测试库 。
robot/robot.txt
*** Settings ***
Library RequestsLibrary
Library SeleniumLibrary*** Variables ***
${demo_url} http://myblog.luffy/admin*** Test Cases ***
api[Tags] criticalCreate Session api ${demo_url}${alarm_system_info} RequestsLibrary.Get Request api /log ${alarm_system_info.status_code}log ${alarm_system_info.content}should be true ${alarm_system_info.status_code} == 200ui[Tags] critical${chrome_options} = Evaluate sys.modules['selenium.webdriver'].ChromeOptions() sys, selenium.webdriverCall Method ${chrome_options} add_argument headlessCall Method ${chrome_options} add_argument no-sandbox${options}= Call Method ${chrome_options} to_capabilitiesOpen Browser ${demo_url}/ browser=chrome desired_capabilities=${options}sleep 2sCapture Page ScreenshotPage Should Contain Djangoclose browser
# 使用tools镜像启动容器,来验证手动使用robotframework来做验收测试
$ docker run --rm -ti 172.21.51.143:5000/devops/tools:v2 bash
bash-5.0# apk add chromium chromium-chromedriver
$ cat requirements.txt
robotframework
robotframework-seleniumlibrary
robotframework-databaselibrary
robotframework-requests#pip安装必要的软件包
$ pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt #使用robot命令做测试
$ robot -d artifacts/ robot.txt
FROM alpine:3.13.4
LABEL maintainer="inspur_lyx@hotmail.com"
USER rootRUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \apk update && \apk add --no-cache openrc docker git curl tar gcc g++ make \bash shadow openjdk8 python2 python2-dev py-pip python3-dev openssl-dev libffi-dev \libstdc++ harfbuzz nss freetype ttf-freefont chromium chromium-chromedriver && \mkdir -p /root/.kube && \usermod -a -G docker rootCOPY config /root/.kube/COPY requirements.txt /RUN pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt RUN rm -rf /var/cache/apk/* && \rm -rf ~/.cache/pip#-----------------安装 kubectl--------------------#
COPY kubectl /usr/local/bin/
RUN chmod +x /usr/local/bin/kubectl
# ------------------------------------------------##---------------安装 sonar-scanner-----------------#
COPY sonar-scanner /usr/lib/sonar-scanner
RUN ln -s /usr/lib/sonar-scanner/bin/sonar-scanner /usr/local/bin/sonar-scanner && chmod +x /usr/local/bin/sonar-scanner
ENV SONAR_RUNNER_HOME=/usr/lib/sonar-scanner
# ------------------------------------------------#
$ docker build . -t 172.21.51.143:5000/devops/tools:v3$ docker push 172.21.51.143:5000/devops/tools:v3
更新 Jenkins 中 kubernetes 中的 containers template
为什么要安装 robot 插件?
安装 robotFramework
与 jenkinsfile 的集成
container('tools') {sh 'robot -i critical -d artifacts/ robot.txt'echo "R ${currentBuild.result}"step([$class : 'RobotPublisher',outputPath: 'artifacts/',outputFileName : "output.xml",disableArchiveOutput : false,passThreshold : 80,unstableThreshold: 20.0,onlyCritical : true,otherFiles : "*.png"])echo "R ${currentBuild.result}"archiveArtifacts artifacts: 'artifacts/*', fingerprint: true}
python-demo 项目添加 robot.txt 文件:
jenkins/pipelines/p10.yaml
pipeline {agent { label 'jnlp-slave'}options {buildDiscarder(logRotator(numToKeepStr: '10'))disableConcurrentBuilds()timeout(time: 20, unit: 'MINUTES')gitLabConnection('gitlab')}environment {IMAGE_REPO = "172.21.51.143:5000/myblog"DINGTALK_CREDS = credentials('dingTalk')TAB_STR = "\n \n "}stages {stage('git-log') {steps {script{sh "git log --oneline -n 1 > gitlog.file"env.GIT_LOG = readFile("gitlog.file").trim()}sh 'printenv'}} stage('checkout') {steps {container('tools') {checkout scm}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('CI'){failFast trueparallel {stage('Unit Test') {steps {echo "Unit Test Stage Skip..."}}stage('Code Scan') {steps {container('tools') {withSonarQubeEnv('sonarqube') {sh 'sonar-scanner -X'sleep 3}script {timeout(1) {def qg = waitForQualityGate('sonarqube')if (qg.status != 'OK') {error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"}}}}}}}}stage('build-image') {steps {container('tools') {retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('push-image') {steps {container('tools') {retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('deploy') {steps {container('tools') {sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"timeout(time: 1, unit: 'MINUTES') {sh "kubectl apply -f manifests/;sleep 20;"}}updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')script{env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR}}}stage('Accept Test') {steps {container('tools') {sh 'robot -i critical -d artifacts/ robot.txt|| echo ok'echo "R ${currentBuild.result}"step([$class : 'RobotPublisher',outputPath: 'artifacts/',outputFileName : "output.xml",disableArchiveOutput : false,passThreshold : 80,unstableThreshold: 20.0,onlyCritical : true,otherFiles : "*.png"])echo "R ${currentBuild.result}"archiveArtifacts artifacts: 'artifacts/*', fingerprint: true}}}}post {success { echo 'Congratulations!'sh """curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"title":"myblog","text": "😄👍 构建成功 👍😄 \n**项目名称**:luffy \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"}}'""" }failure {echo 'Oh no!'sh """curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \-H 'Content-Type: application/json' \-d '{"msgtype": "markdown","markdown": {"title":"myblog","text": "😖❌ 构建失败 ❌😖 \n**项目名称**:luffy \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"}}'"""}always { echo 'I will always say Hello again!'}}
}
在 Jenkins 中查看 robot 的构建结果。
通过这三篇文章,主要学习了以下几个方面:
但是,也存在一些问题:
后面会通过 sharedLibrary 对进行 CI/CD 流程进行一个优化
下一篇:Java反射机制