csdn0811 2025-11-27 19:12 采纳率: 60.7%
浏览 6

关于k8s集群的pod无法访问集群外的mysql服务,如何解决?

我的k8s集群部署了go服务,master节点在192.168.205.141,而go所引用的mysql服务在集群外部,地址是192.168.205.143: 5000 , 但现在的问题是集群内部署的goo应用pod无法访问外部的mysql服务,怎么解决?我的go应用部署yaml如下:


apiVersion: v1
kind: ConfigMap
metadata:
  name: rbac-combined-config # ConfigMap 的名称,在 Deployment 中会引用这个名称
data:
  app.yaml: |
    server:
      isRelease: false    
      port: 80        
      host: 0.0.0.0     
      domain: ""        

    mysql:
      user: root        
      password: 1234     
      # ip: 192.168.205.143
      ip: external-mysql-pod.default.svc.cluster.local
      port: 5000         
      database: test    


  # model.conf:Casbin权限模型的配置文件
  model.conf: |
    [request_definition]
    r = sub, obj, act    # 请求定义:主体(subject)、资源(object)、操作(action)

    [policy_definition]
    p = sub, obj, act    # 策略定义

    [role_definition]
    g = _, _             # 角色定义:用户角色关联

    [policy_effect]
    e = some(where (p.eft == allow)) # 策略效果:只要有一个策略允许就允许

    [matchers]
    m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act 
    # 匹配器:用户具有角色,且资源匹配,且操作匹配

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: rbac-app # Deployment 名称
spec:
  replicas: 1 # Pod 副本数量,1表示只运行1个实例
  selector:
    matchLabels:
      app: rbac-app # 选择器:选择带有 app=rbac-app 标签的 Pod
  template:
    metadata:
      labels:
        app: rbac-app # Pod 的标签,与上面的选择器匹配
    spec: 
      containers:
        - name: rbac-app # 容器名称
          image: core.harbor.domain/library/rbac-admin:latest # 容器镜像地址
          securityContext:  # 安全上下文:设置容器权限
            privileged: true  # 容器具有特权,可以访问宿主机资源
          ports:
            - containerPort: 8080 # 容器内部监听的端口
          env:
            - name: GIN_MODE # Go Gin框架的运行模式
              value: "release" # release=生产模式
          volumeMounts: # 卷挂载:将外部存储挂载到容器内部/
            - mountPath: /app/internal/config/files # 配置文件挂载路径
              name: config-volume # 引用的卷名称
            - mountPath: /app/logs # 日志目录挂载路径
              name: logs-volume
            - mountPath: /app/static/upload # 文件上传目录挂载路径
              name: upload-volume
            - mountPath: /etc/resolv.conf # DNS配置文件挂载路径d
              name: resolv-conf
      volumes: # 定义的卷列表
        - name: config-volume # 配置卷
          configMap:
            name: rbac-combined-config # 使用上面定义的ConfigMap
        - name: logs-volume # 日志卷
          persistentVolumeClaim:
            claimName: logs-pvc # 使用持久化存储声明
        - name: upload-volume # 上传文件卷
          persistentVolumeClaim:
            claimName: upload-pvc
        - name: resolv-conf # DNS配置卷
          hostPath:
            path: /etc/resolv.conf

---
# PersistentVolumeClaim (PVC):申请持久化存储
# PVC 向 Kubernetes 申请存储空间,由 StorageClass 动态提供
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: logs-pvc # PVC 名称
spec:
  accessModes:
    - ReadWriteMany # 访问模式:多节点读写
  storageClassName: local-nfs-storage # 存储类名称(使用NFS存储)
  resources:
    requests:
      storage: 1Gi # 申请1GB存储空间

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: upload-pvc # 上传文件存储声明
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: local-nfs-storage
  resources:
    requests:
      storage: 1Gi

---
# Service:为应用程序提供网络访问
# Service 提供稳定的网络端点,即使Pod重启IP变化,Service地址不变
apiVersion: v1
kind: Service
metadata:
  name: rbac-app # Service 名称
spec:
  type: NodePort # Service 类型:NodePort 会在每个节点上开放端口
  selector:
    app: rbac-app # 选择器:将流量转发到带有 app=rbac-app 标签的Pod
  ports:
    - port: 80 # Service 端口(集群内部访问端口
      targetPort: 8080 # 目标端口(Pod内部的实际端口)
      nodePort: 30080 # NodePort(集群外部访问端口)



