目录
Kubernetes Service:
没有 selector 的 Service :
VIP 和 Service 代理:
userspace 代理模式:
iptables 代理模式:
多端口 Service:
选择自己的 IP 地址:
服务发现:
Headless Service:
配置 Selector:
发布服务 —— 服务类型:
NodePort 类型:
LoadBalancer 类型:
AWS 内部负载均衡器:
AWS SSL 支持:
外部 IP:
不足之处:
未来:
避免冲突:
IP 和 VIP:
API 对象:
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。
这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector实现的。
对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变更,应用程序就会被更新。
非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Pod。
一个 Service 在 Kubernetes 中是一个 REST 对象,和 Pod 类似。
Service 定义可以基于 POST 方式,请求 apiserver 创建新的实例。
Service 能够将一个接收端口映射到任意的 targetPort。
targetPort 可以是一个字符串,引用了 backend Pod 的一个端口的名称。
Kubernetes Service 能够支持 TCP 和 UDP 协议,默认 TCP 协议。
Servcie 抽象了该如何访问 Kubernetes Pod,但也能够抽象其它类型的 backend。
希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
希望服务指向另一个 Namespace 中或其它集群中的服务。
正在将工作负载转移到 Kubernetes 集群,和运行在 Kubernetes 集群之外的 backend。
Service 没有定义 selector,就不会创建相关的 Endpoints 对象。可以手动将 Service 映射到指定的 Endpoints。
ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。
对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
当查询主机my-service.prod.svc.CLUSTER时,集群的 DNS 服务将返回一个键为 externalName的值的 CNAME 记录。
Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。
kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。
从 Kubernetes v1.2 起,默认就是 iptables 代理。
kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。
对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。
任何连接到“代理端口”的请求,都会被代理到 Service 的backend Pods 中的某个上面。
使用哪个 backend Pod,是基于 Service 的 SessionAffinity 来确定的。
使用哪个 backend Pod,是基于 Service 的 SessionAffinity 来确定的。
任何到达 Service 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、Service、或 Pod 的任何信息。
默认的策略是,通过 round-robin 算法来选择 backend Pod。
实现基于客户端 IP 的会话亲和性,可以通过设置 service.spec.sessionAffinity 的值为 "ClientIP" 。
kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。
每个 Service,它会安装 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。
每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod。
默认的策略是,随机选择一个 backend。
实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity 的值设置为 "ClientIP"。
任何到达 Service 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、Service、或 Pod 的任何信息。
比 userspace 代理更快、更可靠。
Kubernetes 支持在 Service 对象中定义多个端口。
当使用多个端口时,必须给出所有的端口的名称,这样 Endpoint 就不会产生歧义
通过设置 spec.clusterIP 字段来指定自己的集群 IP 地址。
Kubernetes 支持2种基本的服务发现模式 —— 环境变量和 DNS。
环境变量:
kubelet 会为每个活跃的 Service 添加一组环境变量。
支持 Docker links兼容 变量、简单的 {SVCNAME}_SERVICE_HOST 和 {SVCNAME}_SERVICE_PORT 变量
Pod 想要访问的任何 Service 必须在 Pod 自己之前被创建,否则这些环境变量就不会被赋值(DNS 并没有这个限制)。
DNS:
一个可选(尽管强烈推荐)集群插件 是 DNS 服务器。
DNS 服务器监视着创建新 Service 的 Kubernetes API,从而为每一个 Service 创建一组 DNS 记录。
整个集群的 DNS 一直被启用,那么所有的 Pod 应该能够自动对 Service 进行名称解析。
Kubernetes 也支持对端口名称的 DNS SRV(Service)记录。
Kubernetes DNS 服务器是唯一的一种能够访问 ExternalName 类型的 Service 的方式。
通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。
允许开发人员自由寻找他们自己的方式,从而降低与 Kubernetes 系统的耦合性。
应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个 API 来构建。
这类 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们,而且平台也不会为它们进行负载均衡和路由。
DNS 如何实现自动配置,依赖于 Service 是否定义了 selector。
对定义了 selector 的 Headless Service,Endpoint 控制器在 API 中创建了 Endpoints 记录,并且修改 DNS 配置返回 A 记录(地址),通过这个地址直接到达 Service 的后端 Pod上。
不配置 Selector:
对没有定义 selector 的 Headless Service,Endpoint 控制器不会创建 Endpoints 记录。
ExternalName 类型 Service 的 CNAME 记录
记录:与 Service 共享一个名称的任何 Endpoints,以及所有其它类型
对一些应用(如 Frontend)的某些部分,可能希望通过外部(Kubernetes 集群外部)IP 地址暴露 Service。
Kubernetes ServiceTypes 允许指定一个需要的类型的 Service,默认是 ClusterIP 类型。
Type 的取值:
ClusterIP:
通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。
NodePort:
通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求
LoadBalancer:
使用云提供商的负载局衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
ExternalName:
通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容。
type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。
该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定。
需要指定的端口号,可以配置 nodePort 的值,系统将分配这个端口,否则调用 API 将会失败。
Service 将能够通过
使用支持外部负载均衡器的云提供商的服务,设置 type 的值为 "LoadBalancer",将为 Service 提供负载均衡器。
负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Service 的 status.loadBalancer 字段被发布出去。
在混合云环境中,有时从虚拟私有云(VPC)环境中的服务路由流量是非常有必要的。
可以通过在 Service 中增加 annotation 来实现。
在水平分割的 DNS 环境中,需要两个 Service 来将外部和内部的流量路由到 Endpoint 上。
对运行在 AWS 上部分支持 SSL 的集群,可以为 LoadBalancer 类型的 Service 增加两个 annotation:
第一个 annotation 指定了使用的证书。
第二个 annotation 指定了 Pod 使用的协议。
HTTP 和 HTTPS 将选择7层代理:ELB 将中断与用户的连接,当转发请求时,会解析 Header 信息并添加上用户的 IP 地址
TCP 和 SSL 将选择4层代理:ELB 将转发流量,并不修改 Header 信息。
外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。
通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量,将会被路由到 Service 的 Endpoint 上。
externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。
Service 的规定,externalIPs 可以同任意的 ServiceType 来一起指定。
为 VIP 使用 userspace 代理,将只适合小型到中型规模的集群,不能够扩展到上千 Service 的大型集群。
使用 userspace 代理,隐藏了访问 Service 的数据包的源 IP 地址,这使得一些类型的防火墙无法起作用。
iptables 代理不会隐藏 Kubernetes 集群内部的 IP 地址,但却要求客户端请求必须通过一个负载均衡器或 Node 端口。
Type 字段支持嵌套功能 —— 每一层需要添加到上一层里面。
为 Service 实现更加灵活的请求进入模式,这些 Service 包含当前 ClusterIP、NodePort 和 LoadBalancer 模式
Kubernetes 最主要的哲学之一,是用户不应该暴露那些能够导致他们操作失败、但又不是他们的过错的场景。
用户不应该必须选择一个端口号,而且该端口还有可能与其他用户的冲突。
在彼此隔离状态下仍然会出现失败。
为了使用户能够为他们的 Service 选择一个端口号,我们必须确保不能有2个 Service 发生冲突。
通过为每个 Service 分配它们自己的 IP 地址来实现。
保证每个 Service 被分配到一个唯一的 IP,需要一个内部的分配器能够原子地更新 etcd 中的一个全局分配映射表,这个更新操作要先于创建每一个 Service。
使 Service能够获取到 IP,这个映射表对象必须在注册中心存在,否则创建 Service 将会失败,指示一个 IP 不能被分配。
Service 的 IP 实际上不能通过单个主机来进行应答。
我们使用 iptables来定义一个虚拟IP地址(VIP),它可以根据需要透明地进行重定向。
当客户端连接到 VIP 时,它们的流量会自动地传输到一个合适的 Endpoint。
环境变量和 DNS,实际上会根据 Service 的 VIP 和端口来进行填充。
在 Kubernetes REST API 中,Service 是 top-level 资源。
内容整理自Kubernetes中文社区:https://www.kubernetes.org.cn/