Kubernetes服务发现Service(一)

网友投稿 686 2022-10-12

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

Kubernetes服务发现Service(一)

1. Service 为何存在

Kubernetes集群就为我们提供了这样的一个对象 - Service,Service是一种抽象的对象,它定义了一组Pod的逻辑集合和一个用于访问它们的策略,其实这个概念和微服务非常类似。一个Serivce下面包含的Pod集合一般是由Label Selector来决定的。

我们这样就可以不用去管后端的Pod如何变化,只需要指定Service的地址就可以了,因为我们在中间添加了一层服务发现的中间件,Pod销毁或者重启后,把这个Pod的地址注册到这个服务发现中心去。Service的这种抽象就可以帮我们达到这种解耦的目的。

2. Kubernetes的三种IP

Node IP: Node节点的IP地址Cluster IP: Service的IP地址Pod IP: Pod的IP地址

Node IP是Kubernetes集群中节点的物理网卡IP地址(一般为内网),属于这个网络的服务器之间都可以直接通信,所以Kubernetes集群外要想访问Kubernetes集群内部的某个节点或者服务,肯定得通过Node IP进行通信(这个时候一般是通过外网IP了)Pod IP是每个Pod的IP地址,它是Docker Engine根据docker0网桥的IP地址段进行分配的(我们这里使用的是flannel这种网络插件保证所有节点的Pod IP不会冲突)Cluster IP是一个虚拟的IP,仅仅作用于Kubernetes Service这个对象,由Kubernetes自己来进行管理和分配地址,当然我们也无法ping这个地址,他没有一个真正的实体对象来响应,他只能结合Service Port来组成一个可以通信的服务,相当于VIP地址,来代理后端服务。

3. 创建Service

现在我们先创建一组Pod

---apiVersion: apps/v1beta1kind: Deploymentmetadata:  name: httpd  labels:    app: httpd-demospec:  replicas: 3  template:    metadata:      labels:        app: httpd    spec:      containers:      - name: httpd        image: httpd        ports:        - containerPort: 80

上面这个Pod 我们定义了三个副本,标签为 app=httpd,下面我们来创建这个Pod的Service,通过spec.selector来指定标签为httpd的Pod。

其中被selector 选中的 Pod,就称为 Service 的Endpoints,可以使用 kubectlgetep 命令查看。

[root@master testyml]# kubectl  get epNAME               ENDPOINTS                                      AGEfuseim.pri-ifs                                             21dhttpd-svc          10.244.0.24:80,10.244.1.112:80,10.244.2.2:80   19h

我们可以看到 httpd-svc的后端端点IP 10.244.0.24:80,10.244.1.112:80,10.244.2.2:80,也就是httpd应用Pod的IP地址。需要注意的是,只有处于Running状态且readlinessProbe检查通过的Pod,才会出现在Service的Endpoints列表里,同样当某个Pod出现问题时,Service也会把这个Pod从Endpoints中摘掉。

现在我们创建上面Pod集合所对应的Service

apiVersion: v1kind: Servicemetadata:  name: httpd-svcspec:   selector:     app: httpd   ports:   - protocol: TCP     port: 8080     targetPort: 80

[root@master testyml]# kubectl   create -f svc.yml service "httpd-svc" created[root@master testyml]# kubectl  get svc --all-namespacesNAMESPACE     NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                          AGEblog          mysql                  ClusterIP   10.101.134.172          3306/TCP                         30dblog          wordpress              NodePort    10.107.173.113          80:32255/TCP                     30ddefault       httpd-svc              ClusterIP   10.108.195.47            8080/TCP                         3mdefault       kubernetes             ClusterIP   10.96.0.1                443/TCP                          114ddefault       mysql-production       ClusterIP   10.102.208.69            3306/TCP                         13ddefault       order                  NodePort    10.99.99.88              8080:30080/TCP                   16dkube-ops      jenkins2               NodePort    10.111.112.3            8080:30005/TCP,50000:30340/TCP   17dkube-system   kube-dns               ClusterIP   10.96.0.10              53/UDP,53/TCP                    114dkube-system   kubernetes-dashboard   NodePort    10.108.149.176          443:30002/TCP                    111d[root@master testyml]#

