一、前言
前一篇文章通过 Deployment 实现了Pod中服务实现滚动更新/回滚等操作;在真实应用场景中,需要将一组Pod提供给外部访问。而且Pod生命周期是短暂的,在 Pod 的生命周期过程中,比如它创建或销毁, IP 地址都会发生变化。不能使用传统的部署方式使用IP方式访问。
所以需要将Deployment 创建的Pod组统一提供一个访问入口,需要提供给外部的用户去调用的。此时就需要服务发现。那么在k8s中怎么实现呢?—Service
二、服务-Service
1、Service 的定义
Service是 k8s 的核心资源类型之一,Service是将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
Service资源基于标签选择器将一组Pod定义成一个逻辑组合,并通过自己的IP地址和端口调度代理请求到组内的Pod对象
2、Service 的工作方式
在 k8s 集群中,每个 Node 运行一个 kube-proxy
进程。 kube-proxy
负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName
的形式。
kube-proxy 这个组件始终监视着apiserver中有关service的变动信息,获取任何一个与service资源相关的变动状态,通过watch监视,一旦有service资源相关的变动和创建,kube-proxy都要转换为当前节点上的能够实现资源调度规则(例如:iptables、ipvs)
-
userspace 代理模式
kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints 对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods
中的某个上面(如 Endpoints
所报告的一样)。 使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity
来确定的。
最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP
(是虚拟 IP) 和 Port
的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。
默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。
-
iptables 代理模式
这种模式,kube-proxy
会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP
和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。
默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。
使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理, 而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。
如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。
你可以使用 Pod 就绪探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。
-
ipvs 代理模式
在 ipvs
模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink
接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端Pod之一。
IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模 式还支持更高的网络流量吞吐量。
IPVS 提供了更多选项来平衡后端 Pod 的流量。 这些是:
-
-
rr
:轮替(Round-Robin) -
lc
:最少链接(Least Connection),即打开链接数量最少者优先 -
dh
:目标地址哈希(Destination Hashing) -
sh
:源地址哈希(Source Hashing) -
sed
:最短预期延迟(Shortest Expected Delay) -
nq
:从不排队(Never Queue)
-
3、Service的使用
a、服务类型:创建Service对象,指定类型为NodePort
apiVersion: v1 kind: Service # 定义Kubernetes资源的类型为Service metadata: name: k8sdemoweb-service # 定义资源的名称 spec: selector: # 指定对应的Pod app: k8demosweb # 指定Pod的标签为k8sweb ports: - protocol: TCP # 协议类型 port: 80 # 指定Service访问的端口 targetPort: 80 # 指定Service转发请求的端口 nodePort: 31001 type: NodePort # 指定Service的类型,在这里使用NodePort来对外访问
对一些应用的某些部分(如前端),可能希望将其暴露给 Kubernetes 集群外部 的 IP 地址
Kubernetes ServiceTypes
允许指定你所需要的 Service 类型,默认是 ClusterIP
。
Type
的取值以及行为如下:
-
-
ClusterIP
:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的ServiceType
。 -
NodePort
:通过每个节点上的 IP 和静态端口(NodePort
)暴露服务。NodePort
服务会路由到自动创建的ClusterIP
服务。 通过请求<节点 IP>:<节点端口>
,你可以从集群的外部访问一个NodePort
服务。 -
LoadBalancer
:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的NodePort
服务和ClusterIP
服务上。 -
ExternalName
:通过返回CNAME
和对应值,可以将服务映射到externalName
字段的内容(例如,foo.bar.example.com
)。 无需创建任何类型代理。
-
b、Headless Services(无头服务)
有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP
)的值为 "None"
来创建 Headless
Service。
- 带选择算符的服务
对定义了选择算符的无头服务,Endpoint 控制器在 API 中创建了 Endpoints 记录, 并且修改 DNS 配置返回 A 记录(IP 地址),通过这个地址直接到达 Service
的后端 Pod 上。
- 无选择算符的服务
对没有定义选择算符的无头服务,Endpoint 控制器不会创建 Endpoints
记录。 然而 DNS 系统会查找和配置,无论是:
-
- 对于
ExternalName
类型的服务,查找其 CNAME 记录 - 对所有其他类型的服务,查找与 Service 名称相同的任何
Endpoints
的记录
- 对于
三、使用Service访问应用:
访问在前面创建的服务:由于本机IP为:192.168.0.109,直接访问192.168.0.109:31001 时,直接访问失败。安装Service类型的描述,该Service类型为NodePort;应该就可以直接访问成功。
但由于本机的k8s环境是使用:minikube 运行在Docker环境中。真实的k8s Node不是本机,导致访问失败。
启动服务访问:
//开启服务访问 PS > minikube service k8sdemoweb-service |-----------|--------------------|-------------|---------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|--------------------|-------------|---------------------------| | default | k8sdemoweb-service | 80 | http://192.168.49.2:31001 | |-----------|--------------------|-------------|---------------------------| * Starting tunnel for service k8sdemoweb-service. |-----------|--------------------|-------------|------------------------| | NAMESPACE | NAME | TARGET PORT | URL | |-----------|--------------------|-------------|------------------------| | default | k8sdemoweb-service | | http://127.0.0.1:29752 | |-----------|--------------------|-------------|------------------------| * 正通过默认浏览器打开服务 default/k8sdemoweb-service... ! Because you are using a Docker driver on windows, the terminal needs to be open to run it.
访问地址:http://127.0.0.1:29752
通过上图看到,访问应用通过Service负载到不同的Pod节点上。