Kubernetes之无头服务(headless)
己经看到如何使用服务来提供稳定的ip地址,从而允许客户端连接到支持服务的每个pod (或其他端点)。到服务的每个连接都被转发到一个随机选择的pod上。但是如果客户端需要链接到所有的pod呢?如果后端的pod都需要连接到所有其他 pod呢?通过服务连接显然不是这样的,那是怎样的呢?
要让客户端连接到所有pod,需要找出每个pod的IP。一种选择是让客户端调用Kubernetes API服务器并通过API调用获取pod及其IP地址列表,但由于应始终努力保持应用程序与Kubernetes无关,因此使用API服务器并不理想。
幸运的是,Kubernetes允许客户通过DNS查找发现pod IP。通常,当执行服务的DNS查找时,DNS服务器会返回单个IP——服务的集群IP。但是,如果告诉 Kubernetes,不需要为服务提供集群IP (通过在服务spec中将clusterIP字段设置为None来完成此操作),则DNS服务器将返回podIP而不是单个服务IP。
DNS服务器不会返回单个DNS A记录,而是会为该服务返回多个A记录,每个记录指向当时支持该服务的单个pod的IP。客户端因此可以做一个简单的DNS A 记录查找并获取属于该服务一部分的所有pod的IP。客户端可以使用该信息连接到其中的一个、多个或全部。
1.创建headless服务
将服务spec中的clusterIP字段设置为None会使服务成为headless服务,因为Kubernetes不会为其分配集群IP,客户端可通过该IP将其连接到支持它的pod。
现在将创建一个名为kubia-headless的headless服务。以下代码清单显示了它的定义。
apiVersion: v1 kind: Service metadata: name: kubia-headless spec: clusterIP: None #这使得服务成为headless ports: - port: 80 targetPort: 8080 selector: app: kubia
在使用kubectl create创建服务之后,可以通过kubectl get和kubectl describe来查看服务,你会发现它没有集群IP,并且它的后端包含与pod选择器匹配的(部分)pod。“部分”是因为pod包含就绪探针,所以只有准备就绪的pod会被列出作为服务的后端文件来确保至少有两个pod报告己准备就绪。
2.通过DNS发现pod
准备好pod后,现在可以尝试执行DNS查找以查看是否获得了实际的pod IP。需要从其中一个pod中执行查找。不幸的是,kubia容器镜像不包含nslookup(或dig)二进制文件,因此无法使它执行DNS查找。
所要做的就是在集群中运行的一个pod中执行DNS查询。为什么不寻找一个包含所需二进制文件的镜像来运行新的容器?要执行与DNS相关的操作,可以使用Docker Hub上提供的tutum/dnsutils容器镜像,它包含nslookup和dig二进制文件。要运行pod,可以完成创建YAML清单并将其传给kubectl create的整个过程。但是太烦琐了,对吗?幸运的是,有一个更快的方法。
不通过YAML文件运行pod
使用kubectl run是这次只想创建一个pod,不需要创建一个ReplicationController来管理pod。可以这样做:
$ kubectl run dnsutils --image=tutum/dnsutils --generator=run-pod/v1 --command -- sleep infinity pod "dnsutils" created
诀窍在--generator=run-pod/vl选项中,该选项让kubectl直接创建 pod,而不需要通过ReplicationController之类的资源来创建。
理解headless服务的DNSA记录解析
使用新创建的pod执行DNS查找:
$ kubectl exec dnsutils nslookup kubia-headless Name: kubia-headless.default.svc.cluster.local Address: 10.108.1.4 Name: kubia-headless.default.svc.cluster.local Address: 10.108.2.5
DNS服务器为kubia-headless.default.svc.cluster.local FQDN返回两个不同的IP。这些是报告准备就绪的两个pod的IP。可以通过使用kubectl get pods -o wide列出pod来确认此问题,该清单显示了pod的IP。
这与常规(非headless服务)服务返回的DNS不同,比如kubia服务,返回的IP是服务的集群IP。(这里就不做代码演示了)
尽管headless服务看起来可能与常规服务不同,但在客户的视角上它们并无不同。即使使用headless服务,客户也可以通过连接到服务的DNS名称来连接到pod上,就像使用常规服务一样。但是对于headless服务,由于DNS返回了pod的IP, 客户端直接连接到该pod,而不是通过服务代理。
注意:headless服务仍然提供跨pod的负载平衡,但是通过DNS轮询机制不是
3.发现所有的pod--包括未就绪的pod
只有准备就绪的pod能够作为服务的后端。但有时希望即使pod没有准备就绪,服务发现机制也能够发现所有匹配服务标签选择器的pod。
幸运的是,不必通过查询KubernetesAPI服务器,可以使用DNS查找机制来查找那些未准备好的pod。要告诉Kubernetes无论pod的准备状态如何,希望将所有pod添加到服务中。必须将以下注解添加到服务中:
kind: Service metadata: annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
警告: 就像说的那样,注解名称表明了这是一个alpha功能。KubernetesService API己经支持一个名为publishNotReadyAddresses的新服务规范字段,它将替换tolerate-unready-endpoints注解。在Kubernetes1.9.0版本中,这个字段还没有实现(这个注解决定了未准备好的endpoints是否在DNS的记录中)。检查文档以查看是否己更改。