企业级 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 路径
| 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)
| 自动发布(默认) | 镜像推送后自动部署到 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 自动发布
k8sdeploytemplateHarborbuildJenkins Podk8sdeploytemplateHarborbuildJenkins 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 服务更新
| 初始化部署 | 是 | 工作负载 + Service |
| 服务更新 | 否 | 仅工作负载 |
四、部署配置
4.1 部署配置类型(deployConfigType)
| 使用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)
| 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 统一入口
十、典型场景
| 首次 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 |
十二、快速检查清单
- K8s 云 kubernetes 已配置,Slave Pod 正常
- 凭据 HARBOR_ID、环境 kubeconfig 已创建
- publishMode、deployMethod 已配置
- kubectl 路径:SkyWalking OAP、registry-secret 就绪
- helm 路径:helm/Chart.yaml 存在
- SMTP、emailUser 已配置
附录:DevOps 三条路径对照
| 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 |