环境准备
在使用 service 之前,首先利用 Deployment 创建出 3 个 pod,注意要为 pod 设置 app=nginx-pod
的标签
创建deployment.yaml,内容如下
apiVersion: apps/v1 kind: Deployment # 类型为 deployment metadata: name: pc-deployment # deployment 的名称 namespace: zouzou spec: replicas: 3 # 三个副本 selector: # 标签选择器 matchLabels: app: nginx-pod template: metadata: labels: # 标签 app: nginx-pod spec: containers: - name: nginx image: nginx:1.14 ports: # 暴露容器的 80 端口 - containerPort: 80
创建 deployment
[root@dce-10-6-215-215 tmp]# kubectl create -f deployment.yaml deployment.apps/pc-deployment created
查看 pod 的详情
[root@dce-10-6-215-215 tmp]# kubectl get pod -n zouzou -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx3-c5d7c9466-vnt9c 1/1 Running 0 24h 172.29.34.135 dce-10-6-215-200 <none> <none> pc-deployment-5bff7844cb-6n65j 1/1 Running 0 51s 172.29.190.159 dce-10-6-215-190 <none> <none> pc-deployment-5bff7844cb-vnvhs 1/1 Running 0 51s 172.29.34.223 dce-10-6-215-200 <none> <none> pc-deployment-5bff7844cb-z5ks7 1/1 Running 0 51s 172.29.34.255 dce-10-6-215-200 <none> <none>
为了方便后面的测试,修改下三台 pod 里 nginx 的 index.html 页面
# 使用下面命令依次更改,注意要换成自己的 pod 名称 kubectl exec -it pc-deployment-5bff7844cb-vnvhs -n zouzou /bin/sh echo "我是 172.29.34.223 的 pod" > /usr/share/nginx/html/index.html
修改完成之后,我们测试一下,看有没有修改成功
ClusterIP 类型的 Service
默认的 Service 类型就是 ClusterIP,它只能在集群内部访问
创建 service-clusterip.yaml 文件
apiVersion: v1 kind: Service # 类型为 Service metadata: name: service-clusterip # Service 的名称 namespace: zouzou spec: selector: # 标签选择器,会和上面创建的 deployment.yaml 的 pod 关联起来 app: nginx-pod clusterIP: 172.31.88.88 # service 的 ip 地址,如果不写,默认会生成一个,注意这个地址不能写,有个范围的,我的是 172.31.0.0/16 type: ClusterIP # 类型为 Service 的 ClusterIP ports: - port: 8080 # Service 端口,自定义 targetPort: 80 # pod 端口,不写默认是 80
注意:上面的 service-clusterip.yaml 只是创建一个 service,因为里面的选择器为 app:nginx-pod,所以会和 deployment.yaml 里的 pod 关联起来(因为 deployment.yaml 里的标签也是 app:nginx-pod)
创建 service
# 创建 service [root@dce-10-6-215-215 tmp]# kubectl create -f service-clusterip.yaml service/service-clusterip created
查看 service
# 可以看到 CLUSTER-IP 就是我们设置的 IP 地址,端口是我们写的 8080,svc 是 service 的简写 [root@dce-10-6-215-215 tmp]# kubectl get svc -n zouzou -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service-clusterip ClusterIP 172.31.88.88 <none> 8080/TCP 2m6s app=nginx-pod
查看 service 的详细信息,可以看到我们的 Selector 选择的是pod 的标签为 app=nginx-pod 的 pod。还有个参数是 Session Affinity(Session 亲和度),这里为 None,后面在说
还有一个很重要的是 Endpoints,里面有三个 ip 地址,意思就是这个 service 找到了三个 pod,当访问 service 的时候,会转发到这三个里面的其中一个上,其实这三个就是我们上面使用 deployment.yaml 创建的三个 pod
# 查看 service 的详细信息 [root@dce-10-6-215-215 tmp]# kubectl describe svc service-clusterip -n zouzou Name: service-clusterip Namespace: zouzou Labels: <none> Annotations: <none> Selector: app=nginx-pod Type: ClusterIP IP: 172.31.88.88 IPFamily: IPv4 Port: <unset> 8080/TCP TargetPort: 80/TCP Endpoints: 172.29.190.159:80,172.29.34.223:80,172.29.34.255:80 # Endpoints 列表,里面就是当前 service 可以负载到的服务入口 Session Affinity: None # session 亲和性 Events: <none>
查看 ipvs 的映射规则
我的有好多,这里找到 service 的 ip 对应的 ip。从下面可以看到,当我们访问 172.31.88.88:8080 的时候,会采用轮询的方式访问下面的三个 ip(也就是我们的 pod),rr 是轮询的意思
[root@dce-10-6-215-215 tmp]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 127.0.0.1:30001 rr -> 172.28.116.206:80 Masq 1 0 0 TCP 172.31.88.88:8080 rr # 主要看这个和下面的三个 -> 172.29.34.223:80 Masq 1 0 0 -> 172.29.34.255:80 Masq 1 0 0 -> 172.29.190.159:80 Masq 1 0 0 TCP 172.31.122.40:80 rr -> 172.28.116.205:80 Masq 1 0 0
循环访问下我们的 service 地址,看下是不是采用轮询的方式
从下面的结果可以看出来,确实是采用轮询的方式来访问了我们的 pod
使用域名进行访问
Service域名格式:$(service name).$(namespace).svc.cluster.local
,其中 cluster.local 为指定的集群的域名
例如上面的就可以写成
service-clusterip.zouzou.svc.cluster.local
Endpoints
Endpoint 是 kubernetes 中的一个资源对象,存储在 etcd 中,用来记录一个 service 对应的所有 pod 的访问地址,它是根据 service 配置文件中 selector 描述产生的。
一个 Service 由一组 Pod 组成,这些 Pod 通过 Endpoints 暴露出来,Endpoints 是实现实际服务的端点集合。换句话说,service 和 pod 之间的联系是通过 endpoints 实现的。
我们可以通过下面的命令查看 Endpoint
# 会返回所有的,因为我这里只有一个 service,所以只有一个 [root@dce-10-6-215-215 tmp]# kubectl get endpoints -n zouzou -o wide NAME ENDPOINTS AGE service-clusterip 172.29.190.159:80,172.29.34.223:80,172.29.34.255:80 20m
负载分发策略
对 Service 的访问被分发到了后端的 Pod 上去,目前 kubernetes 提供了两种负载分发策略:
- 如果不定义,默认使用 kube-proxy 的策略,比如随机、轮询
- 基于客户端地址的会话保持模式,即来自同一个客户端发起的所有请求都会转发到固定的一个 Pod 上
此模式可以使在 spec 中添加 sessionAffinity: ClientIP
选项
修改 service-clusterip.yaml ,加上 sessionAffinity: ClientIP
apiVersion: v1 kind: Service # 类型为 Service metadata: name: service-clusterip # Service 的名称 namespace: zouzou spec: sessionAffinity: ClientIP # 来自同一个客户端发起的所有请求都会转发到固定的一个 Pod 上 selector: # 标签选择器,会和上面创建的 deployment.yaml 的 pod 关联起来 app: nginx-pod clusterIP: 172.31.88.88 # service 的 ip 地址,如果不写,默认会生成一个 type: ClusterIP # 类型为 Service 的 ClusterIP ports: - port: 8080 # Service 端口,自定义 targetPort: 80 # pod 端口
在 apply 一下
# 也可以删除 service,在创建 [root@dce-10-6-215-215 tmp]# kubectl apply -f service-clusterip.yaml service/service-clusterip configured
在来查看下 ipvs 的映射规则,可以看到在我们的 service 后面加了个 persistent,表示持久的,即某一个客户端发起的请求都会分给一个 pod 上
[root@dce-10-6-215-215 tmp]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 127.0.0.1:30001 rr -> 172.28.116.206:80 Masq 1 0 0 TCP 172.31.88.88:8080 rr persistent 10800 -> 172.29.34.223:80 Masq 1 0 0 -> 172.29.34.255:80 Masq 1 0 0 -> 172.29.190.159:80 Masq 1 0 0 TCP 172.31.122.40:80 rr -> 172.28.116.205:80 Masq 1 0 0
在循环访问下 service,看能不能分给一个固定的 pod
[root@dce-10-6-215-215 tmp]# while true;do curl 172.31.88.88:8080; sleep 5; done; 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod 我是 172.29.34.223 的 pod
在用我们的 node 节点访问
[root@dce-10-6-215-200 ~]# while true;do curl 172.31.88.88:8080; sleep 5; done; 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod 我是 172.29.34.255 的 pod
从上面的结果可以看出,当我们设置了 sessionAffinity: ClientIP 后,当某个客户端访问 service 的时候,会将这个客户端的请求分给一个固定的 pod
删除 service
通过 yaml 文件删除
kubectl delete -f service-clusterip.yaml
通过 service 的名称删除
kubectl delete svc service-clusterip -n zouzou