首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Pod 连不上 Harbor?我用两天时间打通 Jenkins + Kaniko CI 流水线(附完整排障思路)

Pod 连不上 Harbor?我用两天时间打通 Jenkins + Kaniko CI 流水线(附完整排障思路)

作者头像
一根头发丝的宽度
发布2026-05-06 20:49:21
发布2026-05-06 20:49:21
1080
举报

📌 本文导览

字数:约 2000+ 字,阅读时间:9 分钟 这两天我从零开始,把一条完整的镜像构建链路彻底打通: Jenkins(K8s Agent) → Kaniko → Harbor这篇文章不仅讲“怎么做”,更重点讲清楚:

  • 问题是怎么一步步定位的?
  • 每一步为什么会失败?
  • 哪些地方值得截图展示(方便读者复现)

一、整体架构示意


二、核心问题一:Pod 无法访问 Harbor

1. 问题现象

在 Pod 内测试:

代码语言:javascript
复制
ping 192.168.xxx.xxx

结果:

代码语言:javascript
复制
100% packet loss

在 Node 上测试:

代码语言:javascript
复制
ping 192.168.xxx.xxx

结果正常:


2. 关键判断

测试

结果

Pod → Harbor

Node → Harbor

👉 结论:不是 Harbor 问题,而是 Pod 网络问题


3. 排查思路


4. 实际排查操作

(1)检查 IP 转发
代码语言:javascript
复制
sysctl net.ipv4.ip_forward

(2)检查 iptables NAT
代码语言:javascript
复制
iptables -t nat -L

重点看:cali-POSTROUTINGcali-nat-outgoingMASQUERADE

检查发现:并没有MASQUERADE规则。


(3)检查网络接口
代码语言:javascript
复制
ip a

关注:tunl0caliXXXX


5. 结论

👉 本质问题:Pod 出口 NAT(SNAT)未生效(后续通过调整 CNI 配置或手动添加 SNAT 规则解决)


三、核心问题二:Kaniko 默认走 HTTPS(经典坑)

1. 报错信息

代码语言:javascript
复制
Get "https://192.168.114.136/v2/": i/o timeout

2. 原因

  • Kaniko 默认优先使用 HTTPS
  • 但 Harbor 只开启了 HTTP(无证书)

3. 解决方式

在 Kaniko 命令中添加:

代码语言:javascript
复制
--insecure
--skip-tls-verify

4. 关键注意点

镜像地址必须带端口(因为 Harbor 监听 80):

代码语言:javascript
复制
192.168.xxx.xxx:80/demo/demo-app

如上图


四、核心问题三:Harbor 认证机制(Kaniko 的特殊性)

1. Kaniko 不使用 docker login

Kaniko 只认 /kaniko/.docker/config.json这个文件。


2. 正确配置 config.json

代码语言:javascript
复制
{
  "auths": {
    "192.168.xxx.xxx:80": {
      "username": "admin",
      "password": "xxxxx",
      "auth": "YWRtaWxxxxxxxxLmNvbQ=="
    }
  }
}

