Jenkins pipeline使用

1878 字
9 分钟
Jenkins pipeline使用

[!jenkins文章分为三部分]

第一部分为docker安装Jenkins与常用插件使用,此文章 [[Jenkins安装]]

第二部分为运行pipeline并通过k8s pod打包 ,此文章

第三部分为,pipeline高阶使用,如map,共享库,参考 [[Jenkins-pipeline进阶使用]]

1 准备#

[!info] 提前安装好插件 参考 [[Jenkins安装]]主要是 Config File Provider

1.1 dockerfile模板#

# global-dockerfile-file
FROM ccr.ccs.tencentyun.com/ccops/all:jdk-17
EXPOSE 18100
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV TZ=Asia/Shanghai\
# jvm配置,按需选择
JAVA_OPTS="-Xmx4096m -Xms4096m -Xmn1536m -Xss256k -XX:+UseConcMarkSweepGC -XX: +UseCompressedClassPointers -XX:+PrintGCDetails -XX:+PrintGC -XX:+PrintGCTimeStamps -Xloggc:/var/ app/logs/gc.log -verbose:gc -Djava.awt.headless=true" \
# skywalking agent,如果不需要刻意删除
JAVA_TOOL_OPTIONS="-javaagent:/skywalking/agent/skywalking-agent.jar" \
SW_AGENT_NAMESPACE="#PROJECT" \
SW_AGENT_NAME="#PROJECT::#APP_NAME" \
SW_AGENT_COLLECTOR_BACKEND_SERVICES="#SW_OAP"
# jar路径不统一,配合pipeline jarPath map使用
ADD #jarPath /#APP_NAME.jar
ENTRYPOINT java ${JAVA_OPTS} -jar /#APP_NAME.jar --spring.profiles.active=prod

1.2 deployment模板#

# global-kubernetes-deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: #APP_NAME
spec:
replicas: #APP_REPLICAS
selector:
matchLabels:
app: #APP_NAME
service: #APP_NAME
strategy:
type: Recreate
template:
metadata:
labels:
app: #APP_NAME
service: #APP_NAME
spec:
volumes:
- name: skywalking-agent
emptyDir: { }
containers:
- image: #APP_IMAGE_NAME
name: #APP_NAME
# 探针相关,按需修改
startupProbe:
tcpSocket:
port: 8080
failureThreshold: 30
periodSeconds: 10
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
ports:
- containerPort: 8080
name: server
# 下面这部分是集成skywalking-agent,按需开启
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking
initContainers:
- name: agent-container
image: ccr.ccs.tencentyun.com/ccops/all:skywalking-java-agent-9.4.0
volumeMounts:
- name: skywalking-agent
mountPath: /agent
command: [ "/bin/sh" ]
args: [ "-c", "cp -R /skywalking/agent /agent/" ]
---
apiVersion: v1
kind: Service
metadata:
name: #APP_NAME
labels:
app: #APP_NAME
spec:
type: ClusterIP
ports:
- name: server
port: 8080
targetPort: 8080
selector:
app: #APP_NAME

2 不集成通知与k8s#

