功能概述
kubernetes Services服务提供VIP访问对应的POD的功能,这种做法是非常好的,因为后台的POD不会是一成不变的,比如升级服务的时候POD的IP会改变,要访问到对应的服务的POD那就得改对应的IP,而kubernetes Services正是为此而生,很好得解决了这个问题。
对于Kubernetes原生应用程序,Kubernetes提供了一个简单的Endpoints API,只要服务中的Pod集合发生更改,该API就会更新。 对于非本机应用程序,Kubernetes提供了一个基于虚拟IP的网桥,用于重定向到后端Pod的服务。
定义Service
kind: Service
apiVersion: v1
metadata:
name: my-service //名字
spec:
selector:
app: MyApp //选择带有label 为app: MyApp的值的pods
ports:
- protocol: TCP //协议
port: 80 //内部端口
targetPort: 9376 //暴露的端口 默认port的值相同
kubernetes Services支持TCP UDP协议,默认是TCP协议
kubernetes Services通常抽象化访问Kubernetes Pods,但它也可以抽象其他种类的后端。 例如:
- 您想要在生产中使用外部数据库群集,但在测试中您使用自己的数据库。
- 您希望将您的服务指向另一个名称空间或另一个群集中的服务。
- 您正在将工作负载迁移到Kubernetes,而您的一些后端运行在Kubernetes之外。
在以上三种情况下,可以做如下处理:
定义一个没有selector的Service
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
由于这些Services没有选择对应的PODS,因此 Endpoints
是没有生成的,因此可以手动将服务映射到您自己的特定端点:
kind: Endpoints
apiVersion: v1
metadata:
name: my-service
subsets:
- addresses:
- ip: 1.2.3.4
ports:
- port: 9376
在没有选择器的情况下访问服务就像它有一个选择器一样工作。 流量将被路由到用户定义的端点
ExternalName
服务是没有选择器的特殊服务。 它没有定义任何端口或端点。 相反,它可以作为将别名返回到驻留在群集外部的外部服务的一种方式。
例如:
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
对于这种Service,查找主机my-service.prod.svc.CLUSTER时,集群DNS服务将返回值为my.database.example.com的CNAME记录。 访问这种服务的方式与其他服务一样,唯一的区别在于重定向发生在DNS级别,并且没有代理或转发发生。 如果您稍后决定将数据库移动到群集中,则可以启动它的容器,添加适当的选择器或端点并更改服务类型。
虚拟IP和服务代理
Proxy-mode: userspace
在此模式下,kube-proxy监视Kubernetes master 以添加和删除Service和Endpoints对象。 对于每个服务,它会在本地节点上打开一个端口(随机选择)。 与此“代理端口”的任何连接都将代理到服务的后端Pod之一(如端点中所报告的)。 根据服务的SessionAffinity决定使用哪个后端Pod。 最后,它安装了iptables规则,这些规则将流量捕获到服务的clusterIP(这是虚拟的)和Port,并将该流量重定向到代理后端Pod的代理端口。 默认情况下,后端的选择是循环法。
Proxy-mode: iptables
在此模式下,kube-proxy监视Kubernetes master以添加和删除Service和Endpoints对象。 对于每个服务,它都会安装iptables规则,这些规则将流量捕获到服务的clusterIP(这是虚拟的)和端口,并将该流量重定向到服务的后端集合之一。 对于每个Endpoints对象,它都会安装选择后端Pod的iptables规则。 默认情况下,后端的选择是随机的。
显然,iptables不需要在用户空间和内核空间之间切换,它应该比用户空间代理更快,更可靠。 但是,与用户空间连接器不同,如果iptables连接器最初选择的连接器不响应,iptables连接器不能自动重试另一个连接,因此它依赖于正在工作的准备就绪探测器。
Proxy-mode: ipvs
在这种模式下,Kubernetes Services和Endpoints调用netlink接口来相应地创建ipvs规则,并定期与Kubernetes Services和Endpoints同步ipvs规则,以确保ipvs状态与预期一致。当访问服务时,流量将被重定向到其中一个后端Pod。
与iptables类似,Ipvs基于netfilter钩子函数,但使用散列表作为基础数据结构并在内核空间中工作。这意味着ipvs可以更快地重定向流量,并且在同步代理规则时具有更好的性能。此外,ipvs为负载均衡算法提供了更多选项,例如:
rr:循环法
lc:最少连接
dh:目标哈希
sh:源哈希
sed:预计的最短延迟
nq:从不排队
注意:在运行kube-proxy之前,ipvs模式假定在节点上安装了IPVS内核模块。当kube-proxy以ipvs代理模式启动时,kube-proxy会验证节点上是否安装了IPVS模块,如果未安装,kube-proxy将回退到iptables代理模式。
Multi-Port Services
许多服务需要公开多个端口。 对于这种情况,Kubernetes支持Service对象上的多个端口定义。 使用多个端口时,您必须提供所有端口名称,以便可以消除端点的歧义,例如:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
Choosing your own IP address
您可以将自己的群集IP地址指定为服务创建请求的一部分。设置spec.clusterIP
字段。例如,如果您已经有一个想要替换的现有DNS条目,或者已配置了特定IP地址并且难以重新配置的旧系统。用户选择的IP地址必须是有效的IP地址,并且位于由API标记指定给API服务器的service-cluster-ip-range
CIDR范围内。如果IP地址值无效,则apiserver将返回一个422 HTTP状态码,以指示该值无效。
为什么不使用循环法DNS?
一个不时出现的问题就是为什么我们用虚拟IP来完成所有这些工作,而不仅仅是使用标准的循环法DNS。有几个原因:
DNS库不不支持DNS TTL并缓存名称查找的结果有很长的历史。
许多应用程序只执行一次DNS查找并缓存结果。
即使应用程序和库进行了适当的重新解析,每个客户端重复解析DNS的负载也难以管理。
Discovering services
Kubernetes支持2种主要模式来查找服务: 环境变量和DNS。
环境变量
当Pod在节点上运行时,kubelet将为每个活动的服务添加一组环境变量。 它支持Docker链接兼容变量(请参阅makeLinkVariables)和更简单的{SVCNAME} _SERVICE_HOST
和{SVCNAME} _SERVICE_PORT
变量,其中服务名称为上限,破折号转换为下划线。
例如,暴露TCP端口6379且已分配了群集IP地址10.0.0.11的服务“redis-master”会生成以下环境变量:
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
但是这种方式有种限制:
任何Pod想要访问的服务都必须在Pod本身之前创建,否则环境变量将不会被填充。 DNS没有这个限制。
DNS
DNS服务器是k8s集群插件。 DNS服务器为watch new Service Kubernetes API并为每个服务创建一组DNS记录。 如果在整个集群中启用了DNS,则所有的Pod应该能够自动进行服务的名称解析。
例如,如果您在Kubernetes命名空间“my-ns”中有一个名为“my-service”的服务,则会创建“my-service.my-ns”的DNS记录。 存在于“my-ns”命名空间中的Pod应该能够通过简单地为“my-service”进行名称查找来找到它。 存在于其他命名空间中的Pod必须将该名称限定为“my-service.my-ns”。 这些名称查找的结果是群集IP。
Kubernetes还支持命名端口的DNS SRV(服务)记录。 如果“my-service.my-ns”服务的TCP端口名为“http”,则可以对“_http._tcp.my-service.my-ns”执行DNS SRV查询以发现端口号“HTTP”。
Headless services
有时你不需要或不需要负载平衡和单一服务IP。 在这种情况下,您可以通过为群集IP(spec.clusterIP
)指定 None
来创建 Headless services 服务。
该选项允许开发人员通过允许他们自由发现自己的方式来减少与Kubernetes系统的耦合。 应用程序仍然可以使用自注册模式,而其他发现系统的适配器可以轻松构建在此API上。
对于此类服务,群集IP未分配,kube-proxy不处理这些服务,并且平台没有为它们执行负载平衡或代理。 DNS如何自动配置取决于服务是否具有已定义的选择器。
Publishing services - service types
对于应用程序的某些部分(例如前端),您可能希望将服务公开到外部(群集外部)IP地址。
Kubernetes ServiceTypes允许您指定您想要的服务类型。默认是ClusterIP
。
Type
值:
ClusterIP
:将服务公开在集群内部的IP上。选择此值将使该服务仅在群集内可访问。这是默认的ServiceType
。
NodePort
:在静态端口(NodePort)上公开每个节点的IP上的服务。将自动创建NodeIP服务将路由到的ClusterIP服务。您可以通过请求<NodeIP>:<NodePort>
,从集群外部联系NodePort
服务。
LoadBalancer
:使用云提供商的负载均衡器在外部公开服务。将自动创建外部负载平衡器将路由到的NodePort
和ClusterIP
服务。
ExternalName
:通过返回CNAME记录及其值,将服务映射到externalName
字段的内容(例如foo.bar.example.com)。没有任何代理设置。
注意:1.7版或更高版本的kube-dns。
end
更多内容请访问官网kubernetes-Services