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-fileFROM ccr.ccs.tencentyun.com/ccops/all:jdk-17EXPOSE 18100RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezoneENV 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.jarENTRYPOINT java ${JAVA_OPTS} -jar /#APP_NAME.jar --spring.profiles.active=prod1.2 deployment模板
# global-kubernetes-deploymentapiVersion: apps/v1kind: Deploymentmetadata: name: #APP_NAMEspec: 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: v1kind: Servicemetadata: name: #APP_NAME labels: app: #APP_NAMEspec: type: ClusterIP ports: - name: server port: 8080 targetPort: 8080 selector: app: #APP_NAME2 不集成通知与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信息,如果不需要可以不加,但需要删除更新内容@NonCPSdef 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>" ] )}
@NonCPSdef 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}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章 智能推荐
1
Jenkins-pipeline进阶使用
💨DevOps jenkins文章分为三部分,此文章是第三部分
2
Jenkins安装
💨DevOps jenkins文章分为三部分,此文章是第一部分
3
Jenkins权限管理
💨DevOps Jenkins权限管理,保证权限最小化
4
ArgoCD+Jenkins持续集成
💨DevOps Argo 与 Jenkins 结合 CI/CD 快速入门
5
OpenClaw安装
💻Linux 龙虾安装笔记
随机文章 随机推荐