k3s 中的负载均衡如何能够直接把域名解析到当前节点的 pod?

2022-12-08 14:47:18 +08:00
 cyjme

背景:

  1. 最近刚开始使用 k8s, 用多台服务器组了集群,服务器在不同地区,服务器之间网速较慢。

  2. load balancer 用的是 k3s 自带的,ingress type 是 traefik 。

  3. 我将网站 pod 部署在了 nodeA 节点, nodeA, nodeB 不在同一地区。

然后我理解的目前我的网站被访问时的路径是:

user requset ---[1]--> node A(svclb-pod) ---[2]---> node B(traefik service 所在节点) ---[3]---> nodeA(website-pod)-----> response 反向传回去

我希望请求到 load balancer 之后,直接就能转发到 nodeA (website-pod),而不经过跨地区的网络传输。

也就是 user request -----> nodeA(svclb-pod)---->nodeA(website-pod)---->response

这样不跨地区访问 nodeB 之后,网站速度就能更快一些。请问有办法实现这种需求吗?

刚接触 k8s ,如果有描述不恰当的地方还请谅解。

1898 次点击
所在节点    Kubernetes
7 条回复
GopherDaily
2022-12-08 15:15:18 +08:00
Google is your friends, https://www.google.com.hk/search?q=k8s+loadbalancer+local&oq=k8s+loadbalancer+local&aqs=chrome..69i57j0i22i30l2j0i10i22i30j0i390l5.7176j0j7&sourceid=chrome&ie=UTF-8

https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip

.spec.externalTrafficPolicy - denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. There are two available options: Cluster (default) and Local. Cluster obscures the client source IP and may cause a second hop to another node, but should have good overall load-spreading. Local preserves the client source IP and avoids a second hop for LoadBalancer and NodePort type Services, but risks potentially imbalanced traffic spreading.
cyjme
2022-12-08 18:33:16 +08:00
@GopherDaily 感谢。

根据文档看起来好像是和 externalTrafficPolicy 有一些关系,我做了尝试之后,发现 externalTrafficPolicy 可以产生如下如下影响:

cluster: nodeA, nodeB, nodeC

blog-servcie ( type: NodePort, port:30025), blog-pod 只运行在 nodeA ,

将 externalTrafficPolicy 设为 Local 后,只有 http://nodeA:30025 可以访问,nodeB:30025 无法访问。externalTrafficPolicy 默认的 Cluster 所有节点都可以访问这个端口。


** 但是这个并不能解决当下的问题: **

以 http://blog.domain 为例,ip 指向 nodeA, blog-pod 运行在 nodeA, nodeB, nodeC 三个节点上,blog-service 的 externalTrafficPolicy 设为 Local ,当访问 blog.domain 的时候,nodeB 和 nodeC 依然会分流收到请求。

期望结果是 只有 nodeA 上的 blog-pod 能收到请求。

我查看了 nodeA 的 svclb-pod 中的 iptables ,它只是把所有流量都转发到了 traefik 的 service ,而 traefik pod 实际只运行在 nodeB ,所以流量必然要先经过 nodeB ?

有没有什么其他方法呢?
GopherDaily
2022-12-08 22:54:19 +08:00
理论上 Service 的 externalTrafficPolicy 设置为 Local 后,从外部访问 Service 的流量到达某个节点后是不会再被路由到的另外一个节点的。

所以外部流量到 nodeA 上后会去找 nodeA 上的 traefik ,而不会尝试找 nodeB 上的 traefik.
traefik 收到这个请求后将请求转发给 website 这个 服务,这次转发依赖其他配置了。

你 的 svclb-pod 是什么意思? Service 是一个逻辑概念,Traefik 是实际的 Pod


以阿里云为例的常见架构:
固定 IP 的 SLB 用来承载 DNS 解析,
Nginx/Envoy 做为 IngressGateway ,并注册类似为 LoadBalancer 的 Service
某个 Controller 监听这个 Service 并自动注册到 SLB 做为后端服务
xingjue
2022-12-08 23:20:05 +08:00
在 k3s 中,负载均衡是由 ingress controller 来实现的,具体实现方式取决于选择的 ingress controller 类型。

对于您所描述的情况,我们可以通过设置 ingress 的路由规则来实现直接将域名解析到当前节点的 pod 。

首先,您需要为您的应用创建一个 ingress 资源,并设置域名和路径的路由规则。例如:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: my-website.com
http:
paths:
- path: /
backend:
serviceName: my-website
servicePort: 80

然后,您需要为您的 ingress 资源添加一个节点选择器,以确保请求只能被路由到目标节点上。例如:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
labels:
app: my-website
annotations:
# 指定 ingress 资源只能被 nodeA 节点上的 ingress controller 处理
ingress.kubernetes.io/affinity: "cookie"
ingress.kubernetes.io/session-cookie-name: "ingress-lb-node"
ingress.kubernetes.io/session-cookie-enabled: "true"
ingress.kubernetes.io/session-cookie-max-age: "86400"
ingress.kubernetes.io/session-cookie-generate-request-header: "true"
spec:
rules:
- host: my-website.com
http:
paths:
- path: /
backend:
serviceName: my-website
servicePort: 80
# 指定 ingress 资源只能被 nodeA 节点上的 ingress controller 处理
nodeSelector:
kubernetes.io/hostname: nodeA
cyjme
2022-12-09 18:07:43 +08:00
@GopherDaily

今天折腾了很多,这里重新梳理下,我前面的关注点太多了,下面只关注流量到达 traefik pod

前面的 svclb-pod 是由 k3s 自带的一个 Load Balancer(Klipper LB)创建的 daemon 。


**当前的环境:**

有一个类型为 LoadBalancer 的 traefik service, load balance 是通过 KipperLB 实现的。Traefik
Service 创建了 Daemon Sets: "svclb-traefik",运行在每一个节点上,监听 80/443 端口。

将 traefik deployment scale 到每个节点上都有一个,并且开启了 access log 。

设置 traefik service 的 spec.externalTrafficPolicy = Local 。



**问题:**

理论上来说,应该只有被访问的节点上的 traefik pod 可以收到请求,但是目前是其他节点也可以收到。






今天刚开始调试的时候看日志是大部分请求都到了同一个节点的,但是会有少量请求到其他节点,以为是配置生效了,怀疑可能是网络的问题(用了 zerotier ,k3s server --flannel-iface={zerotier-Iface}),worker node 在国外,网络质量不够高之类的,但是调试一番之后,其实还是配置没生效,只是我之前只请求一个 url ,似乎有某种机制让请求只到达一个节点?只要换了 url 其他节点也会收到大量请求。externalTrafficPolicy = Local 生效的话,应该是其他节点完全收不到请求才对。


然后又查了一些其他资料,也有人遇到这个问题,但没有明确的答案。可能会和 k3s 的 Klipper LB 有关系,更细节的调试还要涉及到 cni, flannel 还有 k8s 的各种命令。但是我现在这方面知识缺失很多,排查问题过程很艰难。我周末把 k8s 的文档和网络相关的文档先看一遍,然后再重新排查这个问题,可能还要重新搞一个虚拟机环境,尝试不同的 lb 和 cni 配置。后续有结果了我再更新到这里。
GopherDaily
2022-12-09 22:12:09 +08:00
@cyjme 不如贴一些 k get -n xxx all ,再给请求加一些日志
xiaochong2020
265 天前
关掉 servicelb ,你会发现正常了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/901082

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX