文章目录- Service 定义
- 负载分发策略
- 无头 service
- 参考文献
Service 定义
Service 用于为一组提供服务的 Pod 抽象一个稳定的网络访问地址。通过 Service 的定义,能够为客户端应用提供稳定的访问地址和负载均衡功能,以及屏蔽后端 Endpoint 的变化,是 kubernetes 实现微服务的核心资源。
name | type | required | backup |
---|---|---|---|
version | string | 1 | |
kind | string | 1 | Service |
metadate | object | 1 | |
m.name | string | 1 | Service 名称,可配置用于访问 |
m.namespace | string | 1 | 和上面那个,详见我的 CoreDNS 博文 |
m.labels[] | list | ||
m.annotation | list | ||
spec | object | 1 | 详细数据 |
s.selector[] | list | 1 | 将选择具有指定 label 标签的 Pod 作为管理范围 |
s.type | string | 1 | Service 的类型,指定 Service 的访问方式。默认值为 ClusterIP。见下方注释1 |
s.clusterIP | string | 当 service.type == ClusterIP 时,用以配置对应 IP;如果不指定,将由系统自动生成;如果是无头 Service,将此项设置为 None。Headless Service 后文再说。 | |
s.sessionAffinity | string | 是否支持 Session。可选值为 ClientIP,默认值为 None。ClientIP 表示将同一个客户端IP来的访问请求全都转发到同一个后端 Pod、 | |
s.ports[] | list | Service 端口列表 | |
s.p.name | string | 端口名称 | |
s.p.protocol | string | 端口协议,支持 TCP/UDP,默认是 TCP | |
s.p.port | int | 服务监听的端口号 | |
s.p.targetPort | int | 需要转发到后端 Pod 的端口号 | |
s.p.nodePort | int | 当 spec.type == NodePort 时,指定映射到宿主机的端口号 | |
status | object | 当 spec.type == LoadBalancer 时,设置外部负载均衡器的地址 | |
status.loadBalancer | object | 外部负载均衡器 | |
status.l.ingress | object | 外部负载均衡器 | |
status.l.i.ip | string | ||
status.l.i.hostname | string |
注1:
- spec.type Service 的类型,指定 Service 的访问方式,默认值为 ClusterIP。 (1)ClusterIP:虚拟服务 IP 地址,该地址用于 kubernetes 集群内部的 Pod 访问,在 Node 上 kube-proxy 通过设置的 iptables 规则进行转发。 (2)NodePort:使用宿主机的端口,使能够访问各 Node 的外部客户端通过 Node 的 IP 地址和端口号就能访问服务。 (3)LoadBalance:使用外接负载均衡器完成到服务的负载均衡分发,需要在 spec.status.loadBalance 字段指定外部负载均衡器的地址。
注2:这个 targetPort,可以直接用 pod 中的 ports.name,这一点让我有点迷惑,有个问题亟待求证: (1)如果两个 Pod 有同样的 ports.name,但是却对应着不同的 ContainerPort 呢,会怎么样?
负载分发策略
对Service的访问被分发到了后端的Pod上去,目前kubernetes提供了两种负载分发策略:
如果不定义,默认使用kube-proxy的策略,比如随机、轮询等。
基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个Pod上,这对于传统基于Session的认证项目来说很友好,此模式可以在spec中添加sessionAffinity: ClusterIP选项。
我们来做个实验:1、创建三个 pod:
代码语言:javascript复制apiVersion: apps/v1
kind: Deployment
metadata:
name: pc-deployment
namespace: dev
spec:
replicas: 3
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
2、查看创建结果
代码语言:javascript复制[root@k8s-master wlf]# kubectl get pods -n w -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
pc-deployment-6696798b78-2jpf4 1/1 Running 0 2m50s 10.244.102.155 localhost.localdomain <none> <none> app=nginx-pod,pod-template-hash=6696798b78
pc-deployment-6696798b78-lggkb 1/1 Running 0 2m50s 10.244.102.156 localhost.localdomain <none> <none> app=nginx-pod,pod-template-hash=6696798b78
pc-deployment-6696798b78-vsxj8 1/1 Running 0 2m50s 10.244.102.154 localhost.localdomain <none> <none> app=nginx-pod,pod-template-hash=6696798b78
3、为了方便后面的测试,修改下三台nginx的index.html页面。
代码语言:javascript复制kubectl exec -it pc-deployment-6696798b78-2jpf4 -n w /bin/sh
echo "10.244.102.155" > /usr/share/nginx/html/index.html
4、测试一下是否写入成功
代码语言:javascript复制[root@k8s-master wlf]# curl 10.244.102.154
10.244.102.154
5、创建集群负载服务:
代码语言:javascript复制apiVersion: v1
kind: Service
metadata:
name: service-clusterip
namespace: w
spec:
selector:
app: nginx-pod
clusterIP: 10.97.97.97 # service的ip地址,如果不写,默认会生成一个
type: ClusterIP
ports:
- port: 80 # Service端口
targetPort: 80 # pod端口
6、 查看service的详细信息
代码语言:javascript复制# 在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口[root@k8s-master wlf]# kubectl describe svc service-clusterip -n w
Name: service-clusterip
Namespace: w
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP: 10.97.97.97
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.102.154:80,10.244.102.155:80,10.244.102.156:80
Session Affinity: None
Events: <none>
7、查看ipvs的映射规则【rr 轮询】
代码语言:javascript复制TCP 10.97.97.97:80 rr
-> 10.244.102.154:80 Masq 1 0 0
-> 10.244.102.155:80 Masq 1 0 0
-> 10.244.102.156:80 Masq 1 0 0
8、默认访问测试
是轮询吧。
9、修改分发策略
代码语言:javascript复制apiVersion: v1
kind: Service
metadata:
name: service-clusterip
namespace: dev
spec:
selector:
app: nginx-pod
clusterIP: 10.97.97.97 # service的IP地址,如果不写,默认会生成一个
type: ClusterIP
sessionAffinity: ClientIP # 修改分发策略为基于客户端地址的会话保持模式
ports:
- port: 80 # Service的端口
targetPort: 80 # Pod的端口
10、再测试
无头 service
开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略,针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP,如果想要访问service,只能通过service的域名进行查询。
创建一个无头service:
apiVersion: v1 kind: Service metadata: name: service-headliness namespace: dev spec: selector: app: nginx-pod clusterIP: None # 将clusterIP设置为None,即可创建headliness Service type: ClusterIP ports:
- port: 80 targetPort: 80 进入pod 中:
kubectl exec -it pc-deployment-6696798b78-2jpf4 -n w bash root@pc-deployment-6696798b78-2jpf4:/# cat /etc/resolv.conf nameserver 10.96.0.10 search w.svc.cluster.local svc.cluster.local cluster.local localdomain options ndots:5 通过Service的域名进行查询:
dig @10.96.0.10 service-headliness.w.svc.cluster.local
service-headliness.w.svc.cluster.local.30 IN A10.244.102.155 service-headliness.w.svc.cluster.local.30 IN A10.244.102.154 service-headliness.w.svc.cluster.local.30 IN A10.244.102.156
参考文献
https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/