美文网首页
如何在 Kubernetes 中启用 ipvs

如何在 Kubernetes 中启用 ipvs

作者: k8s技术圈 | 来源:发表于2018-08-31 09:46 被阅读1466次

    原文链接:如何在 Kubernetes 中启用 ipvs
    ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCPUDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。

    ipvs vs. iptables

    我们知道kube-proxy支持 iptables 和 ipvs 两种模式, 在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter的,那么 ipvs 模式和 iptables 模式之间有哪些差异呢?

    • ipvs 为大型集群提供了更好的可扩展性和性能
    • ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
    • ipvs 支持服务器健康检查和连接重试等功能

    ipvs 依赖 iptables

    ipvs 会使用 iptables 进行包过滤、SNAT、masquared(伪装)。具体来说,ipvs 将使用ipset来存储需要DROPmasquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了

    下表就是 ipvs 使用的 ipset 集合:

    set name members usage
    KUBE-CLUSTER-IP All service IP + port Mark-Masq for cases that masquerade-all=true or clusterCIDR specified
    KUBE-LOOP-BACK All service IP + port + IP masquerade for solving hairpin purpose
    KUBE-EXTERNAL-IP service external IP + port masquerade for packages to external IPs
    KUBE-LOAD-BALANCER load balancer ingress IP + port masquerade for packages to load balancer type service
    KUBE-LOAD-BALANCER-LOCAL LB ingress IP + port with externalTrafficPolicy=local accept packages to load balancer with externalTrafficPolicy=local
    KUBE-LOAD-BALANCER-FW load balancer ingress IP + port with loadBalancerSourceRanges package filter for load balancer with loadBalancerSourceRanges specified
    KUBE-LOAD-BALANCER-SOURCE-CIDR load balancer ingress IP + port + source CIDR package filter for load balancer with loadBalancerSourceRanges specified
    KUBE-NODE-PORT-TCP nodeport type service TCP port masquerade for packets to nodePort(TCP)
    KUBE-NODE-PORT-LOCAL-TCP nodeport type service TCP port with externalTrafficPolicy=local accept packages to nodeport service with externalTrafficPolicy=local
    KUBE-NODE-PORT-UDP nodeport type service UDP port masquerade for packets to nodePort(UDP)
    KUBE-NODE-PORT-LOCAL-UDP nodeport type service UDP port with externalTrafficPolicy=local accept packages to nodeport service with externalTrafficPolicy=local

    在以下情况下,ipvs 将依赖于 iptables:

    1. kube-proxy 配置参数 --masquerade-all=true

    如果 kube-proxy 配置了--masquerade-all=true参数,则 ipvs 将伪装所有访问 Service 的 Cluster IP 的流量,此时的行为和 iptables 是一致的,由 ipvs 添加的 iptables 规则如下:

    # iptables -t nat -nL
    
    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    
    Chain KUBE-MARK-MASQ (2 references)
    target     prot opt source               destination
    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
    
    Chain KUBE-POSTROUTING (1 references)
    target     prot opt source               destination
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src
    
    Chain KUBE-SERVICES (2 references)
    target     prot opt source               destination
    KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
    

    2. 在 kube-proxy 启动时指定集群 CIDR

    如果 kube-proxy 配置了--cluster-cidr=<cidr>参数,则 ipvs 会伪装所有访问 Service Cluster IP 的外部流量,其行为和 iptables 相同,假设 kube-proxy 提供的集群 CIDR 值为:10.244.16.0/24,那么 ipvs 添加的 iptables 规则应该如下所示:

    # iptables -t nat -nL
    
    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    
    Chain KUBE-MARK-MASQ (3 references)
    target     prot opt source               destination
    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
    
    Chain KUBE-POSTROUTING (1 references)
    target     prot opt source               destination
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src
    
    Chain KUBE-SERVICES (2 references)
    target     prot opt source               destination
    KUBE-MARK-MASQ  all  -- !10.244.16.0/24       0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
    

    3. Load Balancer 类型的 Service

    对于loadBalancer类型的服务,ipvs 将安装匹配 KUBE-LOAD-BALANCER 的 ipset 的 iptables 规则。特别当服务的 LoadBalancerSourceRanges 被指定或指定 externalTrafficPolicy=local 的时候,ipvs 将创建 ipset 集合KUBE-LOAD-BALANCER-LOCAL/KUBE-LOAD-BALANCER-FW/KUBE-LOAD-BALANCER-SOURCE-CIDR,并添加相应的 iptables 规则,如下所示规则:

    # iptables -t nat -nL
    
    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    
    Chain KUBE-FIREWALL (1 references)
    target     prot opt source               destination
    RETURN     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER-SOURCE-CIDR dst,dst,src
    KUBE-MARK-DROP  all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain KUBE-LOAD-BALANCER (1 references)
    target     prot opt source               destination
    KUBE-FIREWALL  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER-FW dst,dst
    RETURN     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER-LOCAL dst,dst
    KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain KUBE-MARK-DROP (1 references)
    target     prot opt source               destination
    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x8000
    
    Chain KUBE-MARK-MASQ (2 references)
    target     prot opt source               destination
    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
    
    Chain KUBE-POSTROUTING (1 references)
    target     prot opt source               destination
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src
    
    Chain KUBE-SERVICES (2 references)
    target     prot opt source               destination
    KUBE-LOAD-BALANCER  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOAD-BALANCER dst,dst
    

    4. NodePort 类型的 Service

    对于 NodePort 类型的服务,ipvs 将添加匹配KUBE-NODE-PORT-TCP/KUBE-NODE-PORT-UDP的 ipset 的iptables 规则。当指定externalTrafficPolicy=local时,ipvs 将创建 ipset 集KUBE-NODE-PORT-LOCAL-TC/KUBE-NODE-PORT-LOCAL-UDP并安装相应的 iptables 规则,如下所示:(假设服务使用 TCP 类型 nodePort)

    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    
    Chain KUBE-MARK-MASQ (2 references)
    target     prot opt source               destination
    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
    
    Chain KUBE-NODE-PORT (1 references)
    target     prot opt source               destination
    RETURN     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-NODE-PORT-LOCAL-TCP dst
    KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0
    
    Chain KUBE-POSTROUTING (1 references)
    target     prot opt source               destination
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src
    
    Chain KUBE-SERVICES (2 references)
    target     prot opt source               destination
    KUBE-NODE-PORT  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-NODE-PORT-TCP dst
    

    5. 指定 externalIPs 的 Service

    对于指定了externalIPs的 Service,ipvs 会安装匹配KUBE-EXTERNAL-IP ipset 集的 iptables 规则,假设我们有指定了 externalIPs 的 Service,则 iptables 规则应该如下所示:

    Chain PREROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain OUTPUT (policy ACCEPT)
    target     prot opt source               destination
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    
    Chain POSTROUTING (policy ACCEPT)
    target     prot opt source               destination
    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
    
    Chain KUBE-MARK-MASQ (2 references)
    target     prot opt source               destination
    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
    
    Chain KUBE-POSTROUTING (1 references)
    target     prot opt source               destination
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000
    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-LOOP-BACK dst,dst,src
    
    Chain KUBE-SERVICES (2 references)
    target     prot opt source               destination
    KUBE-MARK-MASQ  all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst PHYSDEV match ! --physdev-is-in ADDRTYPE match src-type !LOCAL
    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-EXTERNAL-IP dst,dst ADDRTYPE match dst-type LOCAL
    

    kube-proxy 使用 ipvs 模式

    目前,本地化脚本、GCE 脚本和kubeadm支持通过导入环境变量或者指定标志来切换 ipvs 代理模式

    要求

    确保 ipvs 需要的内核模块,需要下面几个模块:ip_vs、ip_vs_rr、ip_vs_wrr、ip_vs_sh、nf_conntrack_ipv4

    已编译到节点内核中的,可以使用如下命令检查:

    $ grep -e ipvs -e nf_conntrack_ipv4 /lib/modules/$(uname -r)/modules.builtin
    # 如果相关内核模块已经编译到内核中,可以得到如下结果:
    kernel/net/ipv4/netfilter/nf_conntrack_ipv4.ko
    kernel/net/netfilter/ipvs/ip_vs.ko
    kernel/net/netfilter/ipvs/ip_vs_rr.ko
    kernel/net/netfilter/ipvs/ip_vs_wrr.ko
    kernel/net/netfilter/ipvs/ip_vs_lc.ko
    kernel/net/netfilter/ipvs/ip_vs_wlc.ko
    kernel/net/netfilter/ipvs/ip_vs_fo.ko
    kernel/net/netfilter/ipvs/ip_vs_ovf.ko
    kernel/net/netfilter/ipvs/ip_vs_lblc.ko
    kernel/net/netfilter/ipvs/ip_vs_lblcr.ko
    kernel/net/netfilter/ipvs/ip_vs_dh.ko
    kernel/net/netfilter/ipvs/ip_vs_sh.ko
    kernel/net/netfilter/ipvs/ip_vs_sed.ko
    kernel/net/netfilter/ipvs/ip_vs_nq.ko
    kernel/net/netfilter/ipvs/ip_vs_ftp.ko
    

    已经加载。

    # 加载模块 <module_name>
    modprobe -- ip_vs
    modprobe -- ip_vs_rr
    modprobe -- ip_vs_wrr
    modprobe -- ip_vs_sh
    modprobe -- nf_conntrack_ipv4
    
    # 检查加载的模块
    lsmod | grep -e ipvs -e nf_conntrack_ipv4
    # 或者
    cut -f1 -d " "  /proc/modules | grep -e ip_vs -e nf_conntrack_ipv4
    

    在使用 ipvs 模式之前,还应在节点上安装ipset相关的软件包,如果不满足需求 kube-proxy 会回退到 iptables 的模式。

    本地集群

    本地集群中 kube-proxy 默认会运行 iptables 的模式。
    要使用 ipvs 模式,在启动集群之前需要导入KUBE_PROXY_MODE=ipvs的环境变量:

    # 运行脚本 hack/local-up-cluster.sh 之前
    export KUBE_PROXY_MODE=ipvs
    

    GCE 集群

    和本地集群一样,GCE 集群中的 kube-proxy 默认也是 iptables 模式,在启动集群之前同样需要导入环境变量KUBE_PROXY_MODE=ipvs:

    # 运行前选择下面的一条命令启动集群:
    # curl -sS https://get.k8s.io | bash
    # wget -q -O - https://get.k8s.io | bash
    # cluster/kube-up.sh
    export KUBE_PROXY_MODE=ipvs
    

    使用 kubeadm 搭建的集群

    通过kubeadm部署的集群中 kube-proxy 同样默认是 iptables 模式。

    如果你是通过配置文件来使用的 kubeadm,则可以在kubeProxy属性下面添加SupportIPVSProxyMode: true来启用 ipvs 模式:

    kind: MasterConfiguration
    apiVersion: kubeadm.k8s.io/v1alpha1
    ...
    kubeProxy:
      config:
        mode: ipvs
    ...
    

    然后执行初始化命令即可:

    $ kubeadm init --config <path_to_configuration_file>
    

    如果你使用的是 v1.8 版本的 kubernetes,你也可以在kubeadm init命令中增加--feature-gates=SupportIPVSProxyMode=true标志来来启用 ipvs 模式:

    $ kubeadm init --feature-gates=SupportIPVSProxyMode=true
    

    注意该参数在 v1.9 后已经弃用掉了

    注意

    如果成功启用了 ipvs 模式,你应该可以使用ipvsadm之类的工具看到如下的一些 ipvs 代理规则:

     # ipvsadm -ln
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
      -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
    TCP  10.0.0.1:443 rr persistent 10800
      -> 192.168.0.1:6443             Masq    1      1          0
    

    或者在 kube-proxy 日志中可以看到如下的一些日志信息:

    Using ipvs Proxier.
    

    当没有这些 ipvs 代理规则或者出现了下面的这些日志信息的时候表明 kube-proxy 的 ipvs 模式启用失败了:

    Can't use ipvs proxier, trying iptables proxier
    Using iptables Proxier.
    

    可以参考下面的调试方法进行错误信息排查

    调试

    检查 ipvs 代理规则

    用户可以使用ipvsadm工具检查 kube-proxy 是否维护正确的 ipvs 规则,比如,我们在集群中有以下一些服务:

    $ kubectl get svc --all-namespaces
    NAMESPACE     NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
    default       kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP         1d
    kube-system   kube-dns     ClusterIP   10.0.0.10    <none>        53/UDP,53/TCP   1d
    

    我们可以得到如下的一些 ipvs 代理规则:

     # ipvsadm -ln
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
      -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
    TCP  10.0.0.1:443 rr persistent 10800
      -> 192.168.0.1:6443             Masq    1      1          0
    TCP  10.0.0.10:53 rr
      -> 172.17.0.2:53                Masq    1      0          0
    UDP  10.0.0.10:53 rr
      -> 172.17.0.2:53                Masq    1      0          0
    

    为什么 kube-proxy 无法启动 ipvs模式

    可以使用下面的一些方法来帮助我们解决这些问题:

    1. 启用 ipvs feature gate

    对于 kubernetes v1.10 版本之后,feature gate SupportIPVSProxyMode已经被默认设置为true了,但是如果你是 v1.10 之前的版本,你需要手动设置--feature-gates=SupportIPVSProxyMode=true来启用该 feature。

    2. 指定 proxy-mode=ipvs

    检查 kube-proxy 的 model 是否被设置为了ipvs

    3. 安装需要的内核模块和软件包

    检查 ipvs 需要的内核模块是否已经被编译进内核模块中,以及需要的软件包(可以参考前面的环境要求部分)

    扫描下面的二维码(或微信搜索k8s技术圈)关注我们的微信公众帐号,在微信公众帐号中回复 加群 即可加入到我们的 kubernetes 讨论群里面共同学习。

    qrcode

    相关文章

      网友评论

          本文标题:如何在 Kubernetes 中启用 ipvs

          本文链接:https://www.haomeiwen.com/subject/wqtswftx.html