背景:
最近刚开始使用 k8s, 用多台服务器组了集群,服务器在不同地区,服务器之间网速较慢。
load balancer 用的是 k3s 自带的,ingress type 是 traefik 。
我将网站 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 ,如果有描述不恰当的地方还请谅解。
1
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. |
2
cyjme OP @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 ? 有没有什么其他方法呢? |
3
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 做为后端服务 |
4
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 |
5
cyjme OP @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 配置。后续有结果了我再更新到这里。 |
6
GopherDaily 2022-12-09 22:12:09 +08:00
@cyjme 不如贴一些 k get -n xxx all ,再给请求加一些日志
|
7
xiaochong2020 276 天前
关掉 servicelb ,你会发现正常了
|