pipeline {
parameters {
choice choices: ['app1', 'app2'], description: '选择发布程序', name: 'APP_NAME'
}
options { buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '5')) }
environment {
PROJECT = '项目名'
BRANCH_NAME = '环境名(分支名)'
HARBOR_NAMESPACE = 'docker仓库凭据名称'
GIT_ID = 'git凭据名称'
GIT_URL = "https://git.xxx.com/${APP_NAME}.git(git的url)"
REGISTRY = '镜像仓库地址'
KUBECONFIG_ID = 'kubeconfig id'
KUBERNETES_APP_REPLICAS = 'deployment副本数'
KUBERNETES_DEPLOYMENT_ID = 'global-kubernetes-deployment' # deployment模板名称
DOCKER_DOCKERFILE_ID = 'global-dockerfile-file' # dockerfile模板
SW_OAP = 'skywalking OPA地址'
}
agent any
tools {
maven 'maven'
jdk 'jdk17'
}
stages {
stage('拉取代码') {
steps {
git(credentialsId: "${GIT_ID}", url: "$GIT_URL", branch: "${BRANCH_NAME}", changelog: true, poll: false)
}
}
stage('编译打包') {
steps {
sh 'mvn clean package install -Dmaven.test.skip=true -DarchetypeCatalog=local'
}
}
stage('镜像制作') {
steps {
// 设置 Docker 镜像名称
def dockerImageName = "${REGISTRY}/${APP_NAME}:1.${BUILD_NUMBER}"
// 使用 configFileProvider 插件提供 Dockerfile 文件
configFileProvider([configFile(fileId: "${DOCKER_DOCKERFILE_ID}", targetLocation: "dockerfile")]){
// 替换dockerfile文件中的变量
def docker = readFile encoding: "UTF-8", file: "dockerfile"
def dockerfile = docker.replaceAll("#APP_NAME","${APP_NAME}")
.replaceAll("#PROJECT","${PROJECT}")
.replaceAll("#SW_OAP","${SW_OAP}")
.replaceAll("#jarPath","${jarPath}")
// 生成新的 dockerfile 部署文件
writeFile encoding: 'UTF-8', file: './Dockerfile', text: "${dockerfile}"
}
// 提供 Docker 环境,使用 Docker 工具来进行 Docker 镜像构建与推送
docker.withRegistry("http://${REGISTRY}", "${HARBOR_NAMESPACE}") {
def customImage = docker.build("${dockerImageName}")
customImage.push()
}
}
}
stage('更新版本') {
steps {
// 使用 Kubectl Cli 插件的方法,提供 Kubeconfig
withKubeConfig([credentialsId: "${KUBECONFIG_ID}"]) {
// 读取 Kubernetes 部署文件
configFileProvider([configFile(fileId: "${KUBERNETES_DEPLOYMENT_ID}", targetLocation: "deployment.yaml")]){
script {
// 替换deployment文件中的变量
def deploy = readFile encoding: "UTF-8", file: "deployment.yaml"
def deployfile = deploy.replaceAll("#APP_NAME","${APP_NAME}")
.replaceAll("#APP_REPLICAS","${KUBERNETES_APP_REPLICAS}")
.replaceAll("#APP_IMAGE_NAME","${dockerImageName}")
// 生成新的 Kubernetes 部署文件
writeFile encoding: 'UTF-8', file: './deploy.yaml', text: "${deployfile}"
// sh "cat deploy.yaml"
// 执行 Kuberctl 命令进行部署操作
sh "kubectl apply -n ${PROJECT} -f deploy.yaml"
}
}
}
}
}
}
}

3 集成k8s#

没写的直接复用不集成k8s的配置就可以

pipeline {
......
agent {
kubernetes {
inheritFrom 'mypod'
}
}
stages {
stage('拉取代码') {
steps { # 不指定container默认使用jnlp
git(credentialsId: "${GIT_ID}", url: "$GIT_URL", branch: "${BRANCH_NAME}", changelog: true, poll: false)
}
}
stage('镜像制作') {
steps {
container('docker') {
// 创建 Dockerfile 文件,但只能在方法块内使用
configFileProvider([configFile(fileId: "${DOCKER_DOCKERFILE_ID}", targetLocation: "dockerfile")]){
script {
// 设置 Docker 镜像名称
def dockerImageName = "${REGISTRY}/${PROJECT}/${APP_NAME}:1.${BUILD_NUMBER}"
// 替换dockerfile文件中的变量
def docker = readFile encoding: "UTF-8", file: "dockerfile"
def dockerfile = docker.replaceAll("#APP_NAME","${APP_NAME}")
.replaceAll("#PROJECT","${PROJECT}")
.replaceAll("#SW_OAP","${SW_OAP}")
// 生成新的 dockerfile 部署文件
writeFile encoding: 'UTF-8', file: './Dockerfile', text: "${dockerfile}"
// sh "cat ./Dockerfile"
// 提供 Docker 环境,使用 Docker 工具来进行 Docker 镜像构建与推送
docker.withRegistry("http://${REGISTRY}", "${HARBOR_NAMESPACE}") {
def customImage = docker.build("${dockerImageName}")
customImage.push()
}
}
}
}
}
}
......
}
}

4 集成飞书#

需要安装此插件

