CI/CD全链路可观测:从Jenkins到K8s全链路排查 一、项目背景与目标起点已有一套基于 5 台 ECS 的 K8s Jenkins CI/CD 环境能自动构建、部署微服务但缺乏监控、日志、链路追踪能力排查问题只能登服务器翻日志。目标在原有 CI/CD 基础上搭建完整的可观测性体系实现指标 日志 链路三位一体让系统从能自动部署升级到能自动部署 能监控 能告警 能快速定位问题。机器规划6 台 ECS主机名IP角色配置k8s-m192.168.171.128K8s master4C 4Gk8s-n1192.168.171.129K8s worker Ingress4C 8Ggitlab192.168.171.131GitLab2C 4Gdocker-harbor192.168.171.132Harbor2C 4Gjenkinsmysql192.168.171.133Jenkins MariaDB2C 4Gmoniotr192.168.171.134monitor服务器4C 8G网络单子网192.168.171.0/24流程2. CI/CD 流水线6 条 Pipelineeureka-service → gateway-service → portal-service → order-service → product-service → stock-service每条 Pipeline 分 4 阶段┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ 拉取项目代码 │→│ 编译代码 │→│ 构建Docker │→│ 部署镜像 │ │ (kaifa_projects)│ │ (mvn clean)│ │ 镜像 push │ │ (kubectl) │ └─────────────────┘ └──────────────┘ └──────────────┘ └──────────────┘3. 部署后访问链路浏览器 → portal.test.com (Ingress) ↓ portal-service (前端页面) ↓ JS 请求 gateway.test.com (Ingress) ↓ 路由 gateway-service (网关) ↓ Ribbon Eureka 服务发现 order/product/stock-service (业务服务) ↓ JDBC MariaDB (192.168.171.133)服务器选型gitlabk8seurekaharborJenkins指标日志链路追踪用户请求 → 微服务↓指标Prometheus 记录 QPS / 错误率 / JVM / 连接池 → Grafana 展示日志stdout → Promtail → Loki带 traceId → Grafana 展示链路OTel Agent → Collector → Tempo → Grafana 展示↓三者通过 traceId 联动指标异常 → 查日志带 traceId→ 点 tempo 按钮 → 看完整链路普罗米修斯grafana链路OTel Agent → Collector → Tempo → Grafana日志微服务 stdout → Promtail → Loki → Grafana三者通过 traceId 联动指标异常 → 查日志带 traceId→ 点 tempo 按钮 → 看完整链路前端页面坑1Harbor 容器重启后需要手动启动项内容现象机器重启后 Harbor 所有容器不会自动起来原因Harbor 用 docker-compose 管理默认没有 restart 策略解决①给docker-compose.yml每个服务加restart: always②或创建 systemd 服务坑2Jenkins 容器里没有 kubectl项内容现象Pipeline 到kubectl apply阶段报kubectl: command not found原因Jenkins 容器没挂载宿主机的 kubectl也没有 kubeconfig解决①从 k8s-m 拷 kubectl 和 kubeconfig 到 Jenkins 机器②run_jenkins.sh加挂载-v /usr/local/bin/kubectl:/usr/local/bin/kubectl-v /root/.kube:/root/.kube坑3滚动更新导致资源不足Pod Pending项内容现象新版本 Pod 一直 Pending旧版本还在 RunningEureka 里没新实例原因K8s 默认滚动更新新 Pod 起了才删旧 Pod。只有 2 个节点内存/CPU 不够同时跑两份解决①手动删旧 Podkubectl delete pod 旧Pod名 -n gongsi-dev②长期方案改成Recreate策略kubectl patch deployment name -n gongsi-dev -p {spec:{strategy:{type:Recreate}}}坑4SSH 私钥格式不对Jenkins 报 invalid format项内容现象凭据里粘贴 OpenSSH 私钥-----BEGIN OPENSSH PRIVATE KEY-----构建时报Load key ...: invalid format原因Jenkins 2.340 的 git-client 插件不识别 OpenSSH 新格式解决转成 PEM 格式ssh-keygen -p -m PEM -f /root/.ssh/id_rsahead -1验证输出-----BEGIN RSA PRIVATE KEY-----坑5Root POM 路径不对项内容现象构建报No such file /var/jenkins_home/workspace/test/pom.xml原因项目在simple-microservice_all/子目录下Jenkins 默认在根目录找 pom.xml解决任务配置里 Root POM 改成simple-microservice_all/pom.xml坑6Eureka 域名eureka_test.com含下划线非法项内容现象Eureka 客户端报Host name may not be null、Cannot execute request on any known server原因配置里写的是http://eureka_test.com/eureka域名含下划线是非法的HTTP 客户端解析不了解决改成合法域名http://eureka.test.com/eureka或直接用 K8s Service 名http://eureka-service-svc/eureka教训域名只能字母、数字、连字符不能用下划线坑7Eurekainstance.hostname: 127.0.0.1项内容现象服务注册到 Eureka但其他服务调用时连的是 127.0.0.1自己原因eureka-service 的配置里hostname: 127.0.0.1和prefer-ip-address: false解决删掉 hostname 那行改成prefer-ip-address: trueEureka 会用 Pod IP 注册坑8jar 里配置是旧的但外部代码是新的项内容现象明明改了 GitLab 上代码、Jenkins 也构建成功了但运行中的 jar 里配置还是旧值根因多层缓存①Jenkins workspace 缓存旧 target②Maven 增量编译③K8s 镜像 tag 没更新④浏览器缓存旧 JS为什么有价值①是 CI/CD 最常遇到的坑②排查路径长要层层验证GitLab → Jenkins workspace → Harbor 镜像 → K8s Pod → jar教训每次验证要从源头到运行逐层确认而不是猜排查命令unzip -p xxx.jar BOOT-INF/classes/application-fat.yml | grep 关键配置坑 9Pod PendingCPU 请求满现象0/2 nodes are available: 2 Insufficient cpu原因两个节点各 2CRequests 被占满解决降 kube-state-metrics 的 CPU 请求到 10m清理 ImagePullBackOff 的僵尸 Pod升级 Worker 到 4C8G坑 10Docker 数据目录不在默认位置现象Promtail 报no such file or directory/var/log/pods/里的软链接指向/data/docker/containers/原因这个集群的 Docker 数据目录被改到了/data/docker不是默认的/var/lib/docker解决在 Promtail 的 Helm values 里加挂载yamlextraVolumes: - name: docker-containers-data hostPath: path: /data/docker/containers extraVolumeMounts: - name: docker-containers-data mountPath: /data/docker/containers readOnly: true坑 11微服务 stdout 被重定向到文件现象kubectl logs没输出/data/docker/containers/.../xxx-json.log是 0 字节原因启动脚本是java -jar ... /app_server/xxx/logs/xxx.logstdout 被重定向到了文件解决在 Deployment 里覆盖command/args去掉重定向坑 12Tempo 查不到 trace现象tagNames: []原因10% 采样测试环境流量小全被采样掉了解决测试环境改成 100% 采样坑 13logback-spring.xml 在 jar 里不生效现象在basic-common-core里加了 logback-spring.xml但日志格式没变原因Spring Boot 只从当前应用的 classpath 加载 logback 配置不会读依赖 jar 里的解决在每个微服务的application.yml里直接配置yamllogging: pattern: console: %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [traceId%X{trace_id:-},spanId%X{span_id:-}] - %msg%n坑 18Derived Field 正则多了反斜杠现象Debug log message 显示no match原因正则写成\\[traceId...Grafana 理解成匹配一个反斜杠解决改成traceId([a-f0-9])或\[traceId([a-f0-9])坑 19traceId 不是行内蓝色链接现象Derived Field 匹配上了但日志行里 traceId 不变蓝原因日志是 JSON 格式Grafana 把 traceId 解析成了结构化字段链接显示在展开后的Fields → Links区域解决展开日志在 Links 里点tempo按钮坑 20服务状态显示旧 Pod 的 DOWN现象Dashboard 里出现已删除的 Pod 显示 DOWN原因kube-state-metrics会保留已删除 Pod 的指标一段时间解决改用 Deployment 级别指标promqlkube_deployment_status_replicas_available{namespace$namespace}