Kubernetes之十一---service资源详解
1、认识service
1.1 为什么要使用service
Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行 滚动升级)。 每个 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?答案是:Service。
1.2 service介绍
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(下面我们会讲到我们为什么需要一个没有label selector的服务)实现的。
举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。 Service 定义的抽象能够解耦这种关联。
对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变更,应用程序就会被更新。 对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Pod。
1.3 三种代理模式
- userspace 代理模式(K8S 1.1之前版本)
- iptables 代理模式(K8S 1.10之前版本)
- ipvs 代理模式(K8S 1.11 之后版本,激活ipvs需要修改配置)
1.3.1 userspace 代理模式
这种模式,kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的backend Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个 backend Pod,是基于 Service 的 SessionAffinity 来确定的。 最后,它安装 iptables 规则,捕获到达该 Service 的 clusterIP(是虚拟 IP)和 Port 的请求,并重定向到代理端口,代理端口再代理请求到 backend Pod。
网络返回的结果是,任何到达 Service 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、Service、或 Pod 的任何信息。
默认的策略是,通过 round-robin 算法来选择 backend Pod。 实现基于客户端 IP 的会话亲和性,可以通过设置 service.spec.sessionAffinity 的值为 "ClientIP" (默认值为 "None")。
1.3.2 iptables 代理模式
这种模式,kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会安装 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。 对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod。
默认的策略是,随机选择一个 backend。 实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity 的值设置为 "ClientIP" (默认值为 "None")。
和 userspace 代理类似,网络返回的结果是,任何到达 Service 的 IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 Kubernetes、Service、或 Pod 的任何信息。 这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始选择的 Pod 没有响应,iptables 代理能够自动地重试另一个 Pod,所以它需要依赖 readiness probes。
1.3.3 ipvs代理模式
ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4层LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCP和UDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。
在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。 iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs 和 iptables 都是基于netfilter的, ipvs 模式和 iptables 模式之间的差异:
- ipvs 为大型集群提供了更好的可扩展性和性能
- ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
- ipvs 支持服务器健康检查和连接重试等功能
同时ipvs 也依赖 iptables,ipvs 会使用 iptables 进行包过滤、SNAT、masquared(伪装)。具体来说,ipvs 将使用ipset来存储需要DROP或masquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了
ipvs虽然在v1.1版本中已经支持,但是想要使用,还需激活ipvs:
① 修改配置文件
1
2
|
[root@master ~] # vim /etc/sysconfig/kubelet KUBE_PROXY=MODE=ipvs |
② 编写脚本,让kubelet所在的主机,启动时装入以下几个模块,由于前面部署的K8s集群是手动部署的,无法启用ipvs规则:
ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv4
在每个master和node节点上创建ipvs规则
#!/bin/bash ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs" for mod in $(ls $ipvs_mods_dir | grep -o "^[^.]*"); do /sbin/modinfo -F filename $mod &> /dev/null if [ $? -eq 0 ]; then /sbin/modprobe $mod fi done
2、修改文件权限,并手动为当前系统加载内核模块:
~]# chmod +x /etc/sysconfig/modules/ipvs.modules ~]# bash /etc/sysconfig/modules/ipvs.modules
3、修改ipvs规则:
[root@master ~]# kubectl edit cm kube-proxy -n kube-system apiVersion: v1 data: config.conf: |- apiVersion: kubeproxy.config.k8s.io/v1alpha1 bindAddress: 0.0.0.0 clientConnection: acceptContentTypes: "" burst: 0 contentType: "" kubeconfig: /var/lib/kube-proxy/kubeconfig.conf qps: 0 clusterCIDR: 10.224.0.0/16 configSyncPeriod: 0s conntrack: maxPerCore: null min: null tcpCloseWaitTimeout: null tcpEstablishedTimeout: null detectLocalMode: "" enableProfiling: false healthzBindAddress: "" hostnameOverride: "" iptables: masqueradeAll: false masqueradeBit: null minSyncPeriod: 0s syncPeriod: 0s ipvs: excludeCIDRs: null minSyncPeriod: 0s scheduler: "" strictARP: false syncPeriod: 0s tcpFinTimeout: 0s tcpTimeout: 0s udpTimeout: 0s kind: KubeProxyConfiguration metricsBindAddress: "" mode: "ipvs" # 只需要在第一次初始化k8s未支持的模块上加载ipvs即可
4、此时我们可以看到kube-proxy上没有重构新的pod,此时的kube-proxy还是运行了44h。
[root@master ~]# kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-546565776c-fl859 1/1 Running 20 44h coredns-546565776c-mwt5p 1/1 Running 18 44h etcd-master 1/1 Running 5 44h kube-apiserver-master 1/1 Running 7 44h kube-controller-manager-master 1/1 Running 5 44h kube-flannel-ds-amd64-rpdk6 1/1 Running 4 43h kube-flannel-ds-amd64-rsb4s 1/1 Running 6 44h kube-flannel-ds-amd64-vcqcz 1/1 Running 4 43h kube-proxy-75gjn 1/1 Running 5 43h kube-proxy-fj6js 1/1 Running 6 44h # 可以看到此时的kube-proxy已经运行了44h,不是最新的kube-proxy kube-proxy-kpfrl 1/1 Running 5 43h kube-scheduler-master 1/1 Running 5 44h
删除kube-proxy的pod标签
1、在node1节点上先安装一个ipvsadm客户端,方便查看此时的ipvs规则
[root@node1 ~]# yum install ipvsadm -y # 安装ipvs客户端 [root@node1 ~]# ipvsadm -ln # 此时可以看到没有任何ipvs规则,说明ipvs规则还是没有被加载进来 IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn [root@node1 ~]#
2、删除旧的kube-proxy标签,自动重构新的kube-proxy标签
[root@master ~]# kubectl get pods -n kube-system --show-labels # 查看此时旧的kube-proxy标签 NAME READY STATUS RESTARTS AGE LABELS coredns-546565776c-fl859 1/1 Running 20 44h k8s-app=kube-dns,pod-template-hash=546565776c coredns-546565776c-mwt5p 1/1 Running 18 44h k8s-app=kube-dns,pod-template-hash=546565776c etcd-master 1/1 Running 5 44h component=etcd,tier=control-plane kube-apiserver-master 1/1 Running 7 44h component=kube-apiserver,tier=control-plane kube-controller-manager-master 1/1 Running 5 44h component=kube-controller-manager,tier=control-plane kube-flannel-ds-amd64-rpdk6 1/1 Running 4 43h app=flannel,controller-revision-hash=56c5465959,pod-template-generation=1,tier=node kube-flannel-ds-amd64-rsb4s 1/1 Running 6 44h app=flannel,controller-revision-hash=56c5465959,pod-template-generation=1,tier=node kube-flannel-ds-amd64-vcqcz 1/1 Running 4 43h app=flannel,controller-revision-hash=56c5465959,pod-template-generation=1,tier=node kube-proxy-75gjn 1/1 Running 5 43h controller-revision-hash=77fcbc7cf9,k8s-app=kube-proxy,pod-template-generation=1 kube-proxy-fj6js 1/1 Running 6 44h controller-revision-hash=77fcbc7cf9,k8s-app=kube-proxy,pod-template-generation=1 kube-proxy-kpfrl 1/1 Running 5 43h controller-revision-hash=77fcbc7cf9,k8s-app=kube-proxy,pod-template-generation=1 kube-scheduler-master 1/1 Running 5 44h component=kube-scheduler,tier=control-plane [root@master ~]# kubectl delete pods -l k8s-app=kube-proxy -n kube-system # 使用-l 选项,过滤关键的标签进行删除。 pod "kube-proxy-75gjn" deleted pod "kube-proxy-fj6js" deleted pod "kube-proxy-kpfrl" deleted
3、查看此时重构新的kube-proxy标签,此时可以看到已经成为最新的kube-proxy标签
[root@master ~]# kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-546565776c-fl859 1/1 Running 20 44h coredns-546565776c-mwt5p 1/1 Running 18 44h etcd-master 1/1 Running 5 44h kube-apiserver-master 1/1 Running 7 44h kube-controller-manager-master 1/1 Running 5 44h kube-flannel-ds-amd64-rpdk6 1/1 Running 4 43h kube-flannel-ds-amd64-rsb4s 1/1 Running 6 44h kube-flannel-ds-amd64-vcqcz 1/1 Running 4 43h kube-proxy-djvh5 1/1 Running 0 50s kube-proxy-r8lc5 1/1 Running 0 51s kube-proxy-xkh9j 1/1 Running 0 53s kube-scheduler-master 1/1 Running 5 44h
4、此时在node1上查看ipvs的规则信息,默认的调度方式是rr方式
[root@node1 ~]# 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:30081 rr TCP 172.17.0.1:30081 rr TCP 172.17.0.1:31180 rr TCP 192.168.7.102:30081 rr TCP 192.168.7.102:31180 rr TCP 10.96.0.1:443 rr -> 192.168.7.101:6443 Masq 1 0 0 TCP 10.96.0.10:53 rr -> 10.224.0.26:53 Masq 1 0 0 -> 10.224.0.27:53 Masq 1 0 0 TCP 10.96.0.10:9153 rr -> 10.224.0.26:9153 Masq 1 0 0 -> 10.224.0.27:9153 Masq 1 0 0 TCP 10.97.97.97:80 rr -> 10.224.1.36:80 Masq 1 0 0 -> 10.224.2.33:80 Masq 1 0 0 TCP 10.97.107.135:80 rr TCP 10.99.99.99:6380 rr -> 10.224.1.41:6380 Masq 1 0 0 TCP 10.99.99.244:6380 rr TCP 10.102.139.95:80 rr TCP 10.105.2.202:80 rr -> 10.224.2.35:80 Masq 1 0 0 TCP 10.107.67.151:80 rr -> 10.224.2.35:80 Masq 1 0 0 TCP 10.224.1.0:30081 rr TCP 10.224.1.0:31180 rr TCP 10.224.1.1:30081 rr TCP 10.224.1.1:31180 rr TCP 127.0.0.1:31180 rr UDP 10.96.0.10:53 rr -> 10.224.0.26:53 Masq 1 0 0 -> 10.224.0.27:53 Masq 1 0 0
5、验证此时的服务还可以进行访问
[root@master ~]# kubectl get pods -o wide # 查看创建所有pod的详细信息 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES liveness-httpget-pod 1/1 Running 2 17h 10.224.2.32 node2 <none> <none> myapp-79476667f5-jqhvt 1/1 Running 1 13h 10.224.1.39 node1 <none> <none> myapp-79476667f5-xljzk 1/1 Running 1 13h 10.224.1.38 node1 <none> <none> nginx-6dd57bccf7-mkrmx 1/1 Running 3 43h 10.224.1.37 node1 <none> <none> nginx-dep-84b6dfdcd5-gm9dd 1/1 Running 3 43h 10.224.2.36 node2 <none> <none> ngx-dep-5d855b5b54-98rc2 1/1 Running 3 43h 10.224.2.35 node2 <none> <none> ngx-deploy-65fb6c8459-2zm44 1/1 Running 1 13h 10.224.2.33 node2 <none> <none> ngx-deploy-65fb6c8459-whgxx 1/1 Running 1 13h 10.224.1.36 node1 <none> <none> redis-658fb45c88-9clst 1/1 Running 0 111m 10.224.1.41 node1 <none> <none> [root@master ~]# curl 10.224.1.39 # 可以看到之前创建的pod服务还是可以访问到 Hello MyApp | Version: v3 | <a href="hostname.html">Pod Name</a>
第二种方法初始化k8s集群方式:由于前面已经使用kubeadm初始化了k8s集群,此时无法启动ipvs规则,以下是在开始使用kubeadm初始化k8s集群部署时使用的方法,kubeadm也可通过配置文件加载配置,以定制更丰富的部署选项。以下是个符合前述命令设定方式的使用示例,不过,它明确定义了kubeProxy的模式为ipvs,并支持通过修改imageRepository的值修改获取系统镜像时使用的镜像仓库。
apiVersion: kubeadm.k8s.io/v1alpha2 kind: MasterConfiguration kubernetesVersion: v1.13.3 # 指定k8s版本 api: advertiseAddress: 172.20.0.71 bindPort: 6443 controlPlaneEndpoint: "" imageRepository: k8s.gcr.io kubeProxy: config: mode: "ipvs" # 只需要在此处改为指定的ipvs规则 ipvs: ExcludeCIDRs: null minSyncPeriod: 0s scheduler: "" syncPeriod: 30s kubeletConfiguration: baseConfig: cgroupDriver: cgroupfs clusterDNS: - 10.96.0.10 clusterDomain: cluster.local failSwapOn: false resolvConf: /etc/resolv.conf staticPodPath: /etc/kubernetes/manifests networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 # 指定Pod网段 serviceSubnet: 10.96.0.0/12 # 指定的service网段
~]# kubeadm init --config kubeadm-config.yaml --ignore-preflight-errors=Swap
1.4 service定义资源清单几个字段
- apiVersion: v1 版本
- kind: Service 类型
- metadata 元数据
- spec 期望状态
- ports:服务公开的端口列表;把哪个端口和后端建立联系
- port:此服务将公开的端口
- targetPort:要在服务所针对的pod上访问的端口的编号或名称
- nodePort:K8S 集群节点上的端口
- selector:标签选择器;关联到哪些pod资源上程序。
- clusterIP:服务的IP地址,通常由主服务器随机分配,Service 资源的默认类型为 ClusterIP, 它仅能接收来自于集群中的 Pod 对象中的客户端程序的访问请求。
- type:确定服务的公开方式。 默认为ClusterIP
- ClusterIP(默认)
- NodePort
- LoadBalancer
- ExternalName
- sessionAffinity:service负载均衡,默认值是None,根据iptables规则随机调度;可使用sessionAffinity保持会话连线;
- ports:服务公开的端口列表;把哪个端口和后端建立联系
- status 当前状态
1.5 service的4中类型
- ClusterIP(默认):仅用于集群内通信,集群内部可达,可以被各pod访问,节点本身可访问;
- NodePort:构建在ClusterIP上,并在路由到clusterIP的每个节点上分配一个端口;
- client ---> NodeIP:NodePort ---> ClusterIP:ServicePort ---> PodIP:containePort
- LoadBalancer:构建在NodePort上,并创建一个外部负载均衡器(如果在当前云中受支持),它将路由到clusterIP;
- ExternelName:通过CNAME将service与externalName的值(比如:foo.bar.example.com)映射起来. 要求kube-dns的版本为1.7或以上.
2、创建clusterIP类型的service
(1)编写yaml文件并创建名为redis的service
先创建一个deployment,启动一个redis pod;在使用service绑定这个pod,其中三个"---"是资源分割符,不能多也不能少
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
[root@master manifests] # vim redis-svc.yaml apiVersion: apps /v1 kind: Deployment metadata: name: redis namespace: default spec: replicas: 1 selector: matchLabels: app: redis role: logstor template: metadata: labels: app: redis role: logstor spec: containers: - name: redis image: redis:4.0-alpine ports: - name: redis containerPort: 6379 # 后端容器端口 --- apiVersion: v1 kind: Service metadata: name: redis namespace: default spec: selector: app: redis role: logstor clusterIP: 10.99.99.99 type : ClusterIP ports: - port: 6380 targetPort: 6379 # 要与后端的容器端口一致 [root@master manifests] # kubectl apply -f redis-svc.yaml deployment.apps /redis created service /redis created |
(2)查询验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[root@master ~] # kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443 /TCP 142d redis ClusterIP 10.99.99.99 <none> 6380 /TCP 12s ---查询service详细信息,pod绑定成功 [root@master ~] # 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.99.99.99" , "ports" :[{"por... Selector: app=redis,role=logstor Type: ClusterIP IP: 10.99.99.99 Port: < unset > 6380 /TCP TargetPort: 6379 /TCP Endpoints: 10.244.2.94:6379 Session Affinity: None Events: <none> |
3、创建NodePort类型的service
3.1 创建service
(1)编写yaml文件并创建名为myapp的service
先创建一个deployment,启动3个myapp pod;在使用service绑定这3个pod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
[root@master manifests] # vim myapp-svc.yaml apiVersion: apps /v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: ikubernetes /myapp :v1 ports: - name: http containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: myapp namespace: default spec: selector: app: myapp release: canary clusterIP: 10.97.97.97 type : NodePort # 与下面自定义的31180端口对应 ports: - port: 80 targetPort: 80 # 要与后端服务器端口一致 nodePort: 31180 # 自定义了一个端口,一般不会去手动定义 [root@master manifests] # kubectl apply -f myapp-svc.yaml deployment.apps /myapp-deploy unchanged service /myapp created |
(2)查询验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[root@master ~] # kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443 /TCP 145d myapp NodePort 10.97.97.97 <none> 80:31180 /TCP 39s redis ClusterIP 10.99.99.99 <none> 6380 /TCP 2d [root@master ~] # 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" :{ "clusterIP" : "10.97.97.97" , "ports" :[{"nod... Selector: app=myapp,release=canary Type: NodePort IP: 10.97.97.97 Port: < unset > 80 /TCP TargetPort: 80 /TCP NodePort: < unset > 31180 /TCP Endpoints: 10.244.1.96:80,10.244.2.101:80,10.244.2.102:80 Session Affinity: None External Traffic Policy: Cluster Events: <none> |
(3)在集群外访问服务
3.2 使用sessionAffinity保持会话连接
(1)sessionAffinity默认是None,没有修改前,访问业务是随机调度
1
2
3
4
5
6
|
[root@master ~] # while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done myapp-deploy-69b47bc96d-mmb5v myapp-deploy-69b47bc96d-wtbx7 myapp-deploy-69b47bc96d-wtbx7 myapp-deploy-69b47bc96d-cj48v ... ... |
(2)打补丁修改sessionAffinity为clientip;实现会话连接
也可以使用exec修改;或者直接修改yaml文件也可以;
1
2
|
[root@master ~] # kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}' service /myapp patched |
(3)查询验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[root@master ~] # 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" :{ "clusterIP" : "10.97.97.97" , "ports" :[{"nod... Selector: app=myapp,release=canary Type: NodePort IP: 10.97.97.97 Port: < unset > 80 /TCP TargetPort: 80 /TCP NodePort: < unset > 31180 /TCP Endpoints: 10.244.1.96:80,10.244.2.101:80,10.244.2.102:80 Session Affinity: ClientIP External Traffic Policy: Cluster Events: <none> |
(4)访问业务查询验证;发现同一客户端的请求始终发往同一pod
1
2
3
4
5
6
|
[root@master ~] # while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done myapp-deploy-69b47bc96d-cj48v myapp-deploy-69b47bc96d-cj48v myapp-deploy-69b47bc96d-cj48v myapp-deploy-69b47bc96d-cj48v ... ... |
(5)重新打补丁修改为None,立即恢复为随机调度
1
2
3
4
5
6
7
|
[root@master ~] # kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}' service /myapp patched [root@master ~] # while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done myapp-deploy-69b47bc96d-cj48v myapp-deploy-69b47bc96d-mmb5v myapp-deploy-69b47bc96d-cj48v myapp-deploy-69b47bc96d-mmb5v |
4、创建无头service
(1)编写yaml文件并创建名为myapp-svc的service
绑定上面创建myapp的3个pod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@master manifests] # vim myapp-svc-headless.yaml apiVersion: v1 kind: Service metadata: name: myapp-svc namespace: default spec: selector: app: myapp release: canary clusterIP: None # 将clusterIP改为None就是随机的IP地址,也就是无头Service ports: - port: 80 targetPort: 80 [root@master manifests] # kubectl apply -f myapp-svc-headless.yaml service /myapp-svc created |
(2)查询验证
1
2
3
4
5
6
|
[root@master ~] # kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443 /TCP 145d myapp NodePort 10.97.97.97 <none> 80:31180 /TCP 2h myapp-svc ClusterIP None <none> 80 /TCP 6s redis ClusterIP 10.99.99.99 <none> 6380 /TCP 2d |
(3)和有头正常myapp的service对比
无头service的解析:
1
2
3
4
5
6
7
|
[root@master manifests] # dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10 ... ... ;; ANSWER SECTION: myapp-svc.default.svc.cluster. local . 5 IN A 10.244.1.96 myapp-svc.default.svc.cluster. local . 5 IN A 10.244.2.101 myapp-svc.default.svc.cluster. local . 5 IN A 10.244.2.102 ... ... |
有头正常myapp的service的解析:
[root@master manifests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10 ... ... ;; ANSWER SECTION: myapp.default.svc.cluster.local. 5 IN A 10.97.97.97 ... ...