kubernetes Service(SVC)
service 概念
SVC 通过 Label Selector 标签选择的方式,匹配一组 Pod,对外访问服务。每一个 SVC可以理解成为一个微服务。
service 能够提供负载均衡的能力,但是在使用上有以下限制:
- 只提供4层负载均衡能力(只有 RR 轮询算法),而没有7层功能,如果需要更多的匹配规则来转发请求,4层上的负载均衡是不支持的。
service 类型
Clusterip:默认类型,自动分配一个仅 Cluster 内部可以访问的 虚拟IP,一般用作集群内部负载均衡。
NodePort(service向外暴露):在ClusterIP 基础上为 Service 在每台机器上绑定一个映射端口,外网客户端可以通过 NodeIP,Nodeport访问。
LoadBalancer(service向外暴露):在 NodePort 基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到 NodeIP 和 NodePort
ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,只有1.7之后版本的 kube-dns支持。
SVC 访问流程组件
- 首先 apiserver 监听 kube-proxy 去进行服务和端口的发现。
- 通过kube-proxy监控,kube-proxy监控所有 Pod 节点信息,标签、IP、port 等,并负责把它们写入到 iptables 规则当中。
- client 访问 SVC,其实访问的是 iptables规则。再由 iptables 导向后端 Pod 节点。
- ipvs,图片上没有,现在的ClusterIP,NodePort 都是采取 ipvs 调度算法对后端 Pod 节点进行调度访问。
VIP 和 Service 代理
在kubernetes集群中,每个 Node 运行一个 Kube-porxy 进程。kube-proxy负责为 service 实现了一种 VIP (虚拟IP) 的形式,而不是 ExternaName 的形式。
service 是 “4层(TCP/UDP over IP)概念”,在1.1版本 新增了 Ingress API(beat 版),用来表示“7层代理”。
代理模式分类
Ⅰ、userspace 代理模式
client Pod 想要访问 Server Pod
- 首先经过 Service IP(iptables),由 iptables
转发至kube-proxy,kube-proxy根据访问的地址,端口进行转发,需要 kube-proxy 充当代理功能。
- 其次 kube-apiserver 也会去监听 kube-proxy,kube-proxy 是否进行所有 Pod 信息的写入。
- 导致 kube-proxy 的工作负载量过大,压力过大。
Ⅱ、Iptables 代理模式
client Pod 访问 Server Pod
所有的请求,代理全部由 iptables 来完成,不再需要 kube-proxy 充当代理角色。
提高了 稳定性和访问效率,压力减少
Ⅲ、ipvs 代理模式
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN
交换,作为 Linux 内核的一部分。ipvs
运行在主机上,在真实服务器集群前充当负载均衡器。ipvs
可以将基于TCP
和UDP
的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。
ipvs 对比 iptables
我们知道kube-proxy
支持 iptables 和 ipvs 两种模式, 在kubernetes
v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter
的,那么 ipvs 模式和 iptables 模式之间有哪些差异呢?
- ipvs 为大型集群提供了更好的可扩展性和性能
- ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
- ipvs 支持服务器健康检查和连接重试等功能
ipvs为负载均衡提供算法:
- rr:轮询带哦都
- lc:最小连接数
- dh:目标地址哈希
- sh:源地址哈希
- sed:最短期望延迟
- nq:不排队调度
注意:ipvs 模式假定在运行 kube-proxy 之前在节点上都已经安装了 IPVS 内核模块。当 kube-proxy 以 ipvs 代理模式启动时,kube-proxy 将验证节点上是否安装了 IPVS 模块,如果未安装,则 kube-proxy 将回退到 iptables 代理模式
client Pod 访问 Server Pod
- 首先,service IP 的 iptables代理变成了 ipvs 模块,实现负载均衡和流量导向。
- client 访问到 IPvs 服务,将流量分发到不同的 Pod 上运行。
Cluster IP( service 的暴露IP,提供内部负载均衡 )
clusterIP 主要在每个 node 节点使用 ipvs,将发向 Cluster IP对应端口的数据,转发到 Service-ipvs,ipvs通过调度算法将请求进行负载均衡,发送至后端 Pod节点。
1、先创建 Deployment 控制器 3个Nginx 应用
apiVersion: apps/v1
kind: Deployment #创建Deployment控制器
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3 #创建三个副本
selector:
matchLabels:
app: myapp #副本标签
release: stabel #副本标签
template:
metadata:
labels:
app: myapp #副本标签
release: stabel #副本标签
env: test
spec:
containers:
- name: myapp
image: nginx:1.9.1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
kubectl apply -f nginx.yaml --record
kubectl get pod -o wide
2、为这三个 Nginx 应用创建 Service 暴露IP、Port
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
type: ClusterIP #Cluster IP
selector: #选择器
app: myapp #service匹配标签
release: stabel #service匹配标签
ports:
- name: http #匹配Deployment.spec.ports名称
port: 80 #暴露端口
targetPort: 80 #后端真是服务器端口
kubectl apply -f myapp-service.yaml
kubectl get svc
kubectl describe service myapp 查看集群虚拟IP 和 后端 Pod地址
访问这个 10.98.227.26 Cluster IP地址,轮询调度三个 nginx 副本的页面
Headless Service(DNS解析)
Headless Service 属于 Cluster IP的一种,Pod 通过 service_name 方式直接解析到后端 Pod IP。
有时不需要或者不想要负载均衡的 Service,遇到这种情况,可以通过指定 Cluster IP的值为 None,来创建 Headless Service。这类Service 并不会分配 ClusterIP,kube-proxy 不会处理他们,而且平台也不会为他们进行负载均衡和路由。
apiVersion: v1
kind: Service
metadata:
name: myapp-headless
namespace: default
labels:
app: myapp
spec:
selector:
app: myapp
clusterIP: "None"
ports:
- protocol: TCP
port: 80
targetPort: 80
1、查看 headless service详细信息
kubectl describe service myapp-headless
2、解析 该 headless 域名
nslookup myapp-headless.default.svc.cluster.local 10.244.0.2
10.244.0.2 是集群的DNS解析地址
NodePort (将内部暴露外部)
nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由kube-proxy 进一步给到对应的 Pod。
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: default
spec:
type: NodePort #NodePort
selector: #选择器
app: myapp #service匹配标签
release: stabel #service匹配标签
ports:
- name: http #匹配Deployment.spec.ports名称
port: 80 #暴露端口
targetPort: 80 #后端真是服务器端口
kubectl get svc
查看 NodePort IP地址
kubectl describe svc myapp-nodeport
查看详细 svc 后端 Pod 节点IP地址
LoadBalancer(从内部暴露外部)
loadBalancer 和 nodePort 其实是同一种方法。区别在于 loadBalancer 比 nodePort 多了一步,就是可以调用 cloud provider 去创建 LB 来向节点导流。
每一个 Node 节点同样会暴露 一个 NodePort,只不过在外网存在一个 LB 供应商的调度层。
客户端访问的是 LB 供应商的 IP & PORT ,由 LB 提供负载均衡。
ExternalName (将外部流量引入集群内部)
对外部服务设定别名,通过别名直接访问
这种类型的 Service 通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如自定义域名:hub.shmguigu.com) 引入外部服务到内部流量。
ExternalName service 是 Service 的特例,它没有selector,也没有定义任何的端口和 Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。
Kind: Service
apiVersion: v1
metadata:
name: my-service-1
namespace: default
spec:
type: ExternalName
externalName: hub.shmguigu.com
kubectl get svc
my-service-1 ExternalName <none> hub.shmguigu.com <none> 9s