【K8s 精选】Kubernetes Service 介绍
1.Service 背景
问题1:为什么需要服务发现
① 容器 Pod 生命周期短暂,容器 IP 地址随时变化
② Deployment 中的 Pod 组需要统一的访问入口和负载均衡
③ 应用在不同部署环境需要统一部拓扑和访问方式
问题2:如何提供外部访问和负载均衡的能力
Kubernetes Service 具备服务发现和负载均衡的功能,即一方面提供了统一的访问入口,另一方面负载均衡到后端 Pod。下图是 Service 的简约架构图,左侧表示 Service 提供了外部访问和 Pod 网络访问 ,右侧表示对接了一组 Pod,同时把请求负载均衡到这组 Pod。
2.Service 架构
Kubernetes 服务发现架构.JPG① Master 节点:Kubernetes 管理节点,负责管理和控制整个集群,包含的组件是 APIServer、Controller Manager 和Scheduler。
② Worker 节点:Kubernetes 工作负载节点,包含的组件主要有 Kubelet、Kube-proxy。
2.1 Service 的关键组件
① APIServer:Kubernetes 所有对象都会注册到 APIServer上,监听这些对象的变化,例如 Pod、StatefulSet、Service 等。
② Controller Manager:负责配置 LoadBalance 的一个负责均衡器给外部访问。
③ Coredns:负责把 Service 名字(类似域名)解析为 Service 虚拟 IP 即 ClusterIP,同时观测 Service 的变化。
④ Kube-proxy:负责把 Service 虚拟 IP 即 ClusterIP 转换为后端 Pod IP,同时观测后端 Pod 的变化。
2.2 访问链路分析
2.2.1 集群内部访问
如上架构图示例,Client Pod3 访问 Service 的步骤:
① Coredns 解析出 CluserIP:Client Pod3 拿着 Service name (域名)请求 Coredns,Coredns 解析域名后返回 ClusterIP。
② Kube-proxy 拦截后负载均衡到后端 Pod:Client Pod3 拿着 ClusterIP 请求宿主机网络后,被 Kube-proxy 所配置的 iptables 拦截了,随后负债均衡转发到后端 Pod。
2.2.2 集群外部访问
① LoaderBalancer 转发请求到某节点的 NodePort:外部请求通过 LoaderBalancer 转发到某节点的 NodePort,同时 LoaderBalander 通过 Controller Manager 监听 Service 的变化。
② Kube-proxy 把 NodePort 转换为 ClusterIP 并转发到后端 Pod:NodePort 的请求被 Kube-proxy 所配置的 iptables 拦截并转发到 CluserIP,最终转发到后端 Pod。
3.Service 示例
3.1 创建和查看 Service
# 创建 service
$kubectl apply -f service.yaml
# 查看 service
$kubectl describe service my-service
Name: my-service
Namespace: default
Labels: app=my-service
Selector: app=MyApp
Type: ClusterIP
IP: 172.29.3.27 # Service 虚拟 IP
Port: 80/TCP
TargetPort: 9376/TCP
Endpoints: 192.168.115.236:9376,192.168.115.237:9376,192.168.115.238:9376 # Selector 匹配到的后端 Pod 地址
Session Affinity: None
3.2 集群内访问 Service
3.2.1 ClusterIP 访问
集群内访问Service.JPG① 直接使用 ClusterIP
# 查询 ClusterIP
$kubectl get svc |grep my-service
② 直接使用 Service Name,Codedns 解析
{servicename}.{namespace}.svc.cluster.local
③ 使用环境变量访问
MY_SERVICE_PORT_80_TCP_PROTO=tcp
MY_SERVICE_PORT=tcp://172.29.3.27:80
MY_SERVICE_SERVICE_PORT=80
MY_SERVICE_PORT_80_TCP_PORT=80
MY_SERVICE_PORT_80_TCP=tcp://172.29.3.27:80
MY_SERVICE_SERVICE_PORT=80
MY_SERVICE_SERVICE_HOST=172.29.3.27
MY_SERVICE_PORT_80_TCP_ADDR=172.29.3.27
3.2.1 Headless Service
Headless访问.JPGapiVersion: v1
kind: Service
metadata:
name: my-service
label:
app: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
selector:
app: myApp
clusterIP: None # 作用是让 Service 不再通过虚拟 IP 来负载均衡
① 通过 Service Name 可以直接解析到所有后端 Pod IP
② 客户端可以自主选择需要访问的 Pod IP
3.3 集群外访问 Service
集群外访问Service.JPGapiVersion: v1
kind: Service
metadata:
name: my-service
label:
app: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 30080
selector:
app: myApp
type: NodePort