基于 Kubernetes v1.33.4 部署 Jenkins Master-Slave 架构
组件要求常驻,Pod 名jenkins-0,运行在k8s-node1,使用root用户,数据落盘使用 JNLP 模式动态创建,完成任务后自动销毁存储使用hostPath固定在k8s-node1权限Master Pod 使用root用户,配置和(或等效的CI/CD 流程从节点拉代码 → 编译 → 构建 Docker 镜像 → 推送到镜像仓库(如 Harbor/Registry)Jenkins Mas
以下是基于 Kubernetes v1.33.4 部署 Jenkins Master-Slave 架构 的完整教程,使用 JNLP(Java Web Start)方式连接从节点,从节点执行 拉取代码 → 编译 → 构建镜像 → 推送镜像仓库 → 销毁,Jenkins Master 以 root 用户运行,Pod 名为 jenkins-0,数据持久化在节点 k8s-node1 上。
✅ 目标总结
| 组件 | 要求 |
|---|---|
| Jenkins Master | 常驻,Pod 名 jenkins-0,运行在 k8s-node1,使用 root 用户,数据落盘 |
| Jenkins Slave | 使用 JNLP 模式动态创建,完成任务后自动销毁 |
| 存储 | 使用 hostPath + nodeAffinity 固定在 k8s-node1 |
| 权限 | Master Pod 使用 root 用户,配置 SecurityContext 和 PodSecurityPolicy(或等效的 PodSecurity) |
| CI/CD 流程 | 从节点拉代码 → 编译 → 构建 Docker 镜像 → 推送到镜像仓库(如 Harbor/Registry) |
📦 环境准备
- Kubernetes 集群 v1.33.4
kubectl已配置k8s-node1节点已存在且可调度- Docker 或 containerd 已安装(用于构建镜像)
- 镜像仓库地址(如:
registry.example.com) - 已配置
docker login凭据(用于推送镜像)
🔧 第一步:准备 Jenkins Master 存储
1. 在 k8s-node1 上创建 Jenkins 数据目录
# 在 k8s-node1 执行
sudo mkdir -p /data/jenkins_home
sudo chown -R 1000:1000 /data/jenkins_home # Jenkins 默认用户,但我们将用 root 覆盖
⚠️ 注意:Jenkins 官方镜像默认使用用户
1000,但我们将在 Pod 中以root运行,所以需确保目录可写。
🛠 第二步:创建命名空间
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: jenkins
kubectl apply -f namespace.yaml
🔐 第三步:创建 ServiceAccount 和 RBAC 权限
# rbac.yaml
apiVersion: v1
kind: ServiceAccount
meta
name: jenkins
namespace: jenkins
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
meta
name: jenkins
rules:
- apiGroups: [""]
resources: ["pods", "services", "secrets", "configmaps", "events"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
meta
name: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: jenkins
kubectl apply -f rbac.yaml
💾 第四步:创建 PersistentVolume 和 PersistentVolumeClaim
# pv-pvc.yaml
apiVersion: v1
kind: PersistentVolume
meta
name: jenkins-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /data/jenkins_home
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node1
---
apiVersion: v1
kind: PersistentVolumeClaim
meta
name: jenkins-pvc
namespace: jenkins
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: manual
volumeName: jenkins-pv
kubectl apply -f pv-pvc.yaml
🐳 第五步:部署 Jenkins Master (StatefulSet)
# jenkins-master.yaml
apiVersion: apps/v1
kind: StatefulSet
meta
name: jenkins
namespace: jenkins
labels:
app: jenkins
spec:
serviceName: jenkins
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
serviceAccountName: jenkins
securityContext:
runAsUser: 0 # 以 root 用户运行
fsGroup: 0 # 文件系统组为 root
nodeSelector:
kubernetes.io/hostname: k8s-node1 # 固定调度到 k8s-node1
containers:
- name: jenkins
image: jenkins/jenkins:lts-jdk17 # 最新版 LTS
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
- containerPort: 50000 # JNLP 端口
env:
- name: JAVA_OPTS
value: "-Djenkins.install.runSetupWizard=false"
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
resources:
limits:
memory: "4Gi"
cpu: "2000m"
requests:
memory: "2Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 3
periodSeconds: 5
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-pvc
---
apiVersion: v1
kind: Service
meta
name: jenkins
namespace: jenkins
labels:
app: jenkins
spec:
type: NodePort
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 30080
- name: jnlp
port: 50000
targetPort: 50000
selector:
app: jenkins
✅ Pod 名为
jenkins-0(StatefulSet 自动命名)
kubectl apply -f jenkins-master.yaml
🔐 第六步:初始化 Jenkins(首次运行)
查看初始密码
kubectl logs jenkins-0 -n jenkins | grep "Jenkins initial setup is required"
# 或直接查看文件
kubectl exec -it jenkins-0 -n jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
访问 Jenkins
http://<k8s-node1-ip>:30080
登录后:
- 跳过插件安装(可自定义)
- 创建管理员用户
- 进入 Dashboard
⚙️ 第七步:安装必要插件
在 Jenkins 中安装以下插件(通过 Manage Jenkins > Plugins):
- Kubernetes Plugin(关键:用于动态创建 Slave Pod)
- Docker Pipeline
- Git
- Credentials Binding
- Blue Ocean(可选)
重启 Jenkins。
☸️ 第八步:配置 Kubernetes Cloud(动态 Slave)
进入:Manage Jenkins > Configure Clouds > Add a new cloud > Kubernetes
填写以下内容:
| 字段 | 值 |
|---|---|
| Name | kubernetes |
| Kubernetes URL | https://kubernetes.default.svc.cluster.local |
| Kubernetes Namespace | jenkins |
| Credentials | 添加 kubeconfig 或使用 ServiceAccount(推荐) |
| Jenkins URL | http://jenkins.jenkins.svc.cluster.local:8080 |
| Jenkins Tunnel | jenkins.jenkins.svc.cluster.local:50000 |
✅ 勾选 “Use the Kubernetes plugin’s internal defaults for Pod Templates”
添加 Pod Template(Slave 模板)
- Name:
jenkins-slave - Namespace:
jenkins - Labels:
jenkins-slave - Usage:
Use this node as much as possible
添加 Container Template
- Name:
jnlp - Docker Image:
jenkins/inbound-agent:jdk17(官方 JNLP 客户端) - Args:
${computer.jnlpmac} ${computer.name} - Working Directory:
/home/jenkins - Run in privileged mode: ✅ 勾选(用于 Docker in Docker)
- Run as User:
0(root) - Run as Group:
0
⚠️ 如果要构建 Docker 镜像,建议挂载
/var/run/docker.sock或使用dind
🐳 可选:挂载 Docker Socket(推荐用于构建镜像)
修改 jenkins-slave 的 Pod Template,在容器中添加:
Volume Mounts:
- Host Path: /var/run/docker.sock
Mount Path: /var/run/docker.sock
或在 Jenkins UI 中添加:
- Volume:
Host Path/var/run/docker.sock→/var/run/docker.sock
🧪 第九步:创建 Jenkins Pipeline Job
新建 Pipeline 任务
pipeline {
agent {
kubernetes {
label 'jenkins-slave'
defaultContainer 'jnlp'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: jenkins/inbound-agent:jdk17
args: ['\$(JENKINS_SECRET)', '\$(JENKINS_AGENT_NAME)']
workingDir: /home/jenkins
securityContext:
runAsUser: 0
privileged: true
volumeMounts:
- name: docker-sock
mountPath: /var/run/docker.sock
volumes:
- name: docker-sock
hostPath:
path: /var/run/docker.sock
'''
}
}
environment {
REGISTRY = 'registry.example.com'
IMAGE_NAME = 'myapp'
IMAGE_TAG = env.BUILD_ID
}
stages {
stage('Clone Code') {
steps {
git branch: 'main', url: 'https://github.com/youruser/your-repo.git'
}
}
stage('Build') {
steps {
sh 'mvn clean package' // 或 npm build 等
}
}
stage('Build and Push Image') {
steps {
script {
docker.build("${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}")
sh "docker login -u youruser -p yourpass ${REGISTRY}"
sh "docker push ${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
}
post {
always {
cleanWs() // 清理工作区
}
}
}
✅ 从节点执行完后自动销毁
🔐 安全建议(可选)
- 避免长期使用 root:生产环境建议使用非 root 用户 + 适当权限
- 使用 ImagePullSecrets:如果私有镜像仓库
- 使用 Secret 管理凭证:如
docker login密码 - 启用 Pod Security Admission:设置
baseline或restricted策略,但需为 Jenkins 特例放行
🧰 常见问题排查
| 问题 | 解决方案 |
|---|---|
| Slave 连接失败 | 检查 jenkins-tunnel 地址是否正确 |
| 构建镜像失败 | 检查 /var/run/docker.sock 是否可访问 |
| 权限拒绝 | 确保容器以 root 运行,privileged: true |
| PV 无法绑定 | 检查 nodeAffinity 和 hostPath 路径是否存在 |
| 插件安装慢 | 设置 Jenkins 更新站点为国内镜像 |
✅ 验证部署
# 查看 Master Pod
kubectl get pod -n jenkins -o wide
# NAME READY STATUS RESTARTS AGE IP NODE
# jenkins-0 1/1 Running 0 10m 10.244.x.x k8s-node1
# 查看 Slave Pod(运行 Pipeline 时自动创建)
kubectl get pod -n jenkins -w
📌 总结
你已成功部署:
- Jenkins Master:常驻
jenkins-0,运行在k8s-node1,使用root,数据持久化 - Jenkins Slave:通过 JNLP 动态创建,完成构建和推送后自动销毁
- 支持拉取代码、编译、Docker 构建、推送镜像
- 完整的 RBAC、存储、权限配置
📚 参考文档
- Jenkins Kubernetes Plugin: https://plugins.jenkins.io/kubernetes/
- Jenkins Docker Agent: https://hub.docker.com/r/jenkins/inbound-agent
- Kubernetes v1.33 官方文档
如需 高可用 Jenkins、使用 Helm 部署 或 集成 Harbor 镜像仓库,可继续扩展。需要我提供 Helm 版本或 GitOps 集成方案吗?
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)