V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cyjme
V2EX  ›  Kubernetes

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

  •  
  •   cyjme · 2022-12-08 14:47:18 +08:00 · 1876 次点击
    这是一个创建于 701 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:

    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 ,如果有描述不恰当的地方还请谅解。

    7 条回复    2024-03-04 09:55:39 +08:00
    GopherDaily
        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.
    cyjme
        2
    cyjme  
    OP
       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
        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 做为后端服务
    xingjue
        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
    cyjme
        5
    cyjme  
    OP
       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
        6
    GopherDaily  
       2022-12-09 22:12:09 +08:00
    @cyjme 不如贴一些 k get -n xxx all ,再给请求加一些日志
    xiaochong2020
        7
    xiaochong2020  
       249 天前
    关掉 servicelb ,你会发现正常了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2628 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:41 · PVG 09:41 · LAX 17:41 · JFK 20:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.