企业级 K8s 容器化部署方案:Jenkins + Harbor + Helm/kubectl + Gitee + Jenkinsfile 自动化实践
本文档基于 jenkinsfileTest/cigroovy.jenkinsfile 及共享库 jenkinslib 编写,描述 Java 微服务从 Maven/Gradle 编译、Docker 镜像推送 Harbor,到 K8s 集群部署(kubectl 动态模板 / Helm Chart)、初始化与服务更新、版本回滚的完整 CI/CD 流程。
一、方案架构
1.1 组件说明
| 组件 |
角色 |
说明 |
| Gitee |
代码仓库 |
SSH 拉取,含 Dockerfile |
| Jenkins (K8s Agent Pod) |
CI/CD |
mvn/docker/kubectl/helm 容器内执行 |
| Harbor |
镜像 / Chart 仓库 |
Docker 镜像;Helm 模式存 Chart |
| Kubernetes |
运行环境 |
Deployment / DaemonSet / StatefulSet |
| SkyWalking |
链路追踪 |
skywalking 模板 initContainer 注入 Agent |
| jenkinslib |
共享库 |
构建、Harbor、模板、K8s 部署、公共流水线 |
1.2 两条 CD 路径
| 路径 |
deployMethod |
说明 |
| kubectl(默认) |
kubectl |
Jenkins 动态生成 YAML → kubectl apply |
| Helm |
helm |
仓库 helm/ Chart → helm upgrade --install |
构建阶段(CheckOut → Build → 镜像推送 Harbor)相同,差异在部署阶段。
1.3 流水线与共享库
| 文件 |
说明 |
cigroovy.jenkinsfile |
K8s CI/CD 入口 |
vars/k8s.groovy + k8s.groovy |
Slave Pod(mvn/docker/kubectl/helm) |
pipeline.groovy |
checkout、发布门禁 |
build.groovy |
compile(mvn/gradle) |
Harbor.groovy |
docker build/push(校验 Dockerfile) |
template.groovy |
K8s YAML 模板生成 |
k8sdeploy.groovy |
kubectl / Helm 部署与回滚 |
resources/k8s-skywalking-*.yaml |
SkyWalking 通用微服务模板 |
resources/k8s-basic-*.yaml |
基础精简模板 |
二、发布模式(publishMode)
| publishMode |
行为 |
| 自动发布(默认) |
镜像推送后自动部署到 K8s |
| 手动发布 |
input 确认后部署 |
| 仅构建 |
仅编译 + 推镜像,不生成 YAML、不部署 |
| 回滚 |
kubectl rollout undo 或 Helm 回滚 |
#mermaid-svg-eBjFu7mng7jKFcdT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eBjFu7mng7jKFcdT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eBjFu7mng7jKFcdT .error-icon{fill:#552222;}#mermaid-svg-eBjFu7mng7jKFcdT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eBjFu7mng7jKFcdT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eBjFu7mng7jKFcdT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eBjFu7mng7jKFcdT .marker.cross{stroke:#333333;}#mermaid-svg-eBjFu7mng7jKFcdT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eBjFu7mng7jKFcdT p{margin:0;}#mermaid-svg-eBjFu7mng7jKFcdT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eBjFu7mng7jKFcdT .cluster-label text{fill:#333;}#mermaid-svg-eBjFu7mng7jKFcdT .cluster-label span{color:#333;}#mermaid-svg-eBjFu7mng7jKFcdT .cluster-label span p{background-color:transparent;}#mermaid-svg-eBjFu7mng7jKFcdT .label text,#mermaid-svg-eBjFu7mng7jKFcdT span{fill:#333;color:#333;}#mermaid-svg-eBjFu7mng7jKFcdT .node rect,#mermaid-svg-eBjFu7mng7jKFcdT .node circle,#mermaid-svg-eBjFu7mng7jKFcdT .node ellipse,#mermaid-svg-eBjFu7mng7jKFcdT .node polygon,#mermaid-svg-eBjFu7mng7jKFcdT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eBjFu7mng7jKFcdT .rough-node .label text,#mermaid-svg-eBjFu7mng7jKFcdT .node .label text,#mermaid-svg-eBjFu7mng7jKFcdT .image-shape .label,#mermaid-svg-eBjFu7mng7jKFcdT .icon-shape .label{text-anchor:middle;}#mermaid-svg-eBjFu7mng7jKFcdT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eBjFu7mng7jKFcdT .rough-node .label,#mermaid-svg-eBjFu7mng7jKFcdT .node .label,#mermaid-svg-eBjFu7mng7jKFcdT .image-shape .label,#mermaid-svg-eBjFu7mng7jKFcdT .icon-shape .label{text-align:center;}#mermaid-svg-eBjFu7mng7jKFcdT .node.clickable{cursor:pointer;}#mermaid-svg-eBjFu7mng7jKFcdT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eBjFu7mng7jKFcdT .arrowheadPath{fill:#333333;}#mermaid-svg-eBjFu7mng7jKFcdT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eBjFu7mng7jKFcdT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eBjFu7mng7jKFcdT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eBjFu7mng7jKFcdT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eBjFu7mng7jKFcdT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eBjFu7mng7jKFcdT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eBjFu7mng7jKFcdT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eBjFu7mng7jKFcdT .cluster text{fill:#333;}#mermaid-svg-eBjFu7mng7jKFcdT .cluster span{color:#333;}#mermaid-svg-eBjFu7mng7jKFcdT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eBjFu7mng7jKFcdT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eBjFu7mng7jKFcdT rect.text{fill:none;stroke-width:0;}#mermaid-svg-eBjFu7mng7jKFcdT .icon-shape,#mermaid-svg-eBjFu7mng7jKFcdT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eBjFu7mng7jKFcdT .icon-shape p,#mermaid-svg-eBjFu7mng7jKFcdT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eBjFu7mng7jKFcdT .icon-shape .label rect,#mermaid-svg-eBjFu7mng7jKFcdT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eBjFu7mng7jKFcdT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eBjFu7mng7jKFcdT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eBjFu7mng7jKFcdT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 回滚
其他
仅构建
自动/手动
kubectl
helm
publishMode
回滚阶段
CheckOut → Build
镜像构建并推送 Harbor
publishMode
结束
deployMethod
生成部署模板
跳过模板
发布到K8s
post 邮件
三、时序图
3.1 kubectl 自动发布
k8sdeploy template Harbor build Jenkins Pod k8sdeploy template Harbor build Jenkins Pod #mermaid-svg-enYvI2GvxJmeu7KN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-enYvI2GvxJmeu7KN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-enYvI2GvxJmeu7KN .error-icon{fill:#552222;}#mermaid-svg-enYvI2GvxJmeu7KN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-enYvI2GvxJmeu7KN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-enYvI2GvxJmeu7KN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-enYvI2GvxJmeu7KN .marker.cross{stroke:#333333;}#mermaid-svg-enYvI2GvxJmeu7KN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-enYvI2GvxJmeu7KN p{margin:0;}#mermaid-svg-enYvI2GvxJmeu7KN .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-enYvI2GvxJmeu7KN text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-enYvI2GvxJmeu7KN .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-enYvI2GvxJmeu7KN .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-enYvI2GvxJmeu7KN .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-enYvI2GvxJmeu7KN .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-enYvI2GvxJmeu7KN #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-enYvI2GvxJmeu7KN .sequenceNumber{fill:white;}#mermaid-svg-enYvI2GvxJmeu7KN #sequencenumber{fill:#333;}#mermaid-svg-enYvI2GvxJmeu7KN #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-enYvI2GvxJmeu7KN .messageText{fill:#333;stroke:none;}#mermaid-svg-enYvI2GvxJmeu7KN .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-enYvI2GvxJmeu7KN .labelText,#mermaid-svg-enYvI2GvxJmeu7KN .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-enYvI2GvxJmeu7KN .loopText,#mermaid-svg-enYvI2GvxJmeu7KN .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-enYvI2GvxJmeu7KN .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-enYvI2GvxJmeu7KN .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-enYvI2GvxJmeu7KN .noteText,#mermaid-svg-enYvI2GvxJmeu7KN .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-enYvI2GvxJmeu7KN .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-enYvI2GvxJmeu7KN .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-enYvI2GvxJmeu7KN .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-enYvI2GvxJmeu7KN .actorPopupMenu{position:absolute;}#mermaid-svg-enYvI2GvxJmeu7KN .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-enYvI2GvxJmeu7KN .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-enYvI2GvxJmeu7KN .actor-man circle,#mermaid-svg-enYvI2GvxJmeu7KN line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-enYvI2GvxJmeu7KN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} compile(mvn/gradle)1BuildImage + push2generateWorkloadTemplate + Service(init时)3Deploy(kubectl apply + rollout)4
3.2 Helm 发布
- 跳过「生成部署模板」
PackageAndPushChart → helm upgrade --install --atomic --wait
- 注意 :Helm 模式下 Jenkins 侧
deployConfigType/Template 参数不生效,由仓库 Chart 决定
3.3 初始化部署 vs 服务更新
| deployAction |
生成 Service |
kubectl apply |
| 初始化部署 |
是 |
工作负载 + Service |
| 服务更新 |
否 |
仅工作负载 |
四、部署配置
4.1 部署配置类型(deployConfigType)
| 参数值 |
输出文件 |
K8s 资源 |
| 使用deployment模板 |
deployment.yaml |
Deployment |
| 使用daemonset模板 |
daemonset.yaml |
DaemonSet |
| 使用statefulset模板 |
statefulset.yaml |
StatefulSet |
4.2 部署配置模板(deployConfigTemplate)
| 参数值 |
资源前缀 |
特性 |
| 通用微服务含skywalking |
k8s-skywalking-* |
initContainer Agent、探针、JAVA_OPTS/APOLLO_OPTS |
| 基础模板 |
k8s-basic-* |
精简,无 SkyWalking/探针 |
占位符:{``{PRONAME}} {``{FULL_IMAGE_NAME}} {``{NAMESPACE}} {``{REPLICAS}} {``{CONTAINER_PORT}} 及 CPU/Memory、Apollo、SkyWalking 等。
五、环境准备
5.1 Jenkins K8s 云
Slave Pod 容器:mvn、docker(挂载 docker.sock)、kubectl、helm。
5.2 Harbor
镜像:{HARBOR_URL}/{PROJECT_GROUP}/{imageName}:{imageTag}_{Tenv}_{BUILD_TIME}
示例:harbor.jdicity.local/registry/order-service:v1.0_prod_20250618_143022
5.3 K8s 凭据(config.K8S_CLUSTER_CREDENTIALS)
| Tenv |
默认凭据 ID |
| prod |
k8s-prod-config |
| test |
k8s-test-config |
| dev |
k8s-dev-config |
可用 K8S_CREDENTIAL_ID 覆盖。
5.4 集群前置条件
- Namespace 已创建
registry-secret imagePullSecrets
- SkyWalking 模板:OAP、Apollo Meta 集群内可达
- 应用暴露
/actuator/health/*(skywalking 模板探针)
5.5 Helm 额外要求
- 仓库根目录
helm/Chart.yaml
- Harbor Chart 仓库已启用
六、Jenkins 参数
6.1 基础参数
| 参数名 |
说明 |
Tenv |
dev/test/prod(邮件标题含环境) |
publishMode |
必配:自动发布/手动发布/仅构建/回滚 |
SrcURL / branchName |
仓库与分支 |
buildType |
mvn / gradle |
buildshell |
如 clean package -DskipTests |
imageName / imageTag |
镜像名与 tag 前缀 |
k8s_ns |
Namespace |
replicas / ContainerPort |
副本数、端口 |
waitMins / emailUser |
手动超时、邮件 |
6.2 部署参数
| 参数名 |
说明 |
deployMethod |
kubectl(默认)/ helm |
deployAction |
初始化部署 / 服务更新 |
deployConfigType |
Deployment/DaemonSet/StatefulSet 模板 |
deployConfigTemplate |
skywalking / 基础模板 |
6.3 SkyWalking 模板资源参数
containerCpuLimits、containerMemoryLimits、containerCpuRequests、containerMemoryRequests、APOLLO_*、skywalkingAgentImage、skywalkingCollector、JAVA_OPTS、APOLLO_OPTS
6.4 环境变量
| 变量 |
默认 |
HARBOR_URL |
harbor.jdicity.local |
PROJECT_GROUP |
registry |
K8S_CREDENTIAL_ID |
覆盖 kubeconfig |
七、流水线阶段
| 阶段 |
条件 |
说明 |
| CheckOut |
publishMode ≠ 回滚 |
pipeline.checkoutCode |
| Build |
同上 |
container(mvn) → build.compile |
| 镜像构建并推送 |
同上 |
打 tag + harbor.BuildImage(含 Dockerfile 校验) |
| 生成部署模板 |
auto/manual 且 kubectl |
template.generateWorkload/Service |
| 发布到K8s |
auto/manual |
pipeline.runPublish → k8sdeploy.RunDeploy |
| 回滚 |
rollback |
kubectl Rollback 或 HelmRollback |
| post |
always |
sendPost(notifyCtx 含 tenv) |
八、Helm 在 CI/CD 中的作用
| 能力 |
说明 |
| Chart 版本化 |
helm package,BUILD_NUMBER 为版本,推 Harbor |
| Release 管理 |
helm upgrade --install {imageName}-{Tenv} |
| 参数化 |
--set image.repository/tag/replicas/containerPort |
| 原子部署 |
--atomic --wait |
| 回滚 |
helm history + upgrade --reuse-values |
kubectl vs Helm 选型:
- 动态 SkyWalking YAML、多工作负载类型 → kubectl
- 稳定 Chart、Release 级管理 → Helm
九、共享库 API
pipeline.groovy
同前后端:checkoutCode、runPublish、selectRollbackVersion
k8sdeploy.groovy
| 方法 |
说明 |
RunDeploy(config) |
按 deployMethod 分发 |
Deploy(...) |
kubectl apply + rollout(含 DaemonSet) |
PackageAndPushChart / HelmDeploy |
Helm 路径 |
Rollback / HelmRollback |
回滚 |
build.groovy
build.compile(buildType, buildshell) // mvn / gradle 统一入口
十、典型场景
| 场景 |
publishMode |
其他 |
| 首次 SkyWalking 上线 |
自动发布 |
deployAction=初始化部署,deployConfigTemplate=skywalking |
| 日常发版 |
自动发布 |
deployAction=服务更新 |
| 只打镜像不部署 |
仅构建 |
--- |
| DaemonSet 日志 agent |
自动发布 |
deployConfigType=daemonset |
| Helm 发版 |
自动发布 |
deployMethod=helm,仓库含 helm/ |
| kubectl 回滚 |
回滚 |
deployMethod=kubectl |
十一、排错
| 现象 |
处理 |
| Dockerfile 不存在 |
仓库根目录添加 Dockerfile |
| Gradle 构建失败 |
buildType=gradle,Build 已统一支持 |
| libraryResource 失败 |
确认 jenkinslib/resources/k8s-*.yaml 已发布 |
| 探针失败 |
改用基础模板或调整 actuator 路径 |
| Helm 参数不生效 |
deployConfigType 仅 kubectl 有效 |
| 仅构建仍部署 |
publishMode 应为仅构建 |
| 邮件无环境 |
已修复:notifyCtx.tenv |
十二、快速检查清单
附录:DevOps 三条路径对照
| 维度 |
前端 |
后端 |
K8s |
| Jenkinsfile |
front.jenkinsfile |
backend.jenkinsfile |
cigroovy.jenkinsfile |
| 制品 |
tar.gz |
JAR |
Docker 镜像 |
| 仓库 |
MinIO |
MinIO |
Harbor |
| 部署 |
SSH 解压 |
SSH + launch.sh |
kubectl / Helm |
| 保留策略 |
artifactRetainCount |
MinIO + 目标机 JAR |
--- |
| 发布模式 |
publishMode |
publishMode |
publishMode |
| 公共库 |
pipeline.groovy |
pipeline.groovy |
pipeline.groovy |