一个例子:
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
ports:
-protocol: TCP
port:8080 //监听端口
targetPort: 8080 //转发到pod的端口
selector:
app: webapp
创建这个Service后,查看系统为其分配的ClusterIP
kubectl creat -f webapp-service.yaml
kubectl get svc
输出
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
webapp ClusterIP 169.169.140.229 8080/TCP
这个Service会监听访问169.169.140.229:8080端口的请求,然后把这些请求发送到集群中拥有label:app=webapp的pod的8080端口上,这样使用者就可以不管pod由于新建或销毁导致的podip变化,直接访问serviceip就可以访问服务
当一个Service对象在Kubernetes集群中被定义出来时,集群内的客户端应用就可以通过服务IP访问到具体的Pod容器提供的服务了。从服务IP到后端Pod的负载均衡机制,则是由每个Node上的kube-proxy负责实现的。
目前kube-proxy提供了以下代理模式(通过启动参数–proxy-mode 设置)。
◎ userspace模式:用户空间模式,由kube-proxy完成代理的实现,效率最低,不再推荐使用。
◎ iptables模式:kube-proxy通过设置Linux Kernel的iptables规则,实现从Service到后端Endpoint列表的负载分发规则,效率很高。但是,如果某个后端Endpoint在转发时不可用,此次客户端请求就会得到失败的响应,相对于userspace模式来说更不可靠。此时应该通过为Pod设置readinessprobe(服务可用性健康检查)来保证只有达到 ready状态的Endpoint才会被设置为Service的后端Endpoint。
◎ ipvs模式:在Kubernetes 1.11版本中达到Stable阶段,kubeproxy通过设置Linux Kernel的netlink接口设置IPVS规则,转发效率和支持的吞吐率都是最高的。ipvs模式要求Linux Kernel启用IPVS模块,如果操作系统未启用IPVS内核模块,kube-proxy则会自动切换至 iptables模式。
Service支持通过设置sessionAffinity实现基于客户端IP的会话保持机制,即首次将某个客户端来源IP发起的请求转发到后端的某个Pod 上,之后从相同的客户端IP发起的请求都将被转发到相同的后端Pod
通过设置service.spec.sessionAffinity就可以了
*******************
kind: Service
metadata:
name: webapp
spec:
sessionAffinity: ClientIP
*******************
*******************
也可以设置会话保持的最长时间
下面的服务将会话保持时间设置为 10800s(3h)
*******************
kind: Service
metadata:
name: webapp
spec:
sessionAffinity: ClientIP
sessionAffinityConfig:
lcientIP:
timeoutSeconds: 10800
*******************
*******************
普通的Service通过Label Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint不是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为 Kubernetes内的一个Service,供集群内的其他应用访问
对于这种应用场景,用户在创建Service资源对象时不设置Label Selector(后端Pod也不存在),同时再定义一个与Service关联的 Endpoint资源对象,在Endpoint中设置外部服务的IP地址和端口号,例如:
apiVersion: v1
kind: Service
metadata:
name: my_service
sepc:
ports:
-portocol: TCP
port: 80
targetPort: 80
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
-addresses:
-IP: 1.2.3.4
ports:
-port: 80
访问没有标签选择器的Service和带有标签选择器的Service一样,请求将被路由到由用户自定义的后端Endpoint上
Kubernetes为Service创建的ClusterIP地址是对后端Pod列表的一层抽象,对于集群外部来说并没有意义,但有许多Service是需要对集群外部提供服务的,Kubernetes提供了多种机制将Service暴露出去,供集群外部的客户端访问。这可以通过Service资源对象的类型字段“type”进行设置。
目前Service的类型如下
◎ ClusterIP:Kubernetes默认会自动设置Service的虚拟IP地址,仅可被集群内部的客户端应用访问。当然,用户也可手工指定一个 ClusterIP地址,不过需要确保该IP在Kubernetes集群设置的ClusterIP地址范围内(通过kube-apiserver服务的启动参数–service-cluster-ip-range 设置),并且没有被其他Service使用。
◎ NodePort:将Service的端口号映射到每个Node的一个端口号上,这样集群中的任意Node都可以作为Service的访问入口地址,即
NodeIP:NodePort。
◎ LoadBalancer:将Service映射到一个已存在的负载均衡器的IP 地址上,通常在公有云环境中使用。
◎ ExternalName:将Service映射为一个外部域名地址,通过 externalName字段进行设置。
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: NodePort
ports:
-port: 8080
targetPort: 8080
nodePort: 8081
selector:
app: webapp
然后就可以通过任意一个Node的IP地址和NodePort 8081端口号访问服务了
通常在公有云环境中设置Service的类型为“LoadBalancer”,可以将 Service映射到公有云提供的某个负载均衡器的IP地址上,客户端通过负载均衡器的IP和Service的端口号就可以访问到具体的服务
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: LoadBalancer
ports:
-portocol: TCP
port: 80
targetPort: 8080
selector:
app: MyApp
在服务创建成功之后,云服务商会在Service的定义中补充LoadBalancer的IP地址
ExternalName类型的服务用于将集群外的服务定义为Kubernetes的集群的Service,并且通过externalName字段指定外部服务的地址,可以使用域名或IP格式。集群内的客户端应用通过访问这个Service就能访问外部服务了。这种类型的Service没有后端Pod,所以无须设置Label Selector
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.daabase.example.com