Docker Desktop单节点K8s集群端口转发至LoadBalancer的负载均衡异常问题
问题现象
在Windows主机的Docker Desktop单节点K8s集群中部署了5副本的Web应用,搭配LoadBalancer类型的Service,Web应用返回主机名用于验证负载均衡效果。集群内通过curl访问该LoadBalancer Service时,流量能正常分发到不同Pod;但执行kubectl port-forward service/mywebapp-svc :80将端口转发到Windows主机后,本地浏览器或curl访问始终指向同一个Pod,清除缓存、更换浏览器都无法解决。
相关配置
apiVersion: apps/v1 kind: Deployment metadata: name: mydeployment labels: app: mywebapp spec: replicas: 5 selector: matchLabels: app: mywebapp template: metadata: labels: app: mywebapp spec: containers: - name: mycontainer image: mywebapp:latest ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: mywebapp-svc spec: type: LoadBalancer selector: app: mywebapp ports: - port: 80 protocol: TCP
原因分析
kubectl port-forward的工作机制是直接在本地主机与单个后端Pod之间建立TCP转发通道,完全绕过Service的负载均衡逻辑:
- 执行
kubectl port-forward service/<service-name>时,kubectl会随机挑选一个匹配Service标签的Pod建立连接; - 通道建立后,所有本地流量都会固定转发到这个Pod,不会触发kube-proxy的iptables/IPVS负载均衡规则;
- 集群内访问Service时,流量是通过kube-proxy的规则实现分发,和port-forward的直接转发机制完全不同。
解决办法
1. 改用NodePort类型的Service
修改Service为NodePort类型,K8s会将Service暴露到节点的一个端口上,本地访问该端口时流量会经过kube-proxy的负载均衡,分发到不同Pod。
修改后的Service配置:
apiVersion: v1 kind: Service metadata: name: mywebapp-svc spec: type: NodePort selector: app: mywebapp ports: - port: 80 protocol: TCP nodePort: 30080 # 可选,指定固定端口,不填则自动分配30000-32767范围内的端口
部署后,直接访问localhost:30080即可看到负载均衡效果。
2. 转发Deployment并手动做本地负载(临时方案)
执行kubectl port-forward deployment/mydeployment :80,每次执行该命令kubectl会随机选择一个Pod,但单条命令只能绑定一个Pod。如果需要本地负载均衡,可以多次执行该命令绑定不同端口(比如kubectl port-forward deployment/mydeployment 8081:80、kubectl port-forward deployment/mydeployment 8082:80等),然后用Nginx或其他工具做一层反向代理,将流量分发到这些端口。
3. 启用Docker Desktop Ingress Controller
开启Docker Desktop的Ingress功能后,配置Ingress资源指向你的Service,通过本地域名访问,Ingress会负责将流量负载均衡到各个Pod。
示例Ingress配置:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: mywebapp-ingress spec: rules: - host: mywebapp.local http: paths: - path: / pathType: Prefix backend: service: name: mywebapp-svc port: number: 80
在Windows的hosts文件中添加127.0.0.1 mywebapp.local,之后访问http://mywebapp.local即可实现负载均衡。
内容的提问来源于stack exchange,提问作者Sebastian Dine

