18.7.3 Jenkins与Kubernetes部署与发布
在Jenkins与Kubernetes的部署与发布中,目标是形成“构建—制品—部署—验证—回滚”的自动化闭环。本节给出架构草图、安装与权限配置、流水线示例、发布与排错流程,并提供可执行练习。
原理草图:Jenkins与Kubernetes发布闭环
集成模式与架构选择
- Jenkins主节点 + K8s构建Pod:通过Kubernetes插件动态创建构建Pod,完成后自动回收。
- Jenkins调用K8s API部署:流水线中用kubectl/Helm发布。
- GitOps联动:Jenkins仅构建推送镜像,部署由Argo CD/Flux同步。
安装与基础准备(示例)
1) 安装Kubernetes插件(Jenkins UI)
- Manage Jenkins → Plugins → 安装 Kubernetes、Kubernetes CLI、Pipeline。
2) 创建命名空间与ServiceAccount、RBAC(集群侧)
# file: k8s/jenkins-sa.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cicd
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: cicd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: jenkins-deployer
namespace: cicd
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "deployments", "services", "configmaps", "secrets", "jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins-deployer-binding
namespace: cicd
subjects:
- kind: ServiceAccount
name: jenkins
namespace: cicd
roleRef:
kind: Role
name: jenkins-deployer
apiGroup: rbac.authorization.k8s.io
kubectl apply -f k8s/jenkins-sa.yaml
3) 生成kubeconfig并导入Jenkins凭据
# 获取ServiceAccount token
SA_SECRET=$(kubectl -n cicd get sa jenkins -o jsonpath='{.secrets[0].name}')
TOKEN=$(kubectl -n cicd get secret $SA_SECRET -o jsonpath='{.data.token}' | base64 -d)
CA=$(kubectl -n cicd get secret $SA_SECRET -o jsonpath='{.data.ca\.crt}')
SERVER=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')
cat > kubeconfig-jenkins <<EOF
apiVersion: v1
kind: Config
clusters:
- name: k8s
cluster:
server: ${SERVER}
certificate-authority-data: ${CA}
contexts:
- name: jenkins@k8s
context:
cluster: k8s
user: jenkins
namespace: cicd
current-context: jenkins@k8s
users:
- name: jenkins
user:
token: ${TOKEN}
EOF
将 kubeconfig-jenkins 保存为 Jenkins “Secret file” 凭据(ID: kubeconfig-cicd)。
Kubernetes插件Pod模板示例(构建+发布双容器)
# Jenkins Kubernetes Cloud Pod Template (YAML)
apiVersion: v1
kind: Pod
metadata:
labels:
jenkins: builder
spec:
serviceAccountName: jenkins
containers:
- name: maven
image: maven:3.9.6-eclipse-temurin-17
command: ["cat"]
tty: true
- name: kubectl
image: bitnami/kubectl:1.28
command: ["cat"]
tty: true
- name: kaniko
image: gcr.io/kaniko-project/executor:v1.20.1
command: ["/busybox/cat"]
tty: true
volumeMounts:
- name: docker-config
mountPath: /kaniko/.docker
volumes:
- name: docker-config
secret:
secretName: regcred
完整流水线示例(构建、推送、部署、回滚)
// file: Jenkinsfile
pipeline {
agent {
kubernetes {
label 'jenkins-k8s'
defaultContainer 'maven'
yamlFile 'k8s/jenkins-pod.yaml'
}
}
environment {
REGISTRY = "registry.example.com"
IMAGE = "registry.example.com/demo/app"
TAG = "${env.BUILD_NUMBER}-${env.GIT_COMMIT.take(7)}"
KUBECONFIG_CRED = "kubeconfig-cicd"
NAMESPACE = "cicd"
}
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Build') {
steps {
sh 'mvn -B -DskipTests package'
}
}
stage('Image Build & Push') {
steps {
container('kaniko') {
sh '''
/kaniko/executor \
--context $WORKSPACE \
--dockerfile $WORKSPACE/Dockerfile \
--destination $IMAGE:$TAG \
--insecure \
--skip-tls-verify
'''
}
}
}
stage('Deploy') {
steps {
withCredentials([file(credentialsId: env.KUBECONFIG_CRED, variable: 'KUBECONFIG')]) {
container('kubectl') {
sh '''
kubectl --kubeconfig=$KUBECONFIG -n $NAMESPACE set image deploy/demo demo=$IMAGE:$TAG
kubectl --kubeconfig=$KUBECONFIG -n $NAMESPACE rollout status deploy/demo --timeout=120s
'''
}
}
}
}
}
post {
failure {
withCredentials([file(credentialsId: env.KUBECONFIG_CRED, variable: 'KUBECONFIG')]) {
container('kubectl') {
sh '''
kubectl --kubeconfig=$KUBECONFIG -n $NAMESPACE rollout undo deploy/demo
'''
}
}
}
}
}
命令说明
- kubectl set image:更新Deployment镜像。
- rollout status:等待发布完成,超时失败。
- rollout undo:快速回滚到上一个Revision。
Helm发布示例(可替换kubectl)
# 预览渲染结果,避免误发布
helm template demo ./charts/demo -n cicd --set image.tag=${TAG}
# 执行发布
helm upgrade --install demo ./charts/demo -n cicd --set image.tag=${TAG}
# 回滚
helm rollback demo 1 -n cicd
发布策略与关键参数示例
# file: k8s/deploy.yaml
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
maxSurge=1:滚动更新时临时多一个Pod;maxUnavailable=0:不中断服务。
常见故障排查(命令级)
# 1) Jenkins Pod无法创建
kubectl -n cicd get events --sort-by=.metadata.creationTimestamp | tail -20
# 2) RBAC权限不足(403)
kubectl -n cicd auth can-i create deployments --as=system:serviceaccount:cicd:jenkins
# 3) 镜像拉取失败
kubectl -n cicd describe pod <pod> | grep -A5 "Failed to pull image"
# 4) 发布卡住
kubectl -n cicd rollout status deploy/demo
kubectl -n cicd get pods -l app=demo -o wide
kubectl -n cicd logs deploy/demo -c demo --tail=100
故障处理思路
- 403:检查Role/RoleBinding与namespace是否一致;
- 镜像拉取失败:检查imagePullSecrets、仓库地址与TAG;
- 发布卡住:检查readiness探针或依赖服务不可达。
安全与合规
- 仅为 cicd 命名空间授权,避免集群级权限;
- Jenkins凭据统一使用“Secret file/文本凭据”,禁止硬编码;
- 镜像扫描(Trivy/Grype)未通过则终止流水线。
练习
1) 在测试集群创建 cicd 命名空间并配置ServiceAccount与RBAC,验证 can-i 权限。
2) 将示例Jenkinsfile跑通,成功发布到 cicd,并手动触发一次 rollout undo。
3) 故意将镜像TAG写错,观察排错过程与日志输出。