我根据网上的教材使用了Endpoints方法:如下:


---
apiVersion: v1
kind: Service
metadata:
  name: external-mysql-pod
spec:
  ports:
  - port: 5000
  clusterIP: None  # 创建Headless Service
---
apiVersion: v1
kind: Endpoints
metadata:
  name: external-mysql-pod
subsets:
- addresses:
  - ip: 192.168.205.143
  ports:
  - port: 5000

但仍然报错:

[root@k8s-master01 go-app]# kubectl logs rbac-app-77684b58fc-zb298
🔧 配置文件: internal/config/files/app.yaml
panic: mysql 解析配置失败: dial tcp: lookup external-mysql-pod.default.svc.cluster.local: i/o timeout

goroutine 1 [running]:
rbac_admin/internal/dao/mdb.InitGorm()
    /app/internal/dao/mdb/mysqlConnection.go:45 +0x2de
rbac_admin/internal/bootstrap.Initialize()
    /app/internal/bootstrap/bootstrap.go:25 +0x1e
main.main()
    /app/cmd/server/main.go:44 +0x34

我通过运行了一个busybox,测试网络连通性,如下:

[root@k8s-master01 go-app]# kubectl run -it --rm --image=core.harbor.domain/library/busybox test-dns -- sh
If you don't see a command prompt, try pressing enter.
/ # nslookup external-mysql-pod.default.svc.cluster.local
Server:        10.96.0.10
Address:    10.96.0.10:53


Name:    external-mysql-pod.default.svc.cluster.local
Address: 192.168.205.143

/ # ping 192.168.205.143
PING 192.168.205.143 (192.168.205.143): 56 data bytes
^C
--- 192.168.205.143 ping statistics ---
6 packets transmitted, 0 packets received, 100% packet loss
/ # telnet 192.168.205.143 5000

我甚至在 Cilium 中“开放所有网络规则”,如下:

[root@k8s-master01 ~]# cat cilium.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: allow-all
spec:
  description: "Allow all traffic, disabling network isolation."
  endpointSelector: {} # 空的选择器匹配所有Pod
  ingress:
  - {} # 空的ingress规则允许所有入站流量
  egress:
  - {} # 空的egress规则允许所有出站流量
  # 注意:enableDefaultDeny 字段在此策略下通常无需显式设置,因为策略本身已允许所有流量。

但也是仍然报错:panic: mysql 解析配置失败: dial tcp: lookup external-mysql-pod.default.svc.cluster.local: i/o timeout。所以帮我看看到底如何解决?是哪里出了问题?

  • 写回答

