一、service简介
- 个人理解:service类似于一个前端代理,所有的访问通过代理分发,无论后端怎么变化,用户的访问方式始终保持不变
- service是一种为一组功能相同的pod提供单一不变的接入点的资源(如何保证service的高可用?service本身是否会成为瓶颈?)
- service也通过标签选择器来选择对应的pod
- service可以将特定客户端的请求每次都指向同一个pod(使用次属性需要考虑负载均衡的影响)
- service工作在TCP与UDP层,因此无法基于cookie来绑定pod
- service的服务发现:
1)所有的service都以环境变量的形式存放在pod中,pod通过环境变量获取service的IP和端口
2)DNS发现服务:
a、k8s自身在kubesystem命名空间有运行dns服务
b、其他所有在同一集群的pod都配置成使用该dns(k8s通过修改每个容器的/etc/resolv.conf文件实现)
c、pod是否使用dns由pod中sepcd dnsPolicy属性决定
d、客户端pod在知道service的名称的情况下可以通过FQDN(全局限定域名)访问
访问格式:web-test.default.svc.cluster.local #service名称.命名空间名称.集群本地服务名称中使用的可配置的集群域后缀
在同一namespace的pod可以省略集群域后缀及命名空间,即只需要service_name
e、端口号依旧使用环境变量获取 - service的IP是无法ping的,因为service的clusterIP只是一个虚拟的IP,只有与service的port结合使用时才有意义
- 通过service访问服务无法记录客户端IP,由于node对数据包执行了SNAT(源网络地址转换),因此数据包的源IP会发生改变
二、endpoint(kubectl get svc svc_name #可以查看到endpoint)
- Endpoint就是暴露一个服务的IP地址和端口的列表
- service的标签选择器是用与构建endpoint的IP、端口列表,然后存入endpoint资源中
- 手动创建endpoint(用于给没有标签选择器的service创建endpoint)
- 手动创建的endpoint需要与对应的service具有相同的名称,并包含该服务的目标IP和端口列表
- 创建完整的service后删除seletor选择器,service将不会自动更新endpoint列表,可以人为控制endpoint
三、使用service链接外部服务
- 使用endpoint写入外部服务器的IP和端口链接外部服务(默认服务发现只能链接集群内部的服务)
- 创建ExternalName类型的服务,通过externalname属性和ports属性指定外部服务器的IP和端口
- 通过service访问外部服务可以直接链接外部服务,隐藏了外部服务的名称、端口等信息
四、将服务暴露给外部客户端
- 创建NodePort类型的service:每个节0点都会打开一个相同的随机端口,用于将流量重定向到节点上的pod,外部通过node_ip:port访问(缺点:pod更换node节点会改变访问方式,或弄得节点故障从而导致服务不可访问)
- 创建LoadBalancer类型的service:通过一个专用的负载均衡器访问,客户端通过负载均衡器的IP连接到服务
(云服务商的k8s集群通常支撑从云基础架构自动提供负载均衡器,用户仅需将类型修改为LoadBalance模式即可,之后根据查看到的负载均衡IP访问服务)
实现需要负载均衡器+独有的公网IP - 创建一个Ingress资源,通过一个IP地址公布多个service
1、Ingress需要一个公网IP
2、Ingress根据请求的主机名和路劲决定请求转发的服务
3、Ingress在网络栈(HTTP)的应用层操作,可以实现基于cookie的回话亲和性
4、只有Ingress控制器在集群中运行,Ingress资源才能正常工作
5、云供应商的Ingress控制器(例如:GKE)要求Ingress指向一个NodePort服务
6、ingress工作原理:客户端——》DNS——》返回ingress_IP——》客户端发出HTTP请求,并在Host头中指定域名——》控制器通过域名确定客户端访问的服务——》通过该服务的Endpoint查看pod IP——》并将客户端的请求转发给其中一个pod(通常情况ingress只通过service选择pod,而不是转发给service)
7、一个Ingress可以暴露多个服务:通过不同的域名指向不同的service,因此在实际应用场景中,需要将Ingress用到的域名在Ingress所在的node上全部解析 - 小结:
1)Ingress决定访问的service(选择需要访问的服务)
2)service选择响应用户请求的pod
3)创建ingress的pod时注意使用replicas机制,(使用DNS解析到多个对应的Ingress节点,以免当pod或node故障时,通过ingress的访问全部失效:仅个人理解)
二、service的yaml示例
apiVersion: v1
kind: Service
metadata:
name: svc-test
spec:
#type: ExternalName
#externalname: www.example.com #在externalname模式是的属性,指定外部服务器的FQDN,同时也需要指定ports属性
sessionAffinity: ClientIp #次属性用于使同一客户端的请求每次都指向同一个pod(有none和client两中选择,默认为none)
externalTrafficPolicy: local #负载均衡器——》service——》node——》pod(选择了node的时候可能响应的pod不在该node上(默认随机),此选即开启:接受到请求的node直接使用本地的pod直接响应;缺点,若此node上无pod响应,则该请求将被直接挂起,且node上的pod数量不一致的情况下,可能导致pod的负载不均衡
selector:
app: web
ports:
- name: http #映射多个端口时需要指定name属性,只需要映射一个端口时可以省略
port: 8080 #映射的端口
targetPort: 80 #pod端口
#nodePort: 30080 #节点端口,使用nodeport模式时可以指定的属性(不指定则自动生成随机端口)
- name: http
port: 8443
targetPort: 443 #pod端口在pod的yaml文件中也定义有name属性,此处可以直接引用,这样即使pod的端口发生变化,此处也无需修改
Ingress的yaml文件
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-test
spec:
tls: #使用HTTPS方式访问,将证书创建为secret资源使用
- hosts:
- test.example.com #使用HTTPS访问的域名
secretName: tls-secret #创建的secret名称
rules:
- host: test.example.com #对外暴露的域名
http:
paths:
- path: /web1 #访问的文件路径
backend:
service:Name: test-svc #service的名称
servicePort: 80 #service的端口
http:
paths:
- path: /web2 #在同一host下的不同路径
backend:
service:Name: test-svc2
servicePort: 80
- host: test2.example.com
http:
paths:
- path: /web1
backend:
service:Name: test2-svc
servicePort: 80