Service
介绍:
实现方式:
1. userspace: 用户空间
用户的请求到达对应节点之上的iptables or ipvs规则(Service的规则),由Service先将他转为本地监听在某个套接字上的用户空间的kube-proxy进行处理,处理完成后再转给Service IP,最终代理至后端Pod.
2. iptables: 直接调度
用户请求到达iptables后直接进行调度,无需进入用户空间处理;
3. ipvs: 直接调度
用ipvs进行调度,与iptables类似
kube-proxy
始终监视着master上的api server服务中有关Service的变动信息;
api server上有关Service对象的变动比如创建、删除,kube-proxy都要将其转化为当前节点上能够实现将用户请求调度到后端特定Pod资源之上的规则(iptables or ipvs)取决于Service实现方式
通过YAML文件创建Service:
1. 类型介绍
# 可手动指定Service的虚拟IP地址
svc.spec.clusterIP <string>
# 标签选择器,用于关联后端的Pod
svc.spec.selector <map[string]string>
# 关联后端Pod的端口
svc.spec.ports <[]Object>
# service的类型(ExternalName, ClusterIP, NodePort, LoadBalancer)
svc.spec.type <string>
ClusterIP: 默认为此类型,仅用于集群内通信
NodePort: 接入机器外部的流量,客户端直接通过节点的IP+NodePort暴露出来的端口就可访问
LoadBalancer: 比如在云环境上搭建了K8S集群(阿里云、AWS云),使用此种类型的Service会自动创建负载均衡器(阿里云的SLB)
ExternalName: 需要被kube-dns能够解析,用于将Service关联至外围服务以供Pod访问,外围服务将处理结果转交个Node,Node再返回给Service,Service再返回给Pod client,从而让Pod访问外围的服务(集群内不存在的服务)
资源记录格式(CoreDns):
SVC_NAME.NS_NAME.DOMAIN.LTD.
svc.cluster.local.
redis.default.svc.cluster.local.
2.创建ClusterIP类型的Service.
$ vim svc-demo.yaml apiVersion: v1 kind: Service metadata: name: redis namespace: default spec: clusterIP: 10.97.97.97 type: ClusterIP selector: app: redis role: logstor ports: - name: redis port: 6479 targetPort: 6379 protocol: TCP $ kubectl apply -f svc-demo.yaml
$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE redis ClusterIP 10.97.97.97 <none> 6379/TCP 2m52s # 后端的Pod是之前创建的一个redis $ kubectl describe svc redis Name: redis Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","... Selector: app=redis,role=logstor Type: ClusterIP IP: 10.97.97.97 Port: redis 6379/TCP TargetPort: 6379/TCP Endpoints: 10.244.1.63:6379 Session Affinity: None Events: <none> # 下列的Pod是之前搞Deployment的时候创建的,现在要把这些发布出去. $ kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS deploy-demo-f5dfc4cf4-cb58r 1/1 Running 1 20h app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-mm27c 1/1 Running 1 20h app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-p7zvp 1/1 Running 1 20h app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-rbqnh 1/1 Running 1 20h app=myapp,pod-template-hash=f5dfc4cf4,release=canary deploy-demo-f5dfc4cf4-wz8tr 1/1 Running 1 20h app=myapp,pod-template-hash=f5dfc4cf4,release=canary
3.创建NodePort类型的Service.
$ vim svc-np-demo.yaml apiVersion: v1 kind: Service metadata: name: redis namespace: default spec: type: NodePort selector: app: myapp release: canary ports: - name: myapp-port nodePort: 30001 port: 80 targetPort: 80 $ kubectl apply -f svc-np-demo.yaml $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 14d myapp NodePort 10.97.65.55 <none> 80:30001/TCP 61s redis ClusterIP 10.97.97.97 <none> 6379/TCP 20m $ kubectl describe svc myapp Name: myapp Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"name":"myapp-por... Selector: app=myapp,release=canary Type: NodePort IP: 10.97.65.55 Port: myapp-port 80/TCP TargetPort: 80/TCP NodePort: myapp-port 30001/TCP Endpoints: 10.244.1.64:80,10.244.1.65:80,10.244.1.66:80 + 2 more... Session Affinity: None External Traffic Policy: Cluster Events: <none> # 集群外部机器一直访问此Service,会发现返回的结果中包含所有Pod. $ while true;do curl http://192.168.222.100:30001/hostname.html;sleep 1; done deploy-demo-f5dfc4cf4-wz8tr deploy-demo-f5dfc4cf4-p7zvp deploy-demo-f5dfc4cf4-p7zvp deploy-demo-f5dfc4cf4-cb58r deploy-demo-f5dfc4cf4-wz8tr deploy-demo-f5dfc4cf4-cb58r deploy-demo-f5dfc4cf4-rbqnh deploy-demo-f5dfc4cf4-rbqnh deploy-demo-f5dfc4cf4-wz8tr deploy-demo-f5dfc4cf4-rbqnh deploy-demo-f5dfc4cf4-p7zvp deploy-demo-f5dfc4cf4-rbqnh deploy-demo-f5dfc4cf4-cb58r .....
小功能:如果启用下面这个功能的话那么来自同一客户端的请求始终发送给第一次接收请求的Pod
svc.spec.sessionAffinity <string>
string:
ClientIP
None(默认值)
# 打补丁更新配置,也可以使用"kubectl edit -f xxx"或直接vim文件,随后使用"kubectl apply -f xxx"也可以.
$ kubectl patch svc myapp -p '{"spec":{"sessionAffinity":{"ClientIP"}}}' # 再次查看,会发现多了"**"那一行. $ kubectl describe svc myapp Name: myapp Namespace: default Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"ports":[{"name":"myapp-por... Selector: app=myapp,release=canary Type: NodePort IP: 10.97.65.55 Port: myapp-port 80/TCP TargetPort: 80/TCP NodePort: myapp-port 30001/TCP Endpoints: 10.244.1.64:80,10.244.1.65:80,10.244.1.66:80 + 2 more... ** Session Affinity: ClientIP External Traffic Policy: Cluster Events: <none> # 而且客户端访问这个Service的结果永远都是一样的
4. headless Service(无头Service)
说明:
之前的Service的工作过程我想大家应该都知道,当客户端访问Service的时候,实际是会有kube-dns进行解析Service的名称,将名称解析为ClusterIP,随后根据算法调度后端Pod以便响应客户端请求,这个headless Service无需配置ClusterIP
要设为"None",那么当客户端请求过来的时候会将Service Name直接解析为后端Pod的地址以便提供响应.
4.1 使用YAML文件创建的方法
$ vim myapp-svc-headless.yaml apiVersion: v1 kind: Service metadata: name: myapp-headless namespace: default spec: clusterIP: None type: ClusterIP selector: app: myapp release: canary ports: - port: 80 targetPort: 80 $ kubectl apply -f myapp-svc-headless.yaml # 会发现"**"标记的那一行中的ClusterIP为None,不用慌,这是正常现象. $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 15d myapp NodePort 10.97.65.55 <none> 80:30001/TCP 160m ** myapp-headless ClusterIP None <none> 80/TCP 15m redis ClusterIP 10.97.97.97 <none> 6379/TCP 179m # 随后我们手动解析这个没有ClusterIP的Service,查看结果(answer上边的和下边的省略了),发现解析结果为后端的所有Pod的地址. $ dig -t A myapp-headless.default.svc.cluster.local @10.96.0.10 ..... ;; ANSWER SECTION: myapp-headless.default.svc.cluster.local. 30 IN A 10.244.1.64 myapp-headless.default.svc.cluster.local. 30 IN A 10.244.1.66 myapp-headless.default.svc.cluster.local. 30 IN A 10.244.1.65 myapp-headless.default.svc.cluster.local. 30 IN A 10.244.2.67 myapp-headless.default.svc.cluster.local. 30 IN A 10.244.2.68 ......