kubernetes_13_普通Service和无头Service

Posted 毛奇志

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kubernetes_13_普通Service和无头Service相关的知识,希望对你有一定的参考价值。

系列文章目录

文章目录


前言

一、普通Service

2.1 有选择器的普通service

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80
        name: http-web-svc

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app.kubernetes.io/name: proxy
  ports:
  - name: name-of-service-port
    protocol: TCP
    port: 80
    targetPort: http-web-svc


2.2 无选择器的普通service

步骤1:部署pod

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app.kubernetes.io/name: proxy
spec:
  containers:
  - name: nginx
    image: nginx:stable
    ports:
      - containerPort: 80

步骤2:部署service

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

步骤3:部署endpoints

apiVersion: v1
kind: Endpoints
metadata:
  # 这里的 name 要与 Service 的名字相同
  name: nginx-service
subsets:
  - addresses:
      - ip: 192.168.159.44 # 需要绑定的pod的地址
    ports:
      - port: 80  # 需要绑定的pod的端口

三个文件 service - endpoint - pod
service 和 endpoint 通过在同一个命名空间里面,使用相同的 metadata.name 绑定
endpoint 和 pod 通过 pod 的虚拟ip和端口绑定

如果删除 endpoints.yaml

二、无头Service

在一个集群中有这个几个组件:pod-a,svc-b,pod-b1,pod-b2。当 pod-a 想访问 pod-b 中的应用程序时,先会把请求打到 svc-b,再由 svc-b 将请求随机转发到 pod-b1或 pod-b2。

如果有个需求:pod-a 需要同时连接到 pod-b1和 pod-b2 ,这时再采用 svc-b 转发显然已经不能满足需求了。那 pod-a 该如何获取到 pod-b1和 pod-b2 的 IP 地址呢?采用 handless service 就可以实现。

2.1 理论:无头Service

有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。

无头service相对于普通service的缺点:没有clusterIP,无法负载均衡到绑定的Pod
无头service相对于普通service的优点:
普通servcie,只能给service下面一个pod发消息
无头service,给service下面所有pod发消息

你可以使用一个无头 Service 与其他服务发现机制进行接口,而不必与 Kubernetes 的实现捆绑在一起。

对于无头 Services 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

带选择算符的服务:对定义了选择算符的无头服务,Endpoints 控制器在 API 中创建了 Endpoints 记录, 并且修改 DNS 配置返回 A 记录(IP 地址),通过这个地址直接到达 Service 的后端 Pod 上。

无选择算符的服务:对没有定义选择算符的无头服务,Endpoints 控制器不会创建 Endpoints 记录。 然而 DNS 系统会查找和配置,无论是:
(1) 对于 ExternalName 类型的服务,查找其 CNAME 记录
(2) 对所有其他类型的服务,查找与 Service 名称相同的任何 Endpoints 的记录

2.2 实践:无头Service

vi service.yaml 
# dns-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: default-subdomain
spec:
  selector:
    name: busybox
  clusterIP: None  # handless service
  ports:
    - name: foo 
      port: 1234
      targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox1
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: default-subdomain
  containers:
    - image: busybox:1.28
      command:
        - sleep
        - "3600"
      name: busybox
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox2
  labels:
    name: busybox
spec:
  hostname: busybox-2
  subdomain: default-subdomain
  containers:
    - image: busybox:1.28
      command:
        - sleep
        - "3600"
      name: busybox

kubectl get all -o wide
nslookup default-subdomain.default.svc.cluster.local 10.96.0.10

普通Service和无头Service使用nslookup的区别:
普通 service 域名获取到的是 service 自己的 IP 地址。
无头 service 域名获取到的是 service 绑定的所有的Pod IP 地址列表(因为无头Service自己没有IP地址)

注意:k8s中有三个和网络相关的系统Pod
proxy 负载均衡,service 绑定 deployment/statefulset/daemonset/job/cronjob
calico 节点之间网络通信
dns 域名解析,包括 ClusterFirst 和 Default

了解:不同的命名空间是有隔离性的。各种资源只能在相同命名空间下,通过标签互相构建连接。所以不同名命空间下可以存在相同名字的标签,互不影响。

小问题:nslookup:command not found

问题:CentOS7 上 nslookup:command not found

# 安装
yum -y install bind-utils
# 测试
nslookup baidu.com

对于nslookup baidu.com的输出结果

第一段内容为dns地址,包括端口号#DNSD端口号53。
第二段内容为解析结果。

