大白话搞懂k8s网络,轻松应对web服务的开发调试
文章讲解k8s网络调试,核心是分清Pod、Node、Cluster三者身份。集群内节点(Master/Worker)可直接访问PodIP、ClusterIP和Service域名;集群外机器不能直连,需使用kubectl port-forward、NodePort等方式。开发自测推荐port-forward,但不能用于生产。集群内微服务调用应统一使用SVC域名,禁止硬编码IP,跨命名空间需写完整域名。容器服务需监听0.0.0.0,否则无法被外部调用。
web服务开发好了,部署到k8s上了,前端调用不符合预期,仅仅看日志经常会很棘手,知道怎样做接口测试,debug直连环境能解决所有问题。开发调k8s服务,永远卡在网络问题,本质原因就一个:没分清 Pod、Node、Cluster 三者的身份,搞不懂谁能访问谁。
核心概念
- Node: 节点,可以是一台物理机,可以是一台虚拟机
- Cluster:集群,可以认为是一套完整的系统,如果在一个节点上搭建k8s叫单节点环境,如果在多个节点上搭建k8s叫多节点环境(常说的高可用环境)
- Pod:部署在 Node 内部,K8s 最小运行单元,跑业务容器(如我们的 Golang 服务)
┌─────────────────────────────────────────────────────────────┐
│ Cluster(K8s集群) │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ Node 节点 B │ │ Node 节点 C │ │
│ │ (物理/虚拟机服务器) │ │ (物理/虚拟机服务器) │ │
│ │ │ │ │ │
│ │ ┌──────┐ ┌──────┐ │ │ ┌──────┐ ┌──────┐ │ │
│ │ │ Pod1 │ │ Pod2 │ │ │ │ Pod3 │ │ Pod4 │ │ │
│ │ │user服务│ │order │ │ │ │ 其他 │ │ 其他 │ │ │
│ │ └──────┘ └──────┘ │ │ └──────┘ └──────┘ │ │
│ └──────────────────────┘ └──────────────────────┘ │
│ │
│ ┌──────────────────────┐ │
│ │ Master Node A │ │
│ │ 控制平面:调度、管理 │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
▲ │ 集群外(D机器 / 开发本地电脑,不能直连PodIP)
先理清环境,机器清单:
- A:Master 控制节点(属于 K8s 集群节点)
- B、C:Worker Node 工作节点(属于 K8s 集群节点)
- D:独立机器,不在集群内(集群外)
集群:A+B+C 组成一套 K8s,Pod 运行在 B / C 上,存在 PodIP、Service (ClusterIP)。
核心结论前置:
✅ A、B、C 都属于集群内节点:可以直接访问 PodIP、ClusterIP、Service 域名 ❌ D 属于集群外机器:不能直连 PodIP / ClusterIP,必须走端口转发、NodePort、Ingress、LoadBalancer
访问场景
场景 1:在 A 机器(Master 节点)访问 B/C 上的 Pod、SVC
A 是集群一员,属于集群内访问
方式一:直接访问PodIP
# 在A机器执行
curl http://<B上PodIP>:8080
curl http://<C上PodIP>:8080
方式二:访问Service
curl http://<svc-clusterip>:8080
# 同命名空间还可以用svc名称访问(需要节点配置集群DNS解析,或者手动配置)
curl http://demo-svc:8080
# 完整域名
curl http://demo-svc.dev.svc.cluster.local:8080
场景 2:在 B 机器(Worker 节点)访问 B/C 上的 Pod、SVC
B 也是集群一员,访问同上
场景 3:在 D 机器(集群外独立机器)访问 B/C 的 Pod、SVC
D 不在集群网络平面,无法直接连通 PodIP、ClusterIP
方案一:kubectl port-forward(开发自测首选,临时用)
kubectl port-forward svc/demo-svc 8888:8080 -n dev --address 0.0.0.0
方案二:SVC 配置 NodePort 后,会在所有集群节点(A/B/C)开放同一个端口
spec:
type: NodePort
ports:
- port: 8080
targetPort: 8080
nodePort: 30080
D 机器访问:
curl http://B机器物理IP:30080
curl http://C机器物理IP:30080
port-forward 端口转发实战
port-forward 是开发自测神器,底层是打通「本地电脑 ↔ 集群」的临时隧道,不用改集群配置、不用暴露公网,用完即走,专门解决外网机器调试集群服务的问题。
- 转发Service(推荐!日常自测首选)
- 转发单个Pod (仅排错使用)
- 后台常驻转发 (解决终端关闭即断开问题)
# 格式:kubectl port-forward svc/服务名 本地端口:集群SVC端口 -n 命名空间
kubectl port-forward svc/order-svc 8888:8080 -n dev
# 格式:kubectl port-forward pod/POD名称 本地端口:容器端口 -n 命名空间
kubectl port-forward pod/order-7f9685796c-2xgq7 8888:8080 -n dev
nohup kubectl port-forward svc/order-svc 8888:8080 -n dev > /dev/null 2>&1
集群内服务互调
集群内微服务调用,**禁止硬编码任何 IP!**统一使用 SVC 域名,依靠 K8s CoreDNS 自动解析,适配所有环境。
域名规则:
- 同命名空间:服务名:端口
- 跨命名空间:服务名.命名空间.svc.cluster.local:端口
// 优先读取环境变量,本地调试用本地地址,集群自动用SVC域名
func getOrderURL() string {
envURL := os.Getenv("ORDER_SERVICE_URL")
if envURL != "" {
return envURL
}
// 集群内跨命名空间调用标准域名
return "http://order-svc.test.svc.cluster.local:8080"
}
func callOrderAPI() error {
resp, err := http.Get(getOrderURL() + "/health")
if err != nil {
return fmt.Errorf("调用订单服务失败: %w", err)
}
defer resp.Body.Close()
res, _ := io.ReadAll(resp.Body)
fmt.Println("调用成功,响应:", string(res))
return nil
}
结尾总结:
- PodIP/ClusterIP 是集群内网地址,外网无法直接访问,不是故障是机制
- port-forward 仅用于开发自测,绝对不用于生产对外服务
- 集群内调用只认 SVC 域名,拒绝硬编码 IP,避免扩容重建后失效
- 跨命名空间调用必须写完整域名,简写无法 DNS 解析
- 容器服务需监听 0.0.0.0,监听 127.0.0.1 会导致无法被外部调用
评论 (0)