k8s部署自动化工具jenkins
一、项目背景
使用ack或者自建k8s集群部署一套自动化部署工具jenkins,实现代码快速构建部署上线
二、部署安装
使用了ack的卷,需要关注一下
#apiVersion: v1
#kind: PersistentVolumeClaim
#metadata:
# name: jenkins-pvc
# namespace: jenkins
#spec:
# accessModes:
# - ReadWriteOnce
# resources:
# requests:
# storage: 500Gi
# storageClassName: alibabacloud-cnfs-nas
#---
apiVersion: v1
kind: ServiceAccount
metadata:name: jenkinsnamespace: jenkins
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: jenkinsnamespace: jenkins
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]resources: ["pods/exec"]verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]resources: ["pods/log"]verbs: ["get","list","watch"]
- apiGroups: [""]resources: ["secrets"]verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:name: jenkinsnamespace: jenkins
roleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: jenkins
subjects:
- kind: ServiceAccountname: jenkinsnamespace: jenkins
---
apiVersion: apps/v1
kind: StatefulSet
metadata:name: jenkinsnamespace: jenkins
spec:replicas: 1selector:matchLabels:app: jenkinstemplate:metadata:labels:app: jenkinsspec:containers:- name: jenkins#image: mirror-registry.cn-hangzhou.cr.aliyuncs.com/hzdx/prod/jenkins:2.462.3-lts-jdk21image: registry.cn-hangzhou.aliyuncs.com/tym-test/demo:jenkinsports:- containerPort: 8080- containerPort: 50000env:- name: TZvalue: Asia/Shanghai- name: LIMITS_MEMORYvalueFrom:resourceFieldRef:divisor: 1Miresource: limits.memory- name: JAVA_OPTSvalue: -Djenkins.model.Jenkins.slaveAgentPort=50000 -Dhudson.lifecycle=hudson.lifecycle.ExitLifecycle-Duser.timezone=Asia/Shanghai -Djava.awt.headless=true -Dorgjenkinsci.plugins.gitclient.Git.timeOut=30livenessProbe:failureThreshold: 5httpGet:path: /loginport: 8080scheme: HTTPinitialDelaySeconds: 60periodSeconds: 10successThreshold: 1timeoutSeconds: 5ports:- containerPort: 8080name: httpportprotocol: TCP- containerPort: 50000name: jnlpportprotocol: TCPreadinessProbe:failureThreshold: 3httpGet:path: /loginport: 8080scheme: HTTPinitialDelaySeconds: 60periodSeconds: 10successThreshold: 1timeoutSeconds: 5securityContext:privileged: truerunAsUser: 0volumeMounts:- mountPath: /var/jenkins_homename: jenkinshome-pvc- mountPath: /run/containerd/containerd.sockname: containerd-sock- mountPath: /usr/bin/ctrname: ctr-command- name: timezonemountPath: /etc/localtimereadOnly: trueserviceAccountName: jenkinsvolumes:#- name: jenkinshome#persistentVolumeClaim:# claimName: jenkins-pvc- hostPath:path: /run/containerd/containerd.socktype: ""name: containerd-sock- hostPath:path: /usr/bin/ctrtype: ""name: ctr-command- name: timezonehostPath:path: /usr/share/zoneinfo/Asia/ShanghaivolumeClaimTemplates:- metadata:name: jenkinshome-pvcspec:accessModes: [ "ReadWriteOnce" ]storageClassName: "cnfs-nas-sc" # 引用名称为cnfs-nas-sc的StorageClass对象。resources:requests:storage: 500Gi
---
# jenkins-service.yaml
apiVersion: v1
kind: Service
metadata:annotations:prometheus.io/port: "8080"prometheus.io/scrape: "true"labels:app: jenkinsname: jenkinsnamespace: jenkins
spec:ports:- name: webnodePort: 30880port: 8080protocol: TCPtargetPort: 8080- name: agentnodePort: 30500port: 50000protocol: TCPtargetPort: 50000selector:app: jenkinstype: NodePort
四、配置ingress的方式进行访问
密码查看:
kubectl logs <jenkins-pod-name> | grep "Administrator password"

