陕西省建设监理协会网站成绩查询,台州市住房和城乡建设局网站,wordpress性能承载量,软考网络规划设计师Service
之前我们了解了Pod的基本用法#xff0c;我们也了解到Pod的生命是有限的#xff0c;死亡过后不会复活了。我们后面学习到的RC和Deployment可以用来动态的创建和销毁Pod。尽管每个Pod都有自己的IP地址#xff0c;但是如果Pod重新启动了的话那么他的IP很有可能也就变…Service
之前我们了解了Pod的基本用法我们也了解到Pod的生命是有限的死亡过后不会复活了。我们后面学习到的RC和Deployment可以用来动态的创建和销毁Pod。尽管每个Pod都有自己的IP地址但是如果Pod重新启动了的话那么他的IP很有可能也就变化了。这就会带来一个问题比如我们有一些后端的Pod的集合为集群中的其他前端的Pod集合提供API服务如果我们在前端的Pod中把所有的这些后端的Pod的地址都写死然后去某种方式去访问其中一个Pod的服务这样看上去是可以工作的对吧但是如果这个Pod挂掉了然后重新启动起来了是不是IP地址非常有可能就变了这个时候前端就极大可能访问不到后端的服务了。
遇到这样的问题该怎么解决呢在没有使用Kubernetes之前我相信可能很多人都遇到过这样的问题不一定是IP变化的问题比如我们在部署一个WEB服务的时候前端一般部署一个Nginx作为服务的入口然后Nginx后面肯定就是挂载的这个服务的大量后端很早以前我们可能是去手动更改Nginx配置中的upstream选项来动态改变提供服务的数量到后面出现了一些服务发现的工具比如Consul、ZooKeeper还有我们熟悉的etcd等工具有了这些工具过后我们就可以只需要把我们的服务注册到这些服务发现中心去就可以然后让这些工具动态的去更新Nginx的配置就可以了我们完全不用去手工的操作了是不是非常方便。
同样的要解决我们上面遇到的问题是不是实现一个服务发现的工具也可以解决啊没错的当我们Pod被销毁或者新建过后我们可以把这个Pod的地址注册到这个服务发现中心去就可以但是这样的话我们的前端的Pod结合就不能直接去连接后台的Pod集合了是吧应该连接到一个能够做服务发现的中间件上面对吧
没错Kubernetes集群就为我们提供了这样的一个对象 - ServiceService是一种抽象的对象它定义了一组Pod的逻辑集合和一个用于访问它们的策略其实这个概念和微服务非常类似。一个Serivce下面包含的Pod集合一般是由Label Selector来决定的。
比如我们上面的例子假如我们后端运行了3个副本这些副本都是可以替代的因为前端并不关心它们使用的是哪一个后端服务。尽管由于各种原因后端的Pod集合会发送变化但是前端却不需要知道这些变化也不需要自己用一个列表来记录这些后端的服务Service的这种抽象就可以帮我们达到这种解耦的目的。
三种IP
在继续往下学习Service之前我们需要先弄明白Kubernetes系统中的三种IP这个问题因为经常有人混乱。
Node IPNode节点的IP地址Pod IP: Pod的IP地址Cluster IP: Service的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来组成一个可以通信的服务。
定义Service
定义Service的方式和我们前面定义的各种资源对象的方式类型例如假定我们有一组Pod服务它们对外暴露了 8080 端口同时都被打上了appmyapp这样的标签那么我们就可以像下面这样来定义一个Service对象
apiVersion: v1
kind: Service
metadata:name: myservice
spec:selector:app: myappports:- protocol: TCPport: 80targetPort: 8080name: myapp-http然后通过的使用kubectl create -f myservice.yaml就可以创建一个名为myservice的Service对象它会将请求代理到使用 TCP 端口为 8080具有标签appmyapp的Pod上这个Service会被系统分配一个我们上面说的Cluster IP该Service还会持续的监听selector下面的Pod会把这些Pod信息更新到一个名为myservice的Endpoints对象上去这个对象就类似于我们上面说的Pod集合了。
需要注意的是Service能够将一个接收端口映射到任意的targetPort。 默认情况下targetPort将被设置为与port字段相同的值。 可能更有趣的是targetPort 可以是一个字符串引用了 backend Pod 的一个端口的名称。 因实际指派给该端口名称的端口号在每个 backend Pod 中可能并不相同所以对于部署和设计 Service 这种方式会提供更大的灵活性。
另外Service能够支持 TCP 和 UDP 协议默认是 TCP 协议。
kube-proxy
前面我们讲到过在Kubernetes集群中每个Node会运行一个kube-proxy进程, 负责为Service实现一种 VIP虚拟 IP就是我们上面说的clusterIP的代理形式现在的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”。
另外需要了解的是如果最开始选择的 Pod 没有响应iptables 代理能够自动地重试另一个 Pod所以它需要依赖 readiness probes。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sD0QIvZU-1678238488098)(./images/services-iptables-overview.svg)]
Service 类型
我们在定义Service的时候可以指定一个自己需要的类型的Service如果不指定的话默认是ClusterIP类型。
我们可以使用的服务类型如下 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”Kubernetes master 将从给定的配置范围内默认30000-32767分配端口每个 Node 将从该端口每个 Node 上的同一端口代理到 Service。该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定如果不指定的话会自动生成一个端口。
需要注意的是Service 将能够通过 :spec.ports[].nodePort 和 spec.clusterIp:spec.ports[].port 而对外可见。
接下来我们来给大家创建一个NodePort的服务来访问我们前面的Nginx服务(保存为service-demo.yaml)
apiVersion: v1
kind: Service
metadata:name: myservice
spec:selector:app: myapptype: NodePortports:- protocol: TCPport: 80targetPort: 80name: myapp-http创建该Service:
$ kubectl create -f service-demo.yaml然后我们可以查看Service对象信息
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 none 443/TCP 27d
myservice NodePort 10.104.57.198 none 80:32560/TCP 14h我们可以看到myservice的 TYPE 类型已经变成了NodePort后面的PORT(S)部分也多了一个 32560 的映射端口。
ExternalName
ExternalName 是 Service 的特例它没有 selector也没有定义任何的端口和 Endpoint。 对于运行在集群外部的服务它通过返回该外部服务的别名这种方式来提供服务。
kind: Service
apiVersion: v1
metadata:name: my-servicenamespace: prod
spec:type: ExternalNameexternalName: my.database.example.com当查询主机 my-service.prod.svc.cluster.local 后面服务发现的时候我们会再深入讲解时集群的 DNS 服务将返回一个值为 my.database.example.com 的 CNAME 记录。 访问这个服务的工作方式与其它的相同唯一不同的是重定向发生在 DNS 层而且不会进行代理或转发。 如果后续决定要将数据库迁移到 Kubernetes 集群中可以启动对应的 Pod增加合适的 Selector 或 Endpoint修改 Service 的 type完全不需要修改调用的代码这样就完全解耦了。