Kubernetes NodePort 并非在所有节点上都可用 - Oracle Cloud Infrastructure (OCI)
Kubernetes NodePort is not available on all nodes - Oracle Cloud Infrastructure (OCI)
我一直在努力克服这个问题,但我现在没有想法,因此我将问题发布在这里。
我正在试验 Oracle 云基础设施 (OCI),我想创建一个公开一些服务的 Kubernetes 集群。
目标是:
- 一个 运行 托管 Kubernetes 集群 (OKE)
- 至少 2 个节点
- 1 项可供外部各方访问的服务
基础结构如下所示:
- 一个 VCN 包罗万象
- 10.0.1.0/24 上的私有子网
- 10.0.0.0/24 上的一个 public 子网
- 私有子网的 NAT 网关
- public 子网的 Internet 网关
- 服务网关
- 两个子网的相应安全列表,除非有人要求,否则我现在不会分享它
- VCN 中的容器引擎 K8S (OKE) 集群启用了 public Kubernetes API
- K8S 集群的节点池现在有 2 个可用性域和 2 个实例。这些实例是具有 1 个 OCPU 和 6GB RAM 运行 Oracle-Linux-7.9-aarch64-2021.12.08-0 图像的 ARM 机器。
- K8S集群中的命名空间(暂且称之为staging)
- 一个部署,指的是在端口 3000 上服务流量的自定义 NextJS 应用程序
现在我想在端口 3000 上公开服务 运行。
我有两个明显的选择:
- 在 K8S 中创建一个 LoadBalancer 服务,它将在 OCI 中产生一个经典的负载均衡器,设置它的监听器并设置指向集群中 2 个节点的后端集,加上它调整子网安全列表以确保流量可以流动
- 在 OCI 中创建一个网络负载均衡器并在 K8S 上创建一个 NodePort 并手动将 NLB 配置为与经典负载均衡器相同的设置
第一个工作得很好,但我想以最低的成本使用这个集群,所以我决定尝试选项 2,即 NLB,因为它更便宜(零成本)。
长话短说,一切正常,我大部分时间都可以在 NLB 的 IP 上访问 NextJS 应用程序,但有时我不能。我决定查看发生了什么,结果发现我在集群中公开的 NodePort 并没有像我想象的那样工作。
NodePort 背后的服务只能在 运行 K8S 中的 pod 节点上访问。假设 NodeA 是 运行 服务,而 NodeB 就在那里。如果我尝试访问 NodeA 上的服务,一切都很好。但是当我尝试在 NodeB 上执行相同操作时,我根本没有收到任何响应。
这是我的问题,我无法弄清楚可能是什么问题。
目前我尝试过的:
- 从 ARM 机器切换到 AMD 机器 - 没有变化
- 在 public 子网中创建了一个堡垒主机来测试哪些节点正在响应请求。结果只有节点响应 运行 pod。
- 在 K8S 中创建了一个与 NodePort 具有相同配置的常规 LoadBalancer(在这种情况下 OCI 将创建一个经典的 Load Balancer),效果很好
- 尝试为 K8S 节点升级到 Oracle 8.4 映像,但没有修复
- 运行节点上的Node Doctor,一切正常
- 查看了kube-proxy、kube-flannel、core-dns的日志,没有报错
- 由于集群由2个节点组成,我试了一下,又加了一个节点,新节点上也无法访问服务
- 从头开始重新创建集群
编辑: 一些更新。我尝试使用 DaemonSet 而不是 Pod 的常规 Deployment,以确保作为一种临时解决方案,所有节点都是 运行 至少一个 Pod 实例和惊喜。以前没有响应该特定端口上的请求的节点,它仍然没有,即使它上面有一个 pod 运行。
Edit2: 最初我是 运行 集群的最新 K8S 版本 (v1.21.5) 我尝试降级到 v1.20.11 不幸的是问题是仍然存在。
Edit3: 检查节点端口是否在没有响应的节点上打开,至少 kube-proxy 正在监听它。
tcp 0 0 0.0.0.0:31600 0.0.0.0:* LISTEN 16671/kube-proxy
Edit4:: 尝试添加白名单 iptables 规则但没有改变任何东西。
[opc@oke-cdvpd5qrofa-nyx7mjtqw4a-svceq4qaiwq-0 ~]$ sudo iptables -P FORWARD ACCEPT
[opc@oke-cdvpd5qrofa-nyx7mjtqw4a-svceq4qaiwq-0 ~]$ sudo iptables -P INPUT ACCEPT
[opc@oke-cdvpd5qrofa-nyx7mjtqw4a-svceq4qaiwq-0 ~]$ sudo iptables -P OUTPUT ACCEPT
Edit5: 作为试验,我再次创建了一个 LoadBalancer 来验证我是否完全精神错乱,我只是在尝试或时没有注意到这个错误真的行。有趣的是,它通过经典负载均衡器的 IP 工作得很好。 但是 当我尝试直接在为负载均衡器打开的端口(目前为 30679)上向节点发送请求时。我仅从 运行 pod 的节点获得响应。另一方面,仍然没有通过负载平衡器,我得到 100% 的成功响应。
奖金,这是来自节点的 iptables,它没有响应请求,不太确定要查找什么:
[opc@oke-cn44eyuqdoq-n3ewna4fqra-sx5p5dalkuq-1 ~]$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
KUBE-NODEPORTS all -- anywhere anywhere /* kubernetes health check service ports */
KUBE-EXTERNAL-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes externally-visible service portals */
KUBE-FIREWALL all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
KUBE-FORWARD all -- anywhere anywhere /* kubernetes forwarding rules */
KUBE-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes service portals */
KUBE-EXTERNAL-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes externally-visible service portals */
ACCEPT all -- 10.244.0.0/16 anywhere
ACCEPT all -- anywhere 10.244.0.0/16
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
KUBE-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes service portals */
KUBE-FIREWALL all -- anywhere anywhere
Chain KUBE-EXTERNAL-SERVICES (2 references)
target prot opt source destination
Chain KUBE-FIREWALL (2 references)
target prot opt source destination
DROP all -- anywhere anywhere /* kubernetes firewall for dropping marked packets */ mark match 0x8000/0x8000
DROP all -- !loopback/8 loopback/8 /* block incoming localnet connections */ ! ctstate RELATED,ESTABLISHED,DNAT
Chain KUBE-FORWARD (1 references)
target prot opt source destination
DROP all -- anywhere anywhere ctstate INVALID
ACCEPT all -- anywhere anywhere /* kubernetes forwarding rules */ mark match 0x4000/0x4000
ACCEPT all -- anywhere anywhere /* kubernetes forwarding conntrack pod source rule */ ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere /* kubernetes forwarding conntrack pod destination rule */ ctstate RELATED,ESTABLISHED
Chain KUBE-KUBELET-CANARY (0 references)
target prot opt source destination
Chain KUBE-NODEPORTS (1 references)
target prot opt source destination
Chain KUBE-PROXY-CANARY (0 references)
target prot opt source destination
Chain KUBE-SERVICES (2 references)
target prot opt source destination
服务规范(运行 是使用 Terraform 生成的):
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"creationTimestamp": "2022-01-28T09:13:33Z",
"name": "web-staging-service",
"namespace": "web-staging",
"resourceVersion": "22542",
"uid": "c092f99b-7c72-4c32-bf27-ccfa1fe92a79"
},
"spec": {
"clusterIP": "10.96.99.112",
"clusterIPs": [
"10.96.99.112"
],
"externalTrafficPolicy": "Cluster",
"ipFamilies": [
"IPv4"
],
"ipFamilyPolicy": "SingleStack",
"ports": [
{
"nodePort": 31600,
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"app": "frontend"
},
"sessionAffinity": "None",
"type": "NodePort"
},
"status": {
"loadBalancer": {}
}
}
欢迎提出任何想法。
谢谢大家。
可能不是理想的解决方法,但您可以尝试将 externalTrafficPolicy 更改为 Local。这将防止对不 运行 应用程序失败的节点进行健康检查。这样流量只会转发到应用所在的节点。将 externalTrafficPolicy 设置为本地也是保留连接源 IP 的要求。另外,您能否共享您正在使用的 NLB 和 LB 的运行状况检查配置。当您更改 externalTrafficPolicy 时,请注意 LB 的运行状况检查会更改,并且需要将相同的内容应用于 NLB。
编辑:另请注意,您需要将安全列表/网络安全组添加到您的节点 subnet/nodepool,它允许来自工作节点子网的所有协议上的流量。
我一直在努力克服这个问题,但我现在没有想法,因此我将问题发布在这里。
我正在试验 Oracle 云基础设施 (OCI),我想创建一个公开一些服务的 Kubernetes 集群。
目标是:
- 一个 运行 托管 Kubernetes 集群 (OKE)
- 至少 2 个节点
- 1 项可供外部各方访问的服务
基础结构如下所示:
- 一个 VCN 包罗万象
- 10.0.1.0/24 上的私有子网
- 10.0.0.0/24 上的一个 public 子网
- 私有子网的 NAT 网关
- public 子网的 Internet 网关
- 服务网关
- 两个子网的相应安全列表,除非有人要求,否则我现在不会分享它
- VCN 中的容器引擎 K8S (OKE) 集群启用了 public Kubernetes API
- K8S 集群的节点池现在有 2 个可用性域和 2 个实例。这些实例是具有 1 个 OCPU 和 6GB RAM 运行 Oracle-Linux-7.9-aarch64-2021.12.08-0 图像的 ARM 机器。
- K8S集群中的命名空间(暂且称之为staging)
- 一个部署,指的是在端口 3000 上服务流量的自定义 NextJS 应用程序
现在我想在端口 3000 上公开服务 运行。
我有两个明显的选择:
- 在 K8S 中创建一个 LoadBalancer 服务,它将在 OCI 中产生一个经典的负载均衡器,设置它的监听器并设置指向集群中 2 个节点的后端集,加上它调整子网安全列表以确保流量可以流动
- 在 OCI 中创建一个网络负载均衡器并在 K8S 上创建一个 NodePort 并手动将 NLB 配置为与经典负载均衡器相同的设置
第一个工作得很好,但我想以最低的成本使用这个集群,所以我决定尝试选项 2,即 NLB,因为它更便宜(零成本)。
长话短说,一切正常,我大部分时间都可以在 NLB 的 IP 上访问 NextJS 应用程序,但有时我不能。我决定查看发生了什么,结果发现我在集群中公开的 NodePort 并没有像我想象的那样工作。
NodePort 背后的服务只能在 运行 K8S 中的 pod 节点上访问。假设 NodeA 是 运行 服务,而 NodeB 就在那里。如果我尝试访问 NodeA 上的服务,一切都很好。但是当我尝试在 NodeB 上执行相同操作时,我根本没有收到任何响应。
这是我的问题,我无法弄清楚可能是什么问题。
目前我尝试过的:
- 从 ARM 机器切换到 AMD 机器 - 没有变化
- 在 public 子网中创建了一个堡垒主机来测试哪些节点正在响应请求。结果只有节点响应 运行 pod。
- 在 K8S 中创建了一个与 NodePort 具有相同配置的常规 LoadBalancer(在这种情况下 OCI 将创建一个经典的 Load Balancer),效果很好
- 尝试为 K8S 节点升级到 Oracle 8.4 映像,但没有修复
- 运行节点上的Node Doctor,一切正常
- 查看了kube-proxy、kube-flannel、core-dns的日志,没有报错
- 由于集群由2个节点组成,我试了一下,又加了一个节点,新节点上也无法访问服务
- 从头开始重新创建集群
编辑: 一些更新。我尝试使用 DaemonSet 而不是 Pod 的常规 Deployment,以确保作为一种临时解决方案,所有节点都是 运行 至少一个 Pod 实例和惊喜。以前没有响应该特定端口上的请求的节点,它仍然没有,即使它上面有一个 pod 运行。
Edit2: 最初我是 运行 集群的最新 K8S 版本 (v1.21.5) 我尝试降级到 v1.20.11 不幸的是问题是仍然存在。
Edit3: 检查节点端口是否在没有响应的节点上打开,至少 kube-proxy 正在监听它。
tcp 0 0 0.0.0.0:31600 0.0.0.0:* LISTEN 16671/kube-proxy
Edit4:: 尝试添加白名单 iptables 规则但没有改变任何东西。
[opc@oke-cdvpd5qrofa-nyx7mjtqw4a-svceq4qaiwq-0 ~]$ sudo iptables -P FORWARD ACCEPT
[opc@oke-cdvpd5qrofa-nyx7mjtqw4a-svceq4qaiwq-0 ~]$ sudo iptables -P INPUT ACCEPT
[opc@oke-cdvpd5qrofa-nyx7mjtqw4a-svceq4qaiwq-0 ~]$ sudo iptables -P OUTPUT ACCEPT
Edit5: 作为试验,我再次创建了一个 LoadBalancer 来验证我是否完全精神错乱,我只是在尝试或时没有注意到这个错误真的行。有趣的是,它通过经典负载均衡器的 IP 工作得很好。 但是 当我尝试直接在为负载均衡器打开的端口(目前为 30679)上向节点发送请求时。我仅从 运行 pod 的节点获得响应。另一方面,仍然没有通过负载平衡器,我得到 100% 的成功响应。
奖金,这是来自节点的 iptables,它没有响应请求,不太确定要查找什么:
[opc@oke-cn44eyuqdoq-n3ewna4fqra-sx5p5dalkuq-1 ~]$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
KUBE-NODEPORTS all -- anywhere anywhere /* kubernetes health check service ports */
KUBE-EXTERNAL-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes externally-visible service portals */
KUBE-FIREWALL all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
KUBE-FORWARD all -- anywhere anywhere /* kubernetes forwarding rules */
KUBE-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes service portals */
KUBE-EXTERNAL-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes externally-visible service portals */
ACCEPT all -- 10.244.0.0/16 anywhere
ACCEPT all -- anywhere 10.244.0.0/16
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
KUBE-SERVICES all -- anywhere anywhere ctstate NEW /* kubernetes service portals */
KUBE-FIREWALL all -- anywhere anywhere
Chain KUBE-EXTERNAL-SERVICES (2 references)
target prot opt source destination
Chain KUBE-FIREWALL (2 references)
target prot opt source destination
DROP all -- anywhere anywhere /* kubernetes firewall for dropping marked packets */ mark match 0x8000/0x8000
DROP all -- !loopback/8 loopback/8 /* block incoming localnet connections */ ! ctstate RELATED,ESTABLISHED,DNAT
Chain KUBE-FORWARD (1 references)
target prot opt source destination
DROP all -- anywhere anywhere ctstate INVALID
ACCEPT all -- anywhere anywhere /* kubernetes forwarding rules */ mark match 0x4000/0x4000
ACCEPT all -- anywhere anywhere /* kubernetes forwarding conntrack pod source rule */ ctstate RELATED,ESTABLISHED
ACCEPT all -- anywhere anywhere /* kubernetes forwarding conntrack pod destination rule */ ctstate RELATED,ESTABLISHED
Chain KUBE-KUBELET-CANARY (0 references)
target prot opt source destination
Chain KUBE-NODEPORTS (1 references)
target prot opt source destination
Chain KUBE-PROXY-CANARY (0 references)
target prot opt source destination
Chain KUBE-SERVICES (2 references)
target prot opt source destination
服务规范(运行 是使用 Terraform 生成的):
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"creationTimestamp": "2022-01-28T09:13:33Z",
"name": "web-staging-service",
"namespace": "web-staging",
"resourceVersion": "22542",
"uid": "c092f99b-7c72-4c32-bf27-ccfa1fe92a79"
},
"spec": {
"clusterIP": "10.96.99.112",
"clusterIPs": [
"10.96.99.112"
],
"externalTrafficPolicy": "Cluster",
"ipFamilies": [
"IPv4"
],
"ipFamilyPolicy": "SingleStack",
"ports": [
{
"nodePort": 31600,
"port": 3000,
"protocol": "TCP",
"targetPort": 3000
}
],
"selector": {
"app": "frontend"
},
"sessionAffinity": "None",
"type": "NodePort"
},
"status": {
"loadBalancer": {}
}
}
欢迎提出任何想法。 谢谢大家。
可能不是理想的解决方法,但您可以尝试将 externalTrafficPolicy 更改为 Local。这将防止对不 运行 应用程序失败的节点进行健康检查。这样流量只会转发到应用所在的节点。将 externalTrafficPolicy 设置为本地也是保留连接源 IP 的要求。另外,您能否共享您正在使用的 NLB 和 LB 的运行状况检查配置。当您更改 externalTrafficPolicy 时,请注意 LB 的运行状况检查会更改,并且需要将相同的内容应用于 NLB。
编辑:另请注意,您需要将安全列表/网络安全组添加到您的节点 subnet/nodepool,它允许来自工作节点子网的所有协议上的流量。