现在我们看到已经创建了名为 httpd-svc的Service,分配的Cluster IP 为 10.108.195.47,该Service还会持续的监听selector下面的Pod,会把这些Pod信息更新到一个名为httpd-svc的Endpoints对象上去,这个对象就类似于我们上面说的Pod集合了。

需要注意的是,Service能够将一个接收端口映射到任意的targetPort。 默认情况下,targetPort将被设置为与port字段相同的值。 可能更有趣的是,targetPort 可以是一个字符串,引用了 backend Pod 的一个端口的名称。 因实际指派给该端口名称的端口号,在每个 backend Pod 中可能并不相同,所以对于部署和设计 Service ,这种方式会提供更大的灵活性。

另外Service能够支持 TCP 和 UDP 协议,默认是 TCP 协议。

4. kube-proxy

在Kubernetes集群中,每个Node会运行一个kube-proxy进程, 负责为Service实现一种 VIP(虚拟 IP,就是clusterIP)的代理形式。Service其实是由kube-proxy组件和Iptables来实现的。

现在的Kubernetes中默认是使用的iptables这种模式来代理这种模式,kube-proxy会监视Kubernetes master对 Service 对象和 Endpoints (端点)对象的添加和移除。 对每个 Service,它会添加上 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend(后端) 中的某一个个上面。 对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod。

默认的策略是,随机选择一个 backend。 我们也可以实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity 的值设置为 "ClientIP" (默认值为 "None")。

5. Service 的类型

ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的ServiceType。NodePort:通过每个 Node 节点上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 :,可以从集群的外部访问一个 NodePort 服务。LoadBalancer:使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务,这个需要结合具体的云厂商进行操作。ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持。

NodePort

如果设置 type 的值为 "NodePort",端口可以通过 Service 的 spec.ports[*].nodePort 字段来指定,如果不指定的话会自动生成一个端口,Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。

需要注意的是,Service 将能够通过 :spec.ports[].nodePort 和 spec.clusterIp:spec.ports[].port 而对外可见。

现在我们修改上面的Service,将Cluster IP 改为NodePort,指定nodeport为30088

apiVersion: v1kind: Servicemetadata:  name: httpd-svcspec:   selector:     app: httpd   type: NodePort   ports:   - protocol: TCP     port: 80     targetPort: 80     nodePort: 30088

现在我们更新这个Service

[root@master testyml]# kubectl   apply -f  svc.yml Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl applyservice "httpd-svc" configured[root@master testyml]# kubectl  get svcNAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGEhttpd-svc          NodePort    10.108.195.47          8080:30088/TCP   16hkubernetes         ClusterIP   10.96.0.1              443/TCP          115dmysql-production   ClusterIP   10.102.208.69          3306/TCP         14dorder              NodePort    10.99.99.88            8080:30080/TCP   17d

ExternalName

ExternalName 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。 对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

kind: ServiceapiVersion: v1metadata:  name: my-service  namespace: prodspec:  type: ExternalName  externalName: my.database.example.com

当查询主机 my-service.prod.svc.cluster.local ,集群的 DNS 服务将返回一个值为 my.database.example.com 的 CNAME 记录。 访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。 如果后续决定要将数据库迁移到 Kubernetes 集群中,可以启动对应的 Pod,增加合适的 Selector 或 Endpoint,修改 Service 的 type,完全不需要修改调用的代码,这样就完全解耦了。

上一篇:简单聊聊Kubernetes的定向调度
下一篇:Kubernetes 健康状态检查 liveness 和 readiness
相关文章

 发表评论

暂时没有评论,来抢沙发吧~