2.3 小结:无头Service

2.3.1 ​常规的service服务和无头服务的区别

​常规的service服务和无头服务的区别
● service:一组Pod访问策略,提供cluster-IP群集之间通讯,还提供负载均衡和服务发现
● Headless service 无头服务,不需要cluster-IP,clusterIP为None的service,直接绑定具体的Pod的IP,无头服务经常用于statefulset的有状态部署。

注:service资源默认分配给cluster-IP是为了让客户端能访问。而service还提供了pod之间的相互发现,互相访问资源,他们不需要cluster-IP

2.3.2 k8s资源通过Service调用(外部调用和内部调用)

外部调用:通过deployment 资源,生成pod控制器,通过控制器生成一份或多份的pod。同命名空间下,创建service资源,service 资源的yaml 配置连接同命名空间下的那个标签lables的资源,通过此方式连接了刚刚创建的pod控制器资源,同时默认service 资源的yaml 配置生成一个集群IP+port,也就是反向代理后端刚刚连接上的deployment(pod控制器)资源,客户端访问集群IP+port,就会负载均衡的方式访问绑定的pod,通过kube-proxy组件进行资源的调度,负载。

内部调用:内部的资源,比如另一个pod控制器想访问deployment(pod控制器)的资源,由于deployment可能启动多份pod,而且pod的IP也会变化,所以k8s内部资源通过IP方式互相通信是不可能的。但是lables是不变,而serice操作了此过成,通过service资源绑定后,访问service资源的解析地址(nginx-ds.default.svc.cluster.local.)即可进行容器的服务互相发现。调用方式不是集群IP+port

小结:外部访问k8s集群是通过service暴露的 宿主机ip:宿主机port 来完成,k8s集群内部访问是通过 serviceName.namespace 来完成。

2.3.3 无头Service使用两个场景

无头服务使用两个场景:
1、无头服务用于服务发现机制的项目或者中间件,如kafka和zookeeper之间进行leader选举,采用的是实例之间的实例IP通讯。
2、既然不需要负载均衡,则就不需要Cluster IP,如果没有Cluster IP则kube-proxy 不会处理它们, 并且kubernetes平台也不会给他创建负载均衡。

场景1:有状态的中间件场景(使用无头Service识别未就绪的pod)

有状态的中间件场景(识别未就绪的pod)

无头服务有一个很重要的场景是发现所有的pod(包括未就绪的pod),只有准备就绪的pod能够作为服务的后端。但有时希望即使pod没有准备就绪,服务发现机制也能够发现所有匹配服务标签选择器的pod。

比如zk集群,zk节点pod之间必须互相识别之后进行选举,pod状态才会变为就绪,使用无头服务完美的解决这个问题。

场景2:当不需要负载均衡以及Service IP时可以使用无头Service

当不需要负载均衡以及Service IP时

还是以zk场景为例,zk节点之间通讯的端口是2888和3888,确实也不需要负载均衡以及Service IP。而提供给客户端的端口是2181,只有它需要,所以结合以上2个场景:

无头服务(用于zk pod之间彼此的通讯和选举的):

apiVersion: v1
kind: Service
metadata:
  name: zk-hs
  labels:
    app: zk
spec:
  # 这使得服务成为无头服务
  clusterIP: None
  ports:
  - port: 2888
    name: server
  - port: 3888
    name: leader-election
  selector:
    app: zk

正常的service给客户端的(需要负载均衡和cluster ip的):

apiVersion: v1
kind: Service
metadata:
  name: zk-cs
  labels:
    app: zk
spec:
  ports:
  - port: 2181
    name: client
  selector:

总结

本文重点是无头Service,这种用的比较少,毕竟默认的Service就是type为ClusterIP,是有头的。

第一,将普通Service和无头Service对比起来,更容易看懂无头Service

第二,从开发中的应用来将无头Service,更容易理解,普通Service是提供给外网访问,无头Service是为了发现所有 selector-label 的Pod.

完!

以上是关于kubernetes_13_普通Service和无头Service的主要内容,如果未能解决你的问题,请参考以下文章

KUBERNETES04_Service服务ClusterIPNodePort方式Ingress域名访问路径重写限流操作

KUBERNETES04_Service服务ClusterIPNodePort方式Ingress域名访问路径重写限流操作

Kubernetes_01_从云原生到kubernetes

Docker Kubernetes 服务发现原理详解

Python __repr__ 和无

kubernetes核心概念 Service