Kubernetes 有四种 service 类型,而 ClusterIP 是最基础的:
如上图所示,你可以想象一下,如果你要创建一个 NodePort 类型的 service,Kubernetes 也会创建一个 ClusterIP。如果你要创建一个 LoadBalancer 类型的 service,Kubernetes 会创建一个 NodePort 以及 ClusterIP。如果你以这样的方式思考,对 Kubernetes service 的理解将变得容易。
接下来我们将会对此进行一一解释。
Services 和 Pods
Services 通过使用 labels 直接指向 pods,而不是指向 deployments 或者 replicasets。这种设计的灵活性极高,因为创建 pods 的方式有很多,而 Service 不需要关心 pods 通过哪种方式创建。
我们先阐述一个简单的示例,然后逐步介绍不同的 service 类型,来了解它们是如何在彼此之上构建的。
不使用 Services
首先,让我们看下不使用 services 的情况。
如上图,我们有2个 node 和 1 个 pod。两个 node 分别使用外部 IP 地址(4.4.4.1和4.4.4.2)以及内部 IP 地址(1.1.1.1和1.1.1.2),而名为 pod-python 的 pod 只有一个内部 IP 地址。
如上图,现在我们添加第二个名为 pod-nginx 的 pod,它被调度到了 node-1 上。虽然两个 pod 在不同的 node 上,但这不影响它们互相访问。在 Kubernetes 集群中,所有的 pod 都可以通过内部 IP 地址访问其他的 pod,不管它们运行在哪个 node 上。
这就意味着 pod-nginx 能通过内部 IP 地址 1.1.1.3 ping通或者连接 pod-python。
如上图,现在我们考虑将 pod-python 杀死并重建一个新 pod。(本文不负责介绍如何管理和控制 pod。)操作完成之后,pod-nginx 就无法继续访问 IP 地址 1.1.1.3,这样系统就中断崩溃了。为了避免这种问题,我们来创建第一类 service!
ClusterIP 类型
与上述场景一样,但这次我们配置了一个 ClusterIP 类型的 service。service 不像 pod 会调度到特定的 node 上,在本文中你可以假定service 仅在整个集群的内存中生效。
现在,pod-nginx 总是能够安全地连接 IP 地址 1.1.10.1 或者域名地址 service-python,然后重定向到一个活跃的 python pod 上。没有灾难,一切美好。
我们来延申下这个示例,将 python 服务扩展到 3 个实例,并且现在我们把 service 和所有 pod 实例的内部 IP 地址以及端口都标注在图中。
集群中的所有 pod 都能通过 http://1.1.10.1:3000 或者 http://service-python:3000 访问到 python pod 的 443 端口。service-python 这个 ClusterIP 类型的 service 将基于随机或者轮询方式分发请求。这就是 ClusterIP 类型的 service 要做的事情,它能够让集群中的 pod 通过一个名字或者 IP 达到可用性。
-
apiVersion: v1
kind: Service
metadata:
name: service-python
spec:
ports:
protocol: TCP
targetPort: 443
selector:
run: pod-python
type: ClusterIP
运行命令 kubectl get svc,结果如下:
NodePort 类型
现在我们想让 ClusterIP 类型的 service 在集群外部也能够使用,所以将其转换成 NodePort 类型的 service。基于我们的示例,只需将 service-python 的 yaml 文件做两处简单的修改,如下所示:
-
apiVersion: v1
kind: Service
metadata:
name: service-python
spec:
ports:
protocol: TCP
targetPort: 443
nodePort: 30080
selector:
run: pod-python
type: NodePort
通过 node-2 的外部请求
如上图所示,现在我们集群内部的 service-python 也能通过所有 node 的内部以及外部 IP 地址和端口 30080 访问。
运行命令 kubectl get svc,结果展示了相同的 cluster ip,但类型显示不一样了,而且多了个额外的 NodePort 端口。
在集群内部,NodePort 类型的 service 同样扮演着之前 ClusterIP 类型 service 的角色。这帮助了我们去想象一个 NodePort 类型的 service 创建了一个 ClusterIP 类型的 service,尽管事实上并没有额外增加一个 ClusterIP 类型的 service。
LoadBalancer 类型
当我们想通过一个 IP 地址将请求分发到所有 node 节点的外部 IP 地址时,可以使用 LoadBalancer 类型的 service。因此,它是构建于 NodePort 类型的 service 之上,如下图所示:
我们可以想象成一个 LoadBalancer 类型的 service 创建了一个 NodePort 类型的 service,接着创建了一个 ClusterIP 类型的 service。只需简单修改下 NodePort 类型的 yaml 文件即可变更为 LoadBalancer 类型,如下所示:
apiVersion: v1
kind: Service
metadata:
name: service-python
spec:
ports:
protocol: TCP
targetPort: 443
nodePort: 30080
selector:
run: pod-python
LoadBalancer类型的 service 所要做的就是创建一个 NodePort 类型的 service,然后发消息给部署 Kubernetes 集群的云服务提供商,请求其为所有 node 节点的外部 IP 地址以及设定的 NodePort 端口配置负载均衡。如果云服务提供商不支持这类请求消息的处理,任何事情都不会发生,LoadBalancer 类型的 service 就会和 NodePort 类型一样了。
运行命令 kubectl get svc,结果仅多展示了一个 EXTERNAL-IP 字段以及不同的类型。
LoadBalancer 类型的 service 同样会在所有 node 节点内外 IP 地址上开放 30080 端口。在集群内部,它和 ClusterIP 类型的 service 作用一样。
ExternalName 类型
最后介绍下 ExternalName 类型的 service,它可以被认为是有点分开的,和之前介绍的 3 种不在一个技术栈。简而言之,它创建了一个内部服务,端点指向了一个 DNS 域名。
基于我们之前的示例,现在假设 pod-nginx 已经迁移到了我们新的 Kubernetes 集群,但 Python 服务还在外部(原来的地方):
如上图所示,pod-nginx 可以直接连接 http://remote.server.url.com,这样是没有问题的。但不久之后,我们想将 python 服务也迁移到新的集群中,到那时就会出问题了,因此我们可以创建一个 ExternalName 类型的 service。
使用的 yaml 文件内容如下:
-
kind: Service
apiVersion: v1
metadata:
name: service-python
spec:
ports:
protocol: TCP
targetPort: 443
type: ExternalName
externalName: remote.server.url.com
现在,pod-nginx 可以简单地与 http://service-python:3000 建立连接,就像使用 ClusterIP 类型的 service 一样。当最终我们决定将Python 服务迁移到新的 Kubernetes 集群中时,我们只需要将 service 的类型改成 ClusterIP 并使用对应的 labels 配置即可。
使用 ExternalName 类型 service 的最大好处在于,你可以先建设好 Kubernetes 集群基础设施,并且基于 services 和 IP 地址设定好规则与限制,尽管有些服务依然存在于集群外部。
原文链接:
https://medium.com/swlh/kubernetes-services-simply-visually-explained-2d84e58d70e5
本文转载自分布式实验室
Kubernetes Service 转载 https://mp.weixin.qq.com/s/dAujOyQLJOuzSu-tamH7zA