pipeline {
......
  environment {
  ROBOT_ID = '告警机器人id'
  }
agent {
kubernetes {
inheritFrom 'mypod'
}
}
stages {
stage('拉取代码') {
steps {
git(credentialsId: "${GIT_ID}", url: "$GIT_URL", branch: "${BRANCH_NAME}", changelog: true, poll: false)
}
post {
failure {
echo "❌ 代码拉取失败"
// 发送失败通知
sendNotification("拉取代码", "❌失败")
}
}
}
}
post {
success {
lark (
robot: "${ROBOT_ID}",
type: "CARD",
title: "📢 ${PROJECT} ${APP_NAME} 构建成功通知 ",
text: [
"📋 **任务名称**:[${JOB_NAME}](${JOB_URL})",
"🔢 **任务编号**:[${BUILD_DISPLAY_NAME}](${BUILD_URL})",
"🌟 **构建状态**: <font color='green'>成功</font>",
"🕐 **构建用时**: ${currentBuild.duration / 1000} 秒",
"📜 **更新内容**: $changeString",
"<at id=all></at>"
],
buttons: [
[
title: "更改记录",
url: "${BUILD_URL}changes"
],
[
title: "控制台",
type: "danger",
url: "${BUILD_URL}console"
]
]
)
}
}
}
# 告警失败函数
def sendNotification(String stageName, String status) {
lark(
robot: "${ROBOT_ID}",
type: "CARD",
title: "❌ ${PROJECT} ${APP_NAME} ${stageName}失败通知",
text: [
"📌 **阶段**: ${stageName}",
"🔢 **状态**: <font color='red'>${status}</font>",
"<at id=all></at>"
]
)
}
......
# 此部分为了获取commit信息,如果不需要可以不加,但需要删除更新内容
@NonCPS
def getChangeString() {
MAX_MSG_LEN = 100
def changeString = ""
echo "Gathering SCM changes"
def changeLogSets = currentBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
truncated_msg = entry.msg.take(MAX_MSG_LEN)
changeString += " - ${truncated_msg} [${entry.author}]\n"
}
}
if (!changeString) {
changeString = " - No new changes"
}
return changeString
}

5 完整配置#