3条回答 默认 最新

  • 檀越@新空间 2025-11-27 19:17
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    你遇到的问题是Kubernetes 集群内的 Pod 无法访问集群外的 MySQL 服务,并且在尝试使用 Headless Service + Endpoints 的方式时,仍然报错:
    lookup external-mysql-pod.default.svc.cluster.local: i/o timeout

    这说明 Pod 无法解析 external-mysql-pod.default.svc.cluster.local 这个 DNS 名称。下面我将从问题原因分析解决方案两方面进行详细说明。


    一、问题原因分析

    1. DNS 解析失败

    错误信息中明确指出:

    lookup external-mysql-pod.default.svc.cluster.local: i/o timeout
    

    这意味着:

    • Kubernetes 中的 Pod 在尝试通过域名 external-mysql-pod.default.svc.cluster.local 访问 MySQL 时,无法解析该域名
    • 原因可能是:
      • DNS 配置不正确(如 /etc/resolv.conf 没有配置正确的 DNS 服务器)。
      • 网络策略限制了外部访问
      • 没有正确配置 Headless Service 和 Endpoints

    2. Headless Service 配置是否正确?

    你定义了一个 Headless ServiceclusterIP: None),但没有为它指定 selectorendpoints 的关联,这可能导致服务未被正确识别。


    二、解决方案

    ✅ 正确配置 Headless Service + Endpoints

    1. 确保 Headless Service 和 Endpoints 关联正确

    你需要让 ServiceEndpoints 关联,Kubernetes 才能知道如何路由流量到外部 IP。

    修改后的 YAML 示例:

    # Headless Service (用于 DNS 解析)
    apiVersion: v1
    kind: Service
    metadata:
      name: external-mysql-pod
    spec:
      ports:
        - port: 5000
      clusterIP: None  # Headless Service
    ---
    # Endpoints (指向外部 MySQL 服务)
    apiVersion: v1
    kind: Endpoints
    metadata:
      name: external-mysql-pod
    subsets:
      - addresses:
          - ip: 192.168.205.143
        ports:
          - port: 5000
    

    注意: 如果你已经创建了这个 ServiceEndpoints,请确认它们是否已正确应用,并且名称一致。


    2. 检查 Pod 的 DNS 配置

    确保你的 Pod 能够访问集群的 DNS 服务(通常是 kube-dnscoredns)。你可以通过以下命令查看 Pod 的 /etc/resolv.conf 文件内容:

    kubectl exec -it <pod-name> -- cat /etc/resolv.conf
    

    如果看到类似以下内容,表示 DNS 配置正常:

    nameserver 10.96.0.10
    search default.svc.cluster.local svc.cluster.local cluster.local
    options ndots:5
    

    如果没有正确配置,请确保:

    • CoreDNS 正常运行

      kubectl get pods -n kube-system | grep coredns
      
    • Pod 使用了正确的 DNS 策略(默认应该是 ClusterFirst)。


    3. 验证 DNS 解析是否生效

    进入 Pod 内部,测试 DNS 解析:

    kubectl exec -it <pod-name> -- nslookup external-mysql-pod.default.svc.cluster.local
    

    如果解析失败,可能是因为:

    • DNS 服务不可用
    • Pod 没有使用集群 DNS(例如设置了 hostNetwork: true)。

    4. 检查网络策略或防火墙规则

    确保:

    • MySQL 服务所在的主机(192.168.205.143) 允许来自 Kubernetes 集群的 Pod 的连接。
    • Kubernetes 集群节点(192.168.205.141) 与 MySQL 服务之间 没有防火墙阻止通信
    • Pod 是否处于正确的网络环境中(比如是否使用了 hostNetwork: false)。

    5. 检查 Go 应用的连接配置

    在你的 ConfigMap 中,你配置了如下内容:

    mysql:
      user: root        
      password: 1234     
      ip: external-mysql-pod.default.svc.cluster.local
      port: 5000         
      database: test
    

    确保这个 ip 字段是正确的,并且 Go 应用能够解析这个域名


    三、推荐的解决步骤(有序列表)

    1. 确认 Headless Service 和 Endpoints 配置正确,确保它们名称一致,且 Endpoints 指向了正确的 IP 地址。
    2. 检查 Pod 的 DNS 配置,确保其可以解析 external-mysql-pod.default.svc.cluster.local
    3. 在 Pod 内部执行 nslookup 测试 DNS 解析,确认域名能否被正确解析。
    4. 检查 MySQL 服务是否可达,从 Kubernetes 节点上尝试连接:
      telnet 192.168.205.143 5000
      
    5. 检查网络策略或防火墙设置,确保没有阻止 Pod 到 MySQL 的连接。
    6. 确保 Go 应用使用的是正确的数据库连接地址,避免硬编码 IP 或错误的 DNS 名称。

    四、代码修改建议(如有需要)

    如果你希望使用 DNS 解析方式,而不是直接写 IP,可以保留如下配置:

    mysql:
      user: root        
      password: 1234     
      ip: external-mysql-pod.default.svc.cluster.local
      port: 5000         
      database: test
    

    但确保:

    • external-mysql-podServiceEndpoints 已正确创建。
    • Pod 能够解析该域名。

    五、总结

    | 问题点 | 解决方案 | |--------|----------| | DNS 解析失败 | 检查 Headless Service 和 Endpoints 配置,确保域名可解析 | | 网络不通 | 检查防火墙、网络策略、MySQL 端口是否开放 | | Go 应用配置错误 | 确保使用了正确的数据库连接地址 |


    如果你能提供 Pod 名称,我可以帮你进一步诊断:

    kubectl describe pod <pod-name>
    kubectl logs <pod-name>
    
    评论

报告相同问题?

问题事件

  • 创建了问题 11月27日