Kubernetes nginx 入口控制器不可靠

Kubernetes nginx ingress controller is unreliable

我需要帮助来详细了解入口控制器,特别是 ingress-nginx 入口控制器应该如何工作。对我来说,它看起来像一个黑盒子,应该监听 public IP,终止 TLS,并将流量转发到 pod。但究竟是如何发生的对我来说是个谜。

这里的主要目标是理解,次要目标是解决我面临的紧迫问题。

我有一个包含五个节点的集群,我正在尝试将 Jupyterhub 应用程序安装到 运行 上。在大多数情况下,它工作正常。我正在使用带有 flannel/calico 的非常标准的 Rancher RKE 设置进行网络连接。节点 运行 带有 iptables 和 firewalld 的 RedHat 7.9,以及 docker 19.03.

Jupyterhub 代理设置了 ClusterIP 服务(我也尝试了 NodePort 服务,它也有效)。我还设置了一个入口。入口有时有效,但通常不响应(连接超时)。具体来说,如果我删除入口,然后重新部署我的 helm chart,入口就会开始工作。此外,如果我重新启动我的一个节点,入口将再次开始工作。入口停止工作的情况我还没有确定。

以下是我的相关服务:

kubectl get services
NAME                       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
hub                        ClusterIP   10.32.0.183   <none>        8081/TCP   378d
proxy-api                  ClusterIP   10.32.0.11    <none>        8001/TCP   378d
proxy-public               ClusterIP   10.32.0.30    <none>        80/TCP     378d

这行得通; telnet 10.32.0.30 80 按预期响应(当然仅来自其中一个节点)。我也可以直接远程登录到代理-public pod(在我的例子中是 10.244.4.41:8000)。

这是我的入口。

kubectl describe ingress
Name:             jupyterhub
Labels:           app=jupyterhub
                  app.kubernetes.io/managed-by=Helm
                  chart=jupyterhub-1.2.0
                  component=ingress
                  heritage=Helm
                  release=jhub
Namespace:        jhub
Address:          k8s-node4.<redacted>,k8s-node5.<redacted>
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
TLS:
  tls-jhub terminates jupyterhub.<redacted>
Rules:
  Host                     Path  Backends
  ----                     ----  --------
  jupyterhub.<redacted>
                           /   proxy-public:http (10.244.4.41:8000)
Annotations:               field.cattle.io/publicEndpoints:
                             [{"addresses":["",""],"port":443,"protocol":"HTTPS","serviceName":"jhub:proxy-public","ingressName":"jhub:jupyterhub","hostname":"jupyterh...
                           meta.helm.sh/release-name: jhub
                           meta.helm.sh/release-namespace: jhub
Events:                    <none>

目前我对这种情况下的入口的理解:

流量到达 k8s-node4 或 k8s-node5 的 443 端口。 一些魔法(由入口控制器控制)接收该流量,终止 TLS,并将未加密的流量发送到端口 8000 的 pod 的 IP。这是我想更好地理解的部分。

那个黑盒子似乎至少部分涉及 flanel/calico 和一些 iptables 魔法,而且它在某些时候显然也涉及 nginx。

更新:与此同时,我确定了导致 Kubernetes 崩溃的原因:重新启动 firewalld。

据我所知,这会清除所有 iptables 规则,而不仅仅是 firewalld 生成的规则。

我在这里找到了问题的答案:https://www.stackrox.io/blog/kubernetes-networking-demystified/可能需要注意的是,这可能会在一定程度上有所不同,具体取决于您使用的网络 CNI,尽管我看到的一切都与 Kubernetes 本身密切相关.

我还在努力消化这个博客的内容,我强烈建议直接参考那个博客,而不是依赖我的回答,这可能是对故事的拙劣复述。

这里是到达端口 443 的包的大致流程。

您将需要使用命令来查看表格。

iptables -t nat -vnL | less

这个输出看起来相当吓人。

下面切出很多其他链条,呼吁切入正题。在这个例子中:

  • 此集群使用 Calico/channel/Flannel 的 CNI 插件。
  • 监听端口为443
  • nginx-ingress-controller 的 pod 在 10.244.0.183 监听(以及其他)。

在那种情况下,数据包的流动方式如下:

  • 数据包进入 PREROUTING 链。
  • PREROUTING 链调用(除其他外)CNI-HOSTPORT-DNAT 链。
  • POSTROUTING链也调用同一条链。
  • CNI-HOSTPORT-DNAT 链依次调用多个 CNI-DN-xxxx 链。
  • CNI-DN-xxx 链执行 DNAT 并将目标地址更改为 10.244.0.183。
  • nginx-ingress-controller 中的容器侦听 10.244.0.183。

如果 pod 位于与到达的数据包不同的节点上,并且如果同一端口有多个 pods load-balanced,则会涉及一些额外的复杂性。负载平衡似乎是通过 iptables 统计模块随机选择一个或另一个 iptables 规则来处理的。

从服务到 pod 的内部流量遵循类似的流程,但不相同。

在这个例子中:

  • 服务在10.32.0.183,端口8001
  • pod 位于 10.244.6.112,端口 8001。
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
...
KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain KUBE-SERVICES (2 references)
...
/* Traffic from within the cluster to 10.32.0.183:8001 */
0 0 KUBE-SVC-ZHCKOT5PFJF4PASJ  tcp  --  *      *       0.0.0.0/0            10.32.0.183          tcp dpt:8001
...

/* Mark the package */
Chain KUBE-SVC-ZHCKOT5PFJF4PASJ (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 KUBE-MARK-MASQ  tcp  --  *      *      !10.244.0.0/16        10.32.0.183  tcp dpt:8081
    0     0 KUBE-SEP-RYU73S2VFHOHW4XO  all  --  *      *       0.0.0.0/0            0.0.0.0/0 

/* Perform DNAT, redirecting from 10.32.0.183 to 10.244.6.12 */
Chain KUBE-SEP-RYU73S2VFHOHW4XO (1 references)                                                                                                                                                                                                                                       0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.6.112         0.0.0.0/0
0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0 tcp to:10.244.6.112:8081

关于如何使节点可靠工作的问题的第二部分:

  • 禁用防火墙。
  • 改为使用 Kubernetes 网络策略(如果您使用的是 Calico,则使用 Calico 网络策略)。