pipeline {
parameters {
choice choices: ['app1', 'app2'], description: '选择发布程序', name: 'APP_NAME'
}
options { buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '5')) }
environment {
PROJECT = '项目名'
BRANCH_NAME = '环境名(分支名)'
HARBOR_NAMESPACE = 'docker仓库凭据名称'
GIT_ID = 'git凭据名称'
GIT_URL = "https://git.xxx.com/${APP_NAME}.git(git的url)"
REGISTRY = '镜像仓库地址'
KUBECONFIG_ID = 'kubeconfig id'
KUBERNETES_APP_REPLICAS = 'deployment副本数'
KUBERNETES_DEPLOYMENT_ID = 'global-kubernetes-deployment' # deployment模板名称
DOCKER_DOCKERFILE_ID = 'global-dockerfile-file' # dockerfile模板
SW_OAP = 'skywalking OPA地址'
}
agent {
kubernetes {
inheritFrom 'mypod'
}
}
stages {
stage('拉取代码') {
steps {
git(credentialsId: "${GIT_ID}", url: "$GIT_URL", branch: "${BRANCH_NAME}", changelog: true, poll: false)
}
post {
failure {
echo "❌ 代码拉取失败"
sendNotification("拉取代码", "❌失败")
}
}
}
stage('编译打包') {
steps {
sh 'mvn clean package install -Dmaven.test.skip=true -DarchetypeCatalog=local'
}
post {
failure {
echo "❌ 打包失败"
sendNotification("maven打包", "❌失败")
}
}
}
stage('镜像制作') {
steps {
container('docker') {
// 创建 Dockerfile 文件,但只能在方法块内使用
configFileProvider([configFile(fileId: "${DOCKER_DOCKERFILE_ID}", targetLocation: "dockerfile")]){
script {
// 设置 Docker 镜像名称
def dockerImageName = "${REGISTRY}/${PROJECT}/${APP_NAME}:1.${BUILD_NUMBER}"
// 替换dockerfile文件中的变量
def dockerfile = readFile encoding: "UTF-8", file: "dockerfile"
def dockerfile = dockerfile.replaceAll("#APP_NAME","${APP_NAME}")
.replaceAll("#PROJECT","${PROJECT}")
.replaceAll("#SW_OAP","${SW_OAP}")
// 生成新的 dockerfile 部署文件
writeFile encoding: 'UTF-8', file: './Dockerfile', text: "${dockerfile}"
// sh "cat ./Dockerfile"
// 提供 Docker 环境,使用 Docker 工具来进行 Docker 镜像构建与推送
docker.withRegistry("http://${REGISTRY}", "${HARBOR_NAMESPACE}") {
def customImage = docker.build("${dockerImageName}")
customImage.push()
}
}
}
}
}
post {
failure {
echo "❌ 镜像制作"
sendNotification("镜像制作", "❌失败")
}
}
}
stage('更新版本') {
steps {
// 使用 Kubectl Cli 插件的方法,提供 Kubeconfig
withKubeConfig([credentialsId: "${KUBECONFIG_ID}"]) {
// 读取 Kubernetes 部署文件
configFileProvider([configFile(fileId: "${KUBERNETES_DEPLOYMENT_ID}", targetLocation: "deployment.yaml")]){
script {
// 替换deployment文件中的变量
def deploy = readFile encoding: "UTF-8", file: "deployment.yaml"
def deployfile = deploy.replaceAll("#APP_NAME","${APP_NAME}")
.replaceAll("#APP_REPLICAS","${KUBERNETES_APP_REPLICAS}")
.replaceAll("#APP_IMAGE_NAME","${dockerImageName}")
// 生成新的 Kubernetes 部署文件
writeFile encoding: 'UTF-8', file: './deploy.yaml', text: "${deployfile}"
// sh "cat deploy.yaml"
// 执行 Kuberctl 命令进行部署操作
sh "kubectl apply -n ${PROJECT} -f deploy.yaml"
}
}
}
}
post {
failure {
echo "❌ 更新版本失败"
sendNotification("更新版本", "❌失败")
}
}
}
}
post {
success {
lark (
robot: "${ROBOT_ID}",
type: "CARD",
title: "📢 ${PROJECT} ${APP_NAME} 构建成功通知 ",
text: [
"📋 **任务名称**:[${JOB_NAME}](${JOB_URL})",
"🔢 **任务编号**:[${BUILD_DISPLAY_NAME}](${BUILD_URL})",
"🌟 **构建状态**: <font color='green'>成功</font>",
"🕐 **构建用时**: ${currentBuild.duration / 1000} 秒",
"📜 **更新内容**: $changeString",
"<at id=all></at>"
],
buttons: [
[
title: "更改记录",
url: "${BUILD_URL}changes"
],
[
title: "控制台",
type: "danger",
url: "${BUILD_URL}console"
]
]
)
}
}
}
def sendNotification(String stageName, String status) {
lark(
robot: "${ROBOT_ID}",
type: "CARD",
title: "❌ ${PROJECT} ${APP_NAME} ${stageName}失败通知",
text: [
"📌 **阶段**: ${stageName}",
"🔢 **状态**: <font color='red'>${status}</font>",
"<at id=all></at>"
]
)
}
@NonCPS
def getChangeString() {
MAX_MSG_LEN = 100
def changeString = ""
echo "Gathering SCM changes"
def changeLogSets = currentBuild.changeSets
for (int i = 0; i < changeLogSets.size(); i++) {
def entries = changeLogSets[i].items
for (int j = 0; j < entries.length; j++) {
def entry = entries[j]
truncated_msg = entry.msg.take(MAX_MSG_LEN)
changeString += " - ${truncated_msg} [${entry.author}]\n"
}
}
if (!changeString) {
changeString = " - No new changes"
}
return changeString
}

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Jenkins pipeline使用
https://ccops.cc/posts/bfb1dd3a/
作者
蹦蹦站长
发布于
2025-02-11
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
蹦蹦站长
一个养兔子的运维
公告
感谢你的来访!希望在这里能找到对你有用的内容!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
81
分类
6
标签
45
总字数
88,456
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.12.1
文章许可
CC BY-NC-SA 4.0

文章目录