当前位置: 首页 > news >正文

Kubernetes ClusterIP 端口深度解析:虚拟服务与流量转发机制

事情的起因是创建了一个 NodePort 类型 Service,其端口映射关系为 8000:30948/TCP。既然30948是在每个node开的端口,那8000是开在哪的呢?出于好奇回顾了一下K8s的Cluster IP和Service


端口映射关系解析

在 Kubernetes 的 NodePort Service 中,端口配置遵循以下格式:

<ClusterIP 端口>:<NodePort 端口>/<协议>
  • 8000:Service 的 ClusterIP 端口(集群内部访问端口)
  • 30948:NodePort 端口(节点外部访问端口)
外部用户
节点IP:30948
集群内部Pod
Service IP:8000
Service
后端Pod

访问测试结果

1. 在宿主机上访问 IP:8000
curl http://<节点IP>:8000

结果:连接失败
原因:

  • 8000 端口仅在集群内部监听(通过 Service 的 ClusterIP)
  • 节点操作系统没有在 8000 端口监听请求
2. 在宿主机上访问 IP:30948
curl http://<节点IP>:30948

结果:成功访问服务
原因:

  • kube-proxy 在所有节点上监听了 30948 端口
  • 流量会被转发到 Service 的后端 Pod

技术原理详解

1. NodePort 工作原理

当创建 NodePort Service 时:

  1. kube-proxy 在所有节点上打开指定端口(30948)

  2. 创建 iptables/IPVS 规则:

    -A KUBE-NODEPORTS -p tcp --dport 30948 -j KUBE-SVC-XXXXXX
    
  3. 流量转发路径:

    外部用户 → 节点IP:30948 → kube-proxy → Service → Pod
    
2. ClusterIP 端口用途
  • 集群内部访问入口:

    # 在集群内部Pod中访问
    curl http://my-dep.default.svc.cluster.local:8000
    
  • 服务发现的基础端口


实际验证步骤

1. 查看 Service 完整定义
kubectl describe svc my-dep

输出关键部分:

Port:             8000/TCP
TargetPort:       80/TCP  # 后端Pod实际端口
NodePort:         30948/TCP
Endpoints:        10.244.1.2:80,10.244.2.3:80 # 后端Pod IP
2. 测试端口访问
# 1. 访问NodePort (应成功)
curl http://<任一节点IP>:30948# 2. 访问ClusterIP端口 (应失败)
curl http://<节点IP>:8000# 3. 在集群内部访问 (在Pod中执行)
kubectl run test --image=busybox -it --rm --restart=Never -- \wget -qO- http://my-dep:8000
3. 检查节点端口监听
# 在K8s节点上执行
sudo netstat -tuln | grep 30948
# 应输出: tcp6  0  0 :::30948  :::*  LISTEN

那么回到最开始的问题,8000端口开在哪呢?

如果你采用的是原生搭建k8s,那么你一定会记得初始化的时候有这样一个命令

kubeadm init \
--apiserver-advertise-address=172.31.0.4 \
--control-plane-endpoint=cluster-endpoint \
--image-repository registry.cn-hangzhou.aliyuncs.com/k8s_images \
--kubernetes-version v1.20.9 \
--service-cidr=10.96.0.0/16 \
--pod-network-cidr=192.168.0.0/16

在这里就指定了创建svc和pod的网段

集群内部访问端口的本质

ClusterIP 端口是 Kubernetes 服务抽象层的核心设计。

请求 10.96.91.238:8000
Client Pod
Service ClusterIP
iptables/IPVS 规则
Pod 1:80
Pod 2:80
Pod 3:80

ClusterIP 端口的三层抽象

1. 虚拟 IP 层 (Service ClusterIP)

  • 非真实接口:ClusterIP (如 10.96.91.238) 是 kube-proxy 创建的虚拟 IP
  • 无端口监听:节点操作系统上没有进程真正监听 8000 端口
  • 内核级拦截:通过 Linux 内核的 netfilter 框架实现流量拦截

2. 规则转发层 (kube-proxy)

kube-proxy 创建转发规则(以 iptables 为例):

# 查看 Service 规则链
sudo iptables -t nat -L KUBE-SERVICES# 示例输出
KUBE-SVC-XYZ  tcp  --  anywhere  10.96.91.238  tcp dpt:8000

具体规则细节:

# DNAT 规则
-A KUBE-SVC-XYZ -m statistic --mode random --probability 0.333 -j KUBE-SEP-111
-A KUBE-SVC-XYZ -m statistic --mode random --probability 0.5 -j KUBE-SEP-222
-A KUBE-SVC-XYZ -j KUBE-SEP-333# 终结点规则
-A KUBE-SEP-111 -p tcp -m tcp -j DNAT --to-destination 10.244.1.2:80
-A KUBE-SEP-222 -p tcp -m tcp -j DNAT --to-destination 10.244.1.3:80
-A KUBE-SEP-333 -p tcp -m tcp -j DNAT --to-destination 10.244.2.4:80

