Kubernetes基本概念的学习-Service
1、Service存在的意义
Service引入主要是解决Pod的动态变化,提供统一的访问入口:
防止Pod失联,准备找到提供同一个服务的Pod(服务发现)
定义一组Pod的访问策略(负载均衡)
Service可以简单的理解为逻辑上的一组Pod,一种可以访问Pod的策略,而且其他Pod可以通过这个Service访问到这个Service代理的Pod,相对于Pod而言,它会有一个固定的名称,一旦创建就固定不变。
Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行 滚动升级)。 每个 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?答案是:Service。
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector实现的。
service是用于一组pod的负载均衡和服务发现的,比如后端有6个跑着应用程序的pod,使用service就能实现对这6个pod的负载均衡分发客户端请求了,如果pod扩容了,那么service就会自动发现pod并把它加入自己的后端请求endpoint列表中。
2、Pod与Service的关联
Service通过标签关联一组Pod;
Service为一组Pod:
selector 关联pod的标签
3、Service的创建
首先创建pod的yaml
apiVersion: apps/v1 kind: Deployment metadata: name: web2 spec: replicas: 3 selector: matchLabels: app: nginx2 template: metadata: labels: app: nginx2 spec: containers: - name: nginx image: nginx:1.17
创建pod
[root@master01 ~]# kubectl apply -f deployment.yaml
可以查看pod的标签
[root@master01 ~]# kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS web2-7b57499dd7-g5zlx 1/1 Running 0 12m app=nginx2,pod-template-hash=7b57499dd7 web2-7b57499dd7-pqgbm 1/1 Running 0 12m app=nginx2,pod-template-hash=7b57499dd7 web2-7b57499dd7-s2wjg 1/1 Running 0 12m app=nginx2,pod-template-hash=7b57499
下面可以创建service的yaml,其中selector下app后面的nginx2就是要负载的pod的标签
apiVersion: v1 kind: Service metadata: name: web2 spec: selector: app: nginx2 ports: - protocol: TCP port: 80 #Service自己的端口 targetPort: 80 #要暴露的端口 type: NodePort
创建service
[root@master01 ~]# kubectl apply -f service.yaml
查看创建的service
[root@master01 ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 10d web2 NodePort 10.1.114.168 <none> 80:31917/TCP 10s
查看service关联的ip
[root@master01 ~]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.4.91:6443 10d web2 10.244.205.227:80,10.244.205.228:80,10.244.75.102:80 2m47s
4、Service类型——ClusterIP
默认类型是ClusterIP。默认,分配一个稳定的IP地址,即VIP,只能在集群内部访问。
[root@master01 ~]# kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 11d web ClusterIP 10.1.164.147 <none> 80/TCP 6s
在node节点可以访问ClusterIP的地址:
[root@work02 ~]# curl 10.1.164.147:80 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif;
5、Service类型-NodePort
在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部进群IP地址。
访问地址:<任意NodeIP>:<NodePort>
端口默认范围:30000-32767
apiVersion: v1 kind: Service metadata: name: web spec: selector: app: web ports: - protocol: TCP port: 80 targetPort: 80 type: NodePort
6、Service类型-LoadBalancer
LoadBalancer:与NodePort类似,在每个节点启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台(华为云、腾讯云)上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。
service类型总结:
ClusterIP:在集群内部使用,也是默认值
ExternalName:通过返回定义的CNAME别名
NodePort:在所有安装了kube-proxy的节点上打开一个端口,此端口可以代理至后端的Pod,然后集群外部可以使用节点的IP地址和NodePort的端口号访问到集群的Pod服务。NodePort端口的默认范围是30000-32768
LoadBalance:使用云平台的
7、Service的网络代理模式
iptables
ipvs
8、继续编写一个Service
apiVersion: v1 kind: Service metadata: name: redis namespace: default spec: selector: app: myapp release: canary clusterIP: 10.96.96.96 type: ClusterIP ports: - port: 8080 #访问Service的端口 targetPort: 80 #代理Pod的端口
9、无头Service
apiVersion: v1 kind: Service metadata: name: headless-service namespace: default spec: selector: app: myapp release: canary clusterIP: None type: ClusterIP ports: - port: 8080 targetPort: 80
无头service就是在定义service时指定 service.spec.clusterIP:None
,即没有clusterip,这就是headless service,简称无头service。
无头service也有标签选择器,有标签选择器就说明有对应的endpoint。
平时的应用一般有这样2种情况,多个应用实例之间没有区别,比如最常见的nginx反向代理到后端服务器的多个应用上,这些后端应用是没有说明区别的。但是这样情况呢,比如Redis集群,每个Redis节点都是不同的,它们之间相互通行并组成一个集群,这时我们使用普通的service向nginx那样反向代理到多个后端应用就显得不合适了。
使用无头service。如要搭建6个节点的redis集群(3主3从架构),我们定义service并不是说要让service将请求连接负载均衡分发到这6个pod,因为这6个pod的实例都是不同的,他们都跑着不同的应用。这时无头service就派上用场的,无头service没有clusterip,直接绑定具体的Pod的IP,无头service经常用于statefulset的有状态部署。
同时创建所谓的 headless service 资源, 这个 headless service 不分配 ClusterIP, 因为根本不会用到. 集群内的节点是通过Pod名称+序号.Service名称
确定彼此进行通信的, 只要序号不变, 访问就不会出错.
headless service
不具有普通Service资源的负载均衡能力, 因为没有ClusterIP
, 所以kube-proxy
组件不处理此类服务, 在访问此类服务的时候返回的是所有后端Pod的Endpoints列表.
访问一个普通的Service
, kube-proxy会将请求重定向到后端的某个Pod
, 多次请求虽然发送到的后端可能不同, 但是前端是无感知的, 因为Service本身有固定IP.
但是访问一个headless service
, 其实是随机且直接访问到后端Pod
, 比如多次ping redis-service
, 你会发现解析出来的地址是不同的, 而这些地址都是Pod的地址.
10、Service的三种代理模式
- userspace 代理模式(K8S 1.1之前版本)
- iptables 代理模式(K8S 1.10之前版本)
- ipvs 代理模式(K8S 1.11 之后版本,激活ipvs需要修改配置);让kubelet所在的主机,启动时装入以下几个模块:ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv4