一、Headless Service

有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。无头 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。

DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。
(1)带选择算符的服务
对定义了选择算符的无头服务,Endpoint 控制器在 API 中创建了 Endpoints 记录, 并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达 Service 的后端 Pod 上。
(2)无选择算符的服务
1)对没有定义选择算符的无头服务,Endpoint 控制器不会创建 Endpoints 记录。 然而 DNS 系统会查找和配置,无论是:对于 ExternalName 类型的服务,查找其 CNAME 记录。

2)对所有其他类型的服务,查找与 Service 名称相同的任何 Endpoints 的记录。

无头(Headless)服务(没有集群 IP)也会以 my-svc.my-namespace.svc.cluster-domain.example 这种名字的形式被指派一个 DNS A 或 AAAA 记录。 与普通服务不同,这一记录会被解析成对应服务所选择的 Pod 集合的 IP。 客户端要能够使用这组 IP,或者使用标准的轮转策略从这组 IP 中进行选择。

接下来通过两个无头(Headless)服务来带领读者理解其特点。

(1)例子1,我们将实现一个带有选择运算符的无头(Headless)服务,验证其特性。

(2)例子2,我们将实现一个无选择运算符的无头(Headless)服务,验证其特性。

例子1,我们创建一个带有标签选择器的服务nginx-service-headless。

第一步,编辑一个无头服务的yaml文件,其Service的定义与之前的定义的唯一区别是添加了一个属性clusterIP: None,Deployment的定义与之前的定义相同。

apiVersion: v1
kind: Service
metadata:
  name: nginx-service-headless
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  clusterIP: None # 无头服务
  selector:
    app: nginx # 定义此Service关联的Pod对应的标签
  type: ClusterIP # 此Service类型为ClusterIP

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels: # 定义Deployment关联的Pod的标签
      app: nginx
  replicas: 3 # 告诉Deployment运行的Pod实例数目
  template: # Pod的模板
    metadata:
      labels:
        app: nginx # Pod的标签
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

第二步,应用这个yaml文件,创建对应的Service与Pod等资源。

kubectl apply -f 2-service-headless.yaml

第三步,查看创建资源的概况,如图所示,Service nginx-service-headless 的CLUSTER-IP为None。

[root@kubernetes-master01 service]# kubectl get all
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-6b474476c4-27gqr   1/1     Running   0          4m29s
pod/nginx-deployment-6b474476c4-6w5zl   1/1     Running   0          4m29s
pod/nginx-deployment-6b474476c4-ww74l   1/1     Running   0          4m29s

NAME                             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/nginx-service-headless   ClusterIP   None         <none>        80/TCP    4m29s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   3/3     3            3           4m29s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-6b474476c4   3         3         3       4m29s

第四步,查看Service nginx-service-headless 后面关联的Pod,如图所示,关联的Pod都是正常的,是我们定义的相同标签的三个Pod。

[root@kubernetes-master01 service]# kubectl describe service nginx-service-headless
Name:              nginx-service-headless
Namespace:         default
Labels:            <none>
Annotations:       Selector:  app=nginx
Type:              ClusterIP
IP:                None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.51:80,10.244.1.52:80,10.244.2.20:80
Session Affinity:  None
Events:            <none>

[root@kubernetes-master01 service]# kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE     IP            NODE               
nginx-deployment-6b474476c4-27gqr   1/1     Running   0          7m47s   10.244.2.20   
nginx-deployment-6b474476c4-6w5zl   1/1     Running   0          7m47s   10.244.1.52   
nginx-deployment-6b474476c4-ww74l   1/1     Running   0          7m47s   10.244.1.51   

第五步,随机登录到一个Pod中,查看的DNS记录情况,结果如图所示,会显示后面的所有的关联的Pod的IP,需要用户根据情况,从中选择要访问的具体Pod。

sh-4.4# nslookup nginx-service-headless
Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	nginx-service-headless.default.svc.cluster.local
Address: 10.244.1.51
Name:	nginx-service-headless.default.svc.cluster.local
Address: 10.244.2.20
Name:	nginx-service-headless.default.svc.cluster.local
Address: 10.244.1.52

除了带有标签选择符的无头(Headless)服务,来进行第二个例子,创建一个不带有标签选择符的无头(Headless)服务。

服务最常见的是抽象化对 Kubernetes Pod 的访问,但是它们也可以抽象化其他种类的后端。 实例:
(1)希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
(2)希望服务指向另一个 名字空间(Namespace) 中或其它集群中的服务。
(3)你正在将工作负载迁移到 Kubernetes。 在评估该方法时,你仅在 Kubernetes 中运行一部分后端。
在任何这些场景中,都能够定义没有选择算符的 Service。 实例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  clusterIP: None # 无头服务
  type: ClusterIP # 此Service类型为ClusterIP

由于此服务没有选择算符,因此不会自动创建相应的 Endpoint 对象。 我们可以通过手动添加 Endpoint 对象,将服务手动映射到运行该服务的网络地址和端口,其中关联的为资源对象Endpoints中的metadata.name字段,需要是我们定义的服务的名字。

apiVersion: v1
kind: Endpoints
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 10.20.40.150
    ports:
      - port: 80

说明:
(1)端点 IPs 必须不可以 是:本地回路(IPv4 的 127.0.0.0/8, IPv6 的 ::1/128)或 本地链接(IPv4 的 169.254.0.0/16 和 224.0.0.0/24,IPv6 的 fe80::/64)。
(2)端点 IP 地址不能是其他 Kubernetes 服务的集群 IP,因为 kube-proxy 不支持将虚拟 IP 作为目标。
(3)访问没有选择算符的 Service,与有选择算符的 Service 的原理相同。 请求将被路由到用户定义的 Endpoint,YAML 中为:10.20.40.150:80(TCP)。

将上面的yaml文件,在Kubernetes集群中应用,查看效果,如图所示,这个无头Service的Endpoints已经挂载上了我们定义的10.20.40.150:80的服务上面。

[root@kubernetes-master01 service]# kubectl describe service my-service
Name:              my-service
Namespace:         default
Labels:            <none>
Annotations:       Selector:  <none>
Type:              ClusterIP
IP:                None
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         10.20.40.150:80
Session Affinity:  None
Events:            <none>

二、猜你喜欢

如果你对容器化技术的相关知识感兴趣,可以阅读:秀丽的容器化技术Kubernetes专栏https://blog.csdn.net/jiangxiulilinux/category_10955709.html

本专栏特点:

  • 理论结合实战
  • 讲解深入浅出
Logo

开源、云原生的融合云平台

更多推荐