3. 真实端点层 (Pod)

  • 实际端口监听:在 Pod 内部的容器端口(如配置的 80 端口)

  • Endpoint 对象管理

    apiVersion: v1
    kind: Endpoints
    metadata:name: my-dep
    subsets:
    - addresses:- ip: 10.244.1.2- ip: 10.244.1.3- ip: 10.244.2.4ports:- port: 80protocol: TCP
    

流量转发全路径

当集群内部客户端访问 10.96.91.238:8000 时:

  1. 客户端发起请求

    resp, err := http.Get("http://10.96.91.238:8000")
    
  2. 内核网络栈拦截

    • 目标 IP 匹配 Service CIDR (如 10.96.0.0/16)
    • 进入 KUBE-SERVICES
  3. DNAT 转换

    • 根据 iptables 规则
    • 目标 IP:Port 被替换为 Pod IP:Port (如 10.244.1.2:80)
  4. 路由到目标 Pod

    • 通过 CNI 插件创建的网络路由
    • 流量进入 Pod 网络命名空间
  5. 容器接收请求

    • 容器内进程监听 80 端口
    • 处理请求并返回响应

与 NodePort 的关键区别

特性ClusterIP 端口 (8000)NodePort 端口 (30948)
可见性仅集群内部可见可从集群外部访问
实现层级内核网络栈 (L3/L4)用户空间监听 (L4)
监听位置无真实监听,仅规则kube-proxy 进程真实监听
访问控制受网络策略控制受节点防火墙控制
性能开销低(内核转发)中(用户态转发)
数据包变化目标地址被修改目标地址不变

查看内核规则

在任意节点执行:

# 查看NAT表规则
sudo iptables -t nat -L KUBE-SERVICES -n --line-numbers# 查找Service规则
sudo iptables -t nat -L KUBE-SVC-$(kubectl get svc my-dep -o jsonpath='{.spec.ports[0].name}') -n

为什么需要 ClusterIP

  1. 稳定访问端点
    Pod 可能随时重建,但 Service IP 保持不变

  2. 负载均衡
    自动将流量分发到多个后端 Pod

  3. 服务发现
    通过 DNS 名称解耦服务位置

  4. 流量策略
    支持会话保持、流量权重等高级特性

  5. 安全隔离
    默认仅集群内部可访问,减少攻击面

生产环境实践

  1. 避免直接使用 NodePort 配合 Ingress 或 LoadBalancer 使用:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:name: my-ingress
    spec:rules:- http:paths:- path: /pathType: Prefixbackend:service:name: my-depport:number: 8000  # 使用ClusterIP端口
    
  2. 自定义 NodePort 范围 修改 apiserver 配置:

    apiServer:extraArgs:service-node-port-range: "30000-35000"
    
  3. 防火墙规则 仅开放必要的 NodePort 端口:

    sudo ufw allow 30948/tcp
    
http://www.xdnf.cn/news/951553.html

相关文章:

  • 我的世界Java版1.21.4的Fabric模组开发教程(十三)自定义方块状态
  • 椭圆曲线密码学(ECC)
  • 基于ADMM的MRI-PET高质量图像重建算法
  • 【Linux】进程间通讯-消息队列
  • PHP:Web 开发的经典利器
  • 我如何使用 CodeMCP 进行开发并控制其他编程助手的预算
  • nodejs express 打包部署
  • VR 技术赋能南锣鼓巷的多元发展潜力与前景​
  • 多模态图像修复系统:基于深度学习的图片修复实现
  • Android Kotlin 协程详解
  • Python 中的加密库:守护数据安全的利刃
  • 8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
  • 拟合问题处理
  • C# dll版本冲突解决方案
  • 运放——单电源供电和双电源供电
  • 商品中心—1.B端建品和C端缓存的技术文档一
  • 消息队列系统设计与实践全解析
  • 规则与人性的天平——由高考迟到事件引发的思考
  • NSS-DAY12
  • 2.2.2 ASPICE的需求分析
  • CopyQ | 在命令中使用正则表达式并实现匹配指定字符串的方法
  • 大话软工笔记—需求分析概述
  • 安宝特案例丨又一落地,Vuzix AR眼镜助力亚马逊英国仓库智能化升级!
  • games101 hw1
  • 密码是什么(三):多表代替密码
  • ​​企业大模型服务合规指南:深度解析备案与登记制度​​
  • Word VBA快速制作填空题
  • configure构建工程
  • 如何高效的组织产品研发团队与产品交付开发团队
  • MeanFlow:何凯明新作,单步去噪图像生成新SOTA