翻译:狄卫华
原文:Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?
最近有人向我了解 NodePorts ,LoadBalancers 和 Ingress 之间的区别是怎么样的。 它们都是将外部流量引入群集的方式,适用的场景却各不相同。 本文接下来我们将介绍它们的工作原理以及适用的相关场景。
注意:文中所述内容适用于 GKE [Google Kubernetes Engine]。 如果你在其他云平台上运行使用步骤略有不同,比如 minikube 或其他相关软件。 我本人也不打算过多深入技术细节, 如果您有兴趣了解更多,Kubernetes 官方文档 会提供更多的有用资源!
ClusterIP
ClusterIP 服务是 Kubernetes 默认的服务类型。 如果你在集群内部创建一个服务,则在集群内部的其他应用程序可以进行访问,但是不具备集群外部访问的能力。
ClusterIP 服务的 YAML 文件看起来像这样:
apiVersion: v1 kind: Service metadata: name: my-internal-service selector: app: my-app spec: type: ClusterIP ports: - name: http port: 80 targetPort: 80 protocol: TCP
如果不能从互联网访问 ClusterIP 服务,我为什么要谈论它呢?事实上,你可以通过 Kubernetes 代理进行访问。
感谢 Ahmet Alp Balkan 提供的图表
启动 Kubernetes 代理:
$ kubectl proxy --port=8080
现在,可以通过 Kubernetes API 通过以下的模式来访问这个服务:
http://localhost:8080/api/v1/proxy/namespaces//services/:/,
通过这种方式可以使用以下的地址来访问我们上述定义的服务:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
何时使用这种访问方式?
有以下几种场景,你可以使用 Kubernetes 代理的方式来访问服务:
- 调试服务或者某些情况下通过笔记本电脑直接连接服务
- 允许内部的通信,显示内部的仪表盘(dashboards)等
因为此种方式需要作为一个授权用户运行 kubectl,因此不应该用来暴露服务至互联网访问或者用于生产环境。
NodePort
NodePort 服务通过外部访问服务的最基本的方式。顾名思义,NodePort 就是在所有的节点或者虚拟机上开放特定的端口,该端口的流量将被转发到对应的服务。
从技术上层面,这不能算是最准确的图表,但我认为它能够直观展示了 NodePort 的工作方式。
NodePort 服务的 YAML 文件看起来像这样:
apiVersion: v1 kind: Service metadata: name: my-nodeport-service selector: app: my-app spec: type: NodePort ports: - name: http port: 80 targetPort: 80 nodePort: 30036 protocol: TCP
从根本上讲,NodePort 方式的服务与 ClusterIP 方式的服务有两个区别。第一,类型是 NodePort,这需要指定一个称作 nodePort 的附加端口,并在所有节点上打开对应的端口。如果我们不具体指定端口,集群会选择一个随机的端口。大多数的情况下,我们都可以让 Kubernetes 帮我们选择合适的端口。正如 thockin 所描述的那样,有许多相关的注意事项(caveats)关于那些端口可供我们使用。
何时使用这种访问方式?
NodePort 方式有许多缺点:
- 每个服务占用一个端口
- 可以使用的 30000-32767 范围端口 (译者注:可以通过api-server启动参数service-node-port-range
指定限制范围,默认为30000-32767) - 如果节点/虚拟机IP地址发生更改,需要进行相关处理
由于上述原因,我不建议在生产环境中使用直接暴露服务。 如果运行的服务不要求高可用或者非常关注成本,这种方法则比较适合。 很好的例子就是用于演示或临时使用的程序。
LoadBalancer
LoadBalancer 服务是暴露服务至互联网最标准的方式。在 GKE 上,这将启动一个网络负载均衡器(Network Load Balancer),它会提供一个 IP 地址,以将所有流量转发到服务。
感谢 Ahmet Alp Balkan 提供图表
何时使用这种访问方式?
这是公开服务的默认的方法。指定的端口上流量都将被转发到对应的服务,不经过过滤和其他路由等操作。这种方式意味着转发几乎任何类型的流量,如HTTP,TCP,UDP,Websockets,gRPC或其他。
这种方式最大的缺点是,负载均衡器公开的每个服务都将获取独立 IP 地址,而我们则必须为每个暴露的服务对应的负载均衡器支付相关费用,这可能会变得非常昂贵!
Ingress
和上述讨论的服务方式不同,Ingress 实际上并不是服务类型中的一种。相反,它位于多个服务的前端充当一个智能路由或者集群的入口点。
你可以使用 Ingress 做很多不同的事情,并且不同类型的 Ingress 控制也具备不同的能力。
GKE 默认的 Ingress 控制器将启动一个 HTTP(S) 的负载均衡器。则将使我们可以基于访问路径和子域名将流量路由到后端服务。例如,你可以将 foo.yourdomain.com
下的流量转发到 foo 服务,将 yourdomain.com/bar/
路径下的流量转发到 bar 服务。
感谢 Ahmet Alp Balkan 提供图表
在 GKE 上定义 L7层 HTTP 负载均衡器的 Ingress 对象定义的 YAML 看起来像这样:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: my-ingress spec: backend: serviceName: other servicePort: 8080 rules: - host: foo.mydomain.com http: paths: - backend: serviceName: foo servicePort: 8080 - host: mydomain.com http: paths: - path: /bar/* backend: serviceName: bar servicePort: 8080
何时使用这种方式?
Ingress 方式可能是暴露服务的最强大的方式,但也最复杂。现在有不同类型的 Ingress 控制器,包括 Google 云 负载均衡器, Nginx, Contour, Istio 等。此外,还有 Ingress 控制器的许多插件,比如 cert-manager 可以用来自动为服务提供 SSL 证书。
如果希望在同一个IP地址下暴露多个服务,并且它们都使用相同的 L7 协议(通常是HTTP),则 Ingress 方式最有用。 如果使用本地 GCP 集成,则只需支付一台负载平衡器费用,并且是“智能”性 Ingress ,可以获得许多开箱即用的功能(如SSL,Auth,路由等)。