Kubernetes - 如何使用 NodePort 服务从集群外部访问 nginx 负载平衡
Kubernetes - How to access nginx load balancing from outside the cluster using a NodePort service
我有一个带有主节点和另外两个节点的 Kubernetes 集群:
sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
kubernetes-master Ready master 4h v1.10.2
kubernetes-node1 Ready <none> 4h v1.10.2
kubernetes-node2 Ready <none> 34m v1.10.2
它们每个都 运行 在 VirtualBox Ubuntu VM 上,可从访客计算机访问:
kubernetes-master (192.168.56.3)
kubernetes-node1 (192.168.56.4)
kubernetes-node2 (192.168.56.6)
我部署了一个有两个副本的 nginx 服务器,每个 kubernetes-node-x 有一个 pod:
sudo kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-64ff85b579-5k5zh 1/1 Running 0 8s 192.168.129.71 kubernetes-node1
nginx-deployment-64ff85b579-b9zcz 1/1 Running 0 8s 192.168.22.66 kubernetes-node2
接下来,我将 nginx 部署的服务公开为 NodePort,以便从集群外部访问它:
sudo kubectl expose deployment/nginx-deployment --type=NodePort
sudo kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h
nginx-deployment NodePort 10.96.194.15 <none> 80:32446/TCP 2m
sudo kubectl describe service nginx-deployment
Name: nginx-deployment
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP: 10.96.194.15
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 32446/TCP
Endpoints: 192.168.129.72:80,192.168.22.67:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
我可以直接使用节点 IP 访问节点中的每个 pod
kubernetes-node1 http://192.168.56.4:32446/
kubernetes-node2 http://192.168.56.6:32446/
但是,我认为 K8s 提供了某种外部集群 ip,可以平衡外部对节点的请求。那个IP是什么??
But, I thought that K8s provided some kind of external cluster ip that balanced the requests to the nodes from the outside. What is that IP??
集群 IP 是集群内部的。不对外暴露,用于跨集群互通。
确实,您有 LoadBanacer 类型的服务可以执行您需要的技巧,只是它依赖于云提供商或 minikube/docker edge 才能正常工作。
I can access each pod in a node directly using their node IP
- 实际上,您不会以这种方式单独访问它们。 NodePort 做了一些不同的技巧,因为它本质上是在任何暴露的节点 IP 上对来自外部的请求进行负载平衡。简而言之,如果您使用暴露的 NodePort 访问任何节点的 IP,kube-proxy 将确保所需的服务获得它,然后服务通过活动 pods 进行循环,因此尽管您访问了特定的节点 IP,您不一定会在该特定节点上获得 pod 运行ning。您可以在此处找到更多详细信息:https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0,正如作者所说,技术上不是最准确的表示,但试图在逻辑层面上显示 NodePort 暴露所发生的事情:
作为旁注,为了在裸机上执行此操作并执行 ssl 等操作,您需要提供自己的入口。比如说,将一个 nginx 放在特定节点上,然后将所有你想要公开的适当服务(注意服务的 fqdn)作为上游引用,这些服务可以 运行 在多个节点上根据需要拥有尽可能多的 nginx - 你不需要自从 k8s 运行 开始演出以来,就不需要处理确切的细节了。这样你就有了一个已知 IP 地址的节点(入口 nginx),它正在处理传入流量并将其重定向到 k8s 内部的服务,这些服务可以 运行 跨任何节点。我不喜欢 ascii 艺术,但会尝试一下:
(outside) -> ingress (nginx) +--> my-service FQDN (running accross nodes):
[node-0] | [node-1]: my-service-pod-01 with nginx-01
| [node 2]: my-service-pod-02 with nginx-02
| ...
+--> my-second-service FQDN
| [node-1]: my-second-service-pod with apache?
...
在上面的草图中,您在 node-0(已知 IP)上有 nginx 入口,它接收外部流量,然后处理我的服务(运行在两个 pods 上的两个节点上)和我的-second-service(单 pod)作为上游。您只需要在服务上公开 FQDN 即可,无需担心特定节点的 IP 详细信息。您可以在文档中找到更多信息:https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/
同样比我的 ansi-art 更好的是这种表示来自与前一点相同的link,它说明了入口背后的想法:
已更新评论
Why isn't the service load balancing the used pods from the service?
- 发生这种情况的原因有多种。根据您的 Liveness 和 Readiness Probes 的配置方式,服务可能仍然不会将 pod 视为停止服务。由于 k8s 等分布式系统的这种异步特性,当 pods 被删除时,我们会遇到暂时的请求丢失,例如滚动更新等。其次,根据您的 kube-proxy 的配置方式,您可以通过一些选项来限制它。通过使用
--nodeport-addresses
的官方文档 (https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport),您可以更改节点代理行为。原来循环法是旧的 kube-proxy 行为,显然新的应该是随机的。最后,为了排除浏览器的连接和会话问题,您是否也从匿名会话中尝试过?您是否在本地缓存了 DNS?
Something else, I killed the pod from node1, and when calling to node1 it didn't use the pod from node 2.
- 这有点奇怪。可能与上面提到的探测器有关。根据官方文档,情况不应如此。我们让 NodePort 的行为与上面提到的官方文档一致:
and each Node will proxy that port (the same port number on every Node) into your Service
。但如果你是这种情况,那么可能是 LB 或 Ingress,甚至可能是具有外部地址的 ClusterIP(见下文)都可以为你解决问题。
if the service is internal (ClusterIP) ... does it load balance to any of the pods in the nodes
绝对是的。还有一件事,您可以使用此行为还可以在 'standard' 端口范围内公开 'load balanced' 行为,而不是来自 NodePort 的 30k+。这是我们用于入口控制器的服务清单的摘录。
apiVersion: v1
kind: Service
metadata:
namespace: ns-my-namespace
name: svc-nginx-ingress-example
labels:
name: nginx-ingress-example
role: frontend-example
application: nginx-example
spec:
selector:
name: nginx-ingress-example
role: frontend-example
application: nginx-example
ports:
- protocol: TCP
name: http-port
port: 80
targetPort: 80
- protocol: TCP
name: ssl-port
port: 443
targetPort: 443
externalIPs:
- 123.123.123.123
请注意,在上面的示例中,用 externalIPs
公开的虚构 123.123.123.123 表示我们的工作节点之一的 IP 地址。 Pods 运行ning in svc-nginx-ingress-example
服务根本不需要在这个节点上,但它们仍然可以将流量路由到它们(并且也在 pods 之间进行负载均衡) 当该 ip 在指定端口上被命中时。
我有一个带有主节点和另外两个节点的 Kubernetes 集群:
sudo kubectl get nodes
NAME STATUS ROLES AGE VERSION
kubernetes-master Ready master 4h v1.10.2
kubernetes-node1 Ready <none> 4h v1.10.2
kubernetes-node2 Ready <none> 34m v1.10.2
它们每个都 运行 在 VirtualBox Ubuntu VM 上,可从访客计算机访问:
kubernetes-master (192.168.56.3)
kubernetes-node1 (192.168.56.4)
kubernetes-node2 (192.168.56.6)
我部署了一个有两个副本的 nginx 服务器,每个 kubernetes-node-x 有一个 pod:
sudo kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-deployment-64ff85b579-5k5zh 1/1 Running 0 8s 192.168.129.71 kubernetes-node1
nginx-deployment-64ff85b579-b9zcz 1/1 Running 0 8s 192.168.22.66 kubernetes-node2
接下来,我将 nginx 部署的服务公开为 NodePort,以便从集群外部访问它:
sudo kubectl expose deployment/nginx-deployment --type=NodePort
sudo kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h
nginx-deployment NodePort 10.96.194.15 <none> 80:32446/TCP 2m
sudo kubectl describe service nginx-deployment
Name: nginx-deployment
Namespace: default
Labels: app=nginx
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP: 10.96.194.15
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 32446/TCP
Endpoints: 192.168.129.72:80,192.168.22.67:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
我可以直接使用节点 IP 访问节点中的每个 pod
kubernetes-node1 http://192.168.56.4:32446/
kubernetes-node2 http://192.168.56.6:32446/
但是,我认为 K8s 提供了某种外部集群 ip,可以平衡外部对节点的请求。那个IP是什么??
But, I thought that K8s provided some kind of external cluster ip that balanced the requests to the nodes from the outside. What is that IP??
集群 IP 是集群内部的。不对外暴露,用于跨集群互通。
确实,您有 LoadBanacer 类型的服务可以执行您需要的技巧,只是它依赖于云提供商或 minikube/docker edge 才能正常工作。
I can access each pod in a node directly using their node IP
- 实际上,您不会以这种方式单独访问它们。 NodePort 做了一些不同的技巧,因为它本质上是在任何暴露的节点 IP 上对来自外部的请求进行负载平衡。简而言之,如果您使用暴露的 NodePort 访问任何节点的 IP,kube-proxy 将确保所需的服务获得它,然后服务通过活动 pods 进行循环,因此尽管您访问了特定的节点 IP,您不一定会在该特定节点上获得 pod 运行ning。您可以在此处找到更多详细信息:https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0,正如作者所说,技术上不是最准确的表示,但试图在逻辑层面上显示 NodePort 暴露所发生的事情:
作为旁注,为了在裸机上执行此操作并执行 ssl 等操作,您需要提供自己的入口。比如说,将一个 nginx 放在特定节点上,然后将所有你想要公开的适当服务(注意服务的 fqdn)作为上游引用,这些服务可以 运行 在多个节点上根据需要拥有尽可能多的 nginx - 你不需要自从 k8s 运行 开始演出以来,就不需要处理确切的细节了。这样你就有了一个已知 IP 地址的节点(入口 nginx),它正在处理传入流量并将其重定向到 k8s 内部的服务,这些服务可以 运行 跨任何节点。我不喜欢 ascii 艺术,但会尝试一下:
(outside) -> ingress (nginx) +--> my-service FQDN (running accross nodes): [node-0] | [node-1]: my-service-pod-01 with nginx-01 | [node 2]: my-service-pod-02 with nginx-02 | ... +--> my-second-service FQDN | [node-1]: my-second-service-pod with apache? ...
在上面的草图中,您在 node-0(已知 IP)上有 nginx 入口,它接收外部流量,然后处理我的服务(运行在两个 pods 上的两个节点上)和我的-second-service(单 pod)作为上游。您只需要在服务上公开 FQDN 即可,无需担心特定节点的 IP 详细信息。您可以在文档中找到更多信息:https://kubernetes.io/docs/tutorials/kubernetes-basics/expose/expose-intro/
同样比我的 ansi-art 更好的是这种表示来自与前一点相同的link,它说明了入口背后的想法:
已更新评论
Why isn't the service load balancing the used pods from the service?
- 发生这种情况的原因有多种。根据您的 Liveness 和 Readiness Probes 的配置方式,服务可能仍然不会将 pod 视为停止服务。由于 k8s 等分布式系统的这种异步特性,当 pods 被删除时,我们会遇到暂时的请求丢失,例如滚动更新等。其次,根据您的 kube-proxy 的配置方式,您可以通过一些选项来限制它。通过使用
--nodeport-addresses
的官方文档 (https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport),您可以更改节点代理行为。原来循环法是旧的 kube-proxy 行为,显然新的应该是随机的。最后,为了排除浏览器的连接和会话问题,您是否也从匿名会话中尝试过?您是否在本地缓存了 DNS?
Something else, I killed the pod from node1, and when calling to node1 it didn't use the pod from node 2.
- 这有点奇怪。可能与上面提到的探测器有关。根据官方文档,情况不应如此。我们让 NodePort 的行为与上面提到的官方文档一致:
and each Node will proxy that port (the same port number on every Node) into your Service
。但如果你是这种情况,那么可能是 LB 或 Ingress,甚至可能是具有外部地址的 ClusterIP(见下文)都可以为你解决问题。
if the service is internal (ClusterIP) ... does it load balance to any of the pods in the nodes
绝对是的。还有一件事,您可以使用此行为还可以在 'standard' 端口范围内公开 'load balanced' 行为,而不是来自 NodePort 的 30k+。这是我们用于入口控制器的服务清单的摘录。
apiVersion: v1 kind: Service metadata: namespace: ns-my-namespace name: svc-nginx-ingress-example labels: name: nginx-ingress-example role: frontend-example application: nginx-example spec: selector: name: nginx-ingress-example role: frontend-example application: nginx-example ports: - protocol: TCP name: http-port port: 80 targetPort: 80 - protocol: TCP name: ssl-port port: 443 targetPort: 443 externalIPs: - 123.123.123.123
请注意,在上面的示例中,用
externalIPs
公开的虚构 123.123.123.123 表示我们的工作节点之一的 IP 地址。 Pods 运行ning insvc-nginx-ingress-example
服务根本不需要在这个节点上,但它们仍然可以将流量路由到它们(并且也在 pods 之间进行负载均衡) 当该 ip 在指定端口上被命中时。