五、编写流水线脚本
示例:(根据实际情况进行编写,所用镜像需要替换)
currentBuild.displayName = "${JOB_NAME}" + "项目第" + "${BUILD_NUMBER}" + "次构建"
currentBuild.description = "${JOB_NAME}" + "job"def now = new Date().format('yyyy-MM-dd HH:mm:ss', TimeZone.getTimeZone('Asia/Shanghai'))
def timestamp = new Date().format('yyyyMMddHHmmss')pipeline {agent {kubernetes {yaml '''apiVersion: v1kind: Podmetadata:labels:k8s-app: jenkins-agentspec:volumes:- name: "maven-conf"configMap:name: "maven-config" # 使用已存在的 ConfigMapitems:- key: "settings.xml" # ConfigMap 中的 keypath: "settings.xml" # 挂载后的文件名- name: "tz"hostPath:path: "/etc/localtime"type: ""- name: "ssh"hostPath:path: "/root/.ssh"- name: "m2"hostPath:path: "/root/.m2"containers:- name: gitimage: mirror-registry-vpc.cn-hangzhou.cr.aliyuncs.com/test/alpine-git:v2.49.1command:- cattty: true- name: jnlpimage: mirror-registry-vpc.cn-hangzhou.cr.aliyuncs.com/test/jenkins-inbound-agent:3309.v27b_9314fd1a_4-1#args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)']- name: mavenimage: mirror-registry-vpc.cn-hangzhou.cr.aliyuncs.com/test/maven:3.9.9-eclipse-temurin-8-alpinecommand:- cattty: truevolumeMounts:- mountPath: "/root/.m2"name: "m2"- mountPath: "/usr/share/maven/conf/settings.xml"name: "maven-conf"subPath: "settings.xml"- mountPath: "/root/.ssh"name: "ssh"- name: "tz"mountPath: "/etc/localtime"- name: kanikoimage: mirror-registry-vpc.cn-hangzhou.cr.aliyuncs.com/test/kaniko:1.25.0-configjsoncommand:- cattty: truevolumeMounts:- name: "tz"mountPath: "/etc/localtime"readOnly: true'''retries 2}}environment {gitUrl = "xxxx"registryVpc = "mirror-registry-vpc.cn-hangzhou.cr.aliyuncs.com"registryCredential = "Ali-ACR-credential"ImageUrl = "${registryVpc}/test"dest_path = "/var/jenkins_home/workspace/${JOB_NAME}"job_path = "/data/docker-compose/jenkins/jenkins_home/workspace/${JOB_NAME}"JAVA_OPTS= "-Djava.security.egd=file:/dev/./urandom -Dfile.encoding=utf-8"yml_dir = "/opt/yaml"remote_host = "xxxxx"}options {disableConcurrentBuilds()timestamps()}parameters {choice(name: 'mode', choices: ['deploy','rollback'], description: '请选择发布或者回滚')gitParameter(name: 'BRANCH_NAME', type: 'PT_BRANCH_TAG', branchFilter: 'origin/(.*)', defaultValue: 'test', selectedValue: 'DEFAULT', sortMode: 'DESCENDING_SMART', description: 'Select your branch or tag.')extendedChoice(name: 'ProjectName',type: 'PT_CHECKBOX',description: '请勾选所要发布的项目模块',quoteValue: false,saveJSONParameterToFile: false,value: 'test',visibleItemCount: 10,multiSelectDelimiter: ',',defaultValue: 'test')}stages {stage('初始化信息') {when {environment name: 'mode', value: 'deploy'}steps {container('maven') {script {// 获取并处理分支名称(移除origin/前缀)def branchName = params.BRANCH_NAMEif (branchName.startsWith('origin/')) {branchName = branchName.replace('origin/', '')}env.CURRENT_BRANCH = branchNameecho "=============================================="echo "🎯 开始构建项目: ${JOB_NAME}"echo "📦 构建编号: ${BUILD_NUMBER}"echo "🌿 当前构建分支: ${env.CURRENT_BRANCH}"echo "📅 构建时间: ${now}"echo "🔧 构建模式: ${params.mode}"echo "📋 选择项目: ${params.ProjectName}"echo "=============================================="// 更新构建描述信息,包含分支信息currentBuild.description = "${JOB_NAME}job - 分支: ${env.CURRENT_BRANCH}"}}}}stage('CheckOut') {when {environment name: 'mode', value: 'deploy'}steps {container('maven') {script {echo "📥 正在克隆代码库,分支: ${env.CURRENT_BRANCH}"sh """ssh ${remote_host} -o StrictHostKeyChecking=no "rm -rf /opt/test && cd /opt && pwd && git clone -b ${env.CURRENT_BRANCH} ${gitUrl}""""echo "✅ 代码克隆完成,分支: ${env.CURRENT_BRANCH}"}}}}stage('Run maven') {when {environment name: 'mode',value: 'deploy'}steps {container('maven') {script {echo "🔨 开始Maven构建,分支: ${env.CURRENT_BRANCH}"sh """ssh ${remote_host} -o StrictHostKeyChecking=no "source /etc/profile && cd /opt/test && mvn -DskipTests clean package""""echo "✅ Maven构建完成,分支: ${env.CURRENT_BRANCH}"}}}}stage('Image build') {when {environment name: 'mode',value: 'deploy'}steps {container('maven') {script {env.currentDate = sh (script: 'date +%Y-%m-%d_%H-%M-%S', returnStdout: true).trim()def selectedProjects = params.ProjectName.split(',')echo "🐳 开始构建Docker镜像,分支: ${env.CURRENT_BRANCH}"echo "📦 镜像标签时间戳: ${env.currentDate}"// 获取用户选择的项目模块for (def project : selectedProjects) {if (project.trim()) {echo "🔧 正在构建项目: ${project},分支: ${env.CURRENT_BRANCH}"sh """ssh ${remote_host} -o StrictHostKeyChecking=no "cd /opt/test/mid-holo-biz/target/ls -lh *.jarcat << EOF > Dockerfile
FROM mirror-registry-vpc.cn-hangzhou.cr.aliyuncs.com/test/eclipse-temurin:jdk-8u452ENV TZ=Asia/Shanghai
ENV LANG C.UTF-8
RUN mkdir /app/ -p
COPY *.jar /app/${project}.jar
ENTRYPOINT [\\"sh\\", \\"-c\\", \\"java -Djava.security.egd=file:/dev/./urandom -Dfile.encoding=utf-8 -jar /app/${project}.jar\\"]
EOFcat Dockerfiledocker build . -t ${ImageUrl}/${project}:${currentDate}docker push ${ImageUrl}/${project}:${currentDate}""""echo "✅ 项目 ${project} 镜像构建完成"}}}}}}stage('Update') {when {environment name: 'mode',value: 'deploy'}steps {container('maven') {script {def selectedProjects = params.ProjectName.split(',')echo "🔄 开始更新部署,分支: ${env.CURRENT_BRANCH}"// 获取用户选择的项目模块for (def project : selectedProjects) {if (project.trim()) { // 添加非空检查echo "🔄 正在更新项目: ${project},分支: ${env.CURRENT_BRANCH}"sh """ssh ${remote_host} -o stricthostkeychecking=no "sh /opt/demo/dxtest-charts/all.sh Change=deploy Name=mid-holo Image=${ImageURL}/${project}:${currentDate} namespace=test""""echo "✅ 项目 ${project} 更新完成"}}}}}}stage('部署完成') {when {environment name: 'mode', value: 'deploy'}steps {script {echo "=============================================="echo "🎉 部署完成!"echo "📦 项目: ${JOB_NAME}"echo "🌿 分支: ${env.CURRENT_BRANCH}"echo "🔢 构建编号: ${BUILD_NUMBER}"echo "📅 完成时间: ${new Date().format('yyyy-MM-dd HH:mm:ss', TimeZone.getTimeZone('Asia/Shanghai'))}"echo "🐳 镜像标签: ${env.currentDate}"echo "=============================================="}}}}
}
六、部署结果查看