3. 常见错误

  • ❌ 不带端口(192.168.xxx.xxx而不是 192.168.xxx.xxx:80
  • ❌ 挂载路径错误
  • ❌ base64 编码错误

五、核心问题四:基础镜像拉取失败(网络超时)

现象

代码语言:javascript
复制
Get "https://index.docker.io/v2/": dial tcp ... i/o timeout

原因

  • Pod 无法直接访问 Docker Hub(或访问极慢)
  • 国内网络环境问题

解决方式

使用国内可访问的镜像源,例如:

代码语言:javascript
复制
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/tiangolo/uvicorn-gunicorn:python3.11-slim

六、核心问题五:Jenkins 权限问题(RBAC)

报错

代码语言:javascript
复制
Unauthorized (401)

原因

  • Pod 使用的 ServiceAccount 没有操作 Pods 的权限
  • Jenkins Master 的 Kubernetes 云配置凭证无效

解决

jenkins-agent绑定 RBAC:

代码语言:javascript
复制
apiVersion: rbac.authorization.k8s.io/v1
kind:Role
metadata:
namespace:cicd
name:jenkins-agent-role
rules:
-apiGroups:[""]
resources:["pods","pods/log","pods/exec"]
verbs:["get","list","watch","create","update","patch","delete"]
---
apiVersion:rbac.authorization.k8s.io/v1
kind:RoleBinding
metadata:
namespace:cicd
name:jenkins-agent-rolebinding
subjects:
-kind:ServiceAccount
name:jenkins-agent
namespace:cicd
roleRef:
kind:Role
name:jenkins-agent-role
apiGroup:rbac.authorization.k8s.io

七、Pipeline 优化全过程(从失败到成功)

这是我最宝贵的实战记录。下面展示每次迭代的关键变化和错误。

第1版:基础 Pod + Kaniko(未挂载认证)

代码语言:javascript
复制
agent {
    kubernetes {
        yaml """
containers:
- name: kaniko
  image: gcr.io/kaniko-project/executor:debug
"""
    }
}

结果:❌ UNAUTHORIZED


第2版:添加 Secret 挂载

代码语言:javascript
复制
volumes:
- name: docker-config
  secret:
    secretName: harbor-secret
volumeMounts:
- name: docker-config
  mountPath: /kaniko/.docker

结果:❌ 仍然 401(因为 registry 地址不带端口,认证信息不匹配)


第3版:修正 destination 为带端口

代码语言:javascript
复制
--destination=192.168.xxx.xxx:80/demo/demo-app:latest

结果:❌ config.json not found(Secret 未正确挂载)


第4版:手动创建 config.json(绕过 Secret)

代码语言:javascript
复制
sh '''
mkdir -p /kaniko/.docker
cat > /kaniko/.docker/config.json <<EOF
{
  "auths": {
    "192.168.xxx.xxx:80": {
      "username": "admin",
      "password": "xxxxxxx",
      "auth": "YWRtaxxxxxxxxzLmNvbQ=="
    }
  }
}
EOF
'''

结果:✅ 认证通过,但基础镜像拉取超时


第5版:替换基础镜像为国内源

代码语言:javascript
复制
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/tiangolo/uvicorn-gunicorn:python3.11-slim

结果:✅ 最终成功!


八、最终成功 Pipeline(完整代码)

代码语言:javascript
复制
pipeline {
    agent {
        kubernetes {
            cloud 'Kubernetes'
            yaml """
apiVersion: v1
kind: Pod
spec:
  serviceAccountName: jenkins-agent
  automountServiceAccountToken: true
  containers:
  - name: jnlp
    image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/jenkins/inbound-agent:trixie-jdk17
    env:
    - name: JENKINS_URL
      value: "http://jenkins:8080"
  - name: kaniko
    image: m.daocloud.io/gcr.io/kaniko-project/executor:debug
    command: ['/busybox/sh', '-c', 'sleep 999999']
    tty: true
    env:
    - name: DOCKER_CONFIG
      value: "/kaniko/.docker"
    volumeMounts:
    - name: workspace-volume
      mountPath: /workspace
  volumes:
  - name: workspace-volume
    emptyDir: {}
"""
        }
    }
    stages {
        stage('Prepare App') {
            steps {
                container('kaniko') {
                    sh '''
                        cd /workspace
                        cat > app.py <<EOF
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
    return "Hello from Kaniko + Harbor!"
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
EOF
                        cat > requirements.txt <<EOF
flask
EOF
                        cat > Dockerfile <<EOF
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
EOF
                    '''
                }
            }
        }
        stage('Build & Push') {
            steps {
                container('kaniko') {
                    sh '''
                        cd /workspace
                        mkdir -p /kaniko/.docker
                        cat > /kaniko/.docker/config.json <<EOF
{
  "auths": {
    "192.168.xxx.xxx:80": {
      "username": "admin",
      "password": "xxxxx",
      "auth": "YWRtaxxxxxxmNvbQ=="
    }
  }
}
EOF
                        /kaniko/executor \
                          --dockerfile=Dockerfile \
                          --context=/workspace \
                          --destination=192.168.xxx.xxx:80/demo/demo-app:latest \
                          --insecure \
                          --skip-tls-verify
                    '''
                }
            }
        }
    }
}

九、完整排查方法

这是本文最有价值的部分。

五层排查模型

代码语言:javascript
复制
1. 网络(通不通)
2. 协议(http/https)
3. 认证(凭证)
4. 镜像源(能否拉取)
5. 权限(RBAC)

👉 一句话总结:CI/CD问题 ≠ 工具问题,而是网络 + 认证 + 权限的综合问题


十、结尾

如果这篇文章帮到了你,欢迎点赞、转发给正在“踩坑”的朋友。 下一篇将进入 CI → CD 自动部署:Jenkins + kubectl + ArgoCD 实现应用自动发布。 👉 关注我,不错过下期硬核实战。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一根头发丝的宽度 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、整体架构示意
  • 二、核心问题一:Pod 无法访问 Harbor
    • 1. 问题现象
    • 2. 关键判断
    • 3. 排查思路
    • 4. 实际排查操作
      • (1)检查 IP 转发
      • (2)检查 iptables NAT
      • (3)检查网络接口
    • 5. 结论
  • 三、核心问题二:Kaniko 默认走 HTTPS(经典坑)
    • 1. 报错信息
    • 2. 原因
    • 3. 解决方式
    • 4. 关键注意点
  • 四、核心问题三:Harbor 认证机制(Kaniko 的特殊性)
    • 1. Kaniko 不使用 docker login
    • 2. 正确配置 config.json
    • 3. 常见错误
  • 五、核心问题四:基础镜像拉取失败(网络超时)
    • 现象
    • 原因
    • 解决方式
  • 六、核心问题五:Jenkins 权限问题(RBAC)
    • 报错
    • 原因
    • 解决
  • 七、Pipeline 优化全过程(从失败到成功)
    • 第1版:基础 Pod + Kaniko(未挂载认证)
    • 第2版:添加 Secret 挂载
    • 第3版:修正 destination 为带端口
    • 第4版:手动创建 config.json(绕过 Secret)
    • 第5版:替换基础镜像为国内源
  • 八、最终成功 Pipeline(完整代码)
  • 九、完整排查方法
    • 五层排查模型
  • 十、结尾
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档