Kubernetes Service
一、概念原理
Pod 解决的是一个微服务或一个应用的发布问题,当有了这些控制器以后,可以批量化的创建相似的 Pod,但不具备给用户提供一个统一的接口并实现负载均衡的能力,Service 是 Kubernetes 集群为我们准备好暴露服务的一种重要方式
1.1 概述
Kubernetes Service 定义了这样一种抽象:一个Pod 的逻辑分组,一种可以访问它们的策略—通常称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector
如果希望把 1.0 版本改成 2.0 版本,可以通过前面学习的几种方式来实现:
- 可以通过 patch 补丁
- kubectl patch deployment(类型)/deployment-demo(名称) --patch ‘{}’
- 可以通过 set image 去修改镜像
- 可以去修改资源清单文件然后通过 apply 应用。
- 修改资源文件,然后使用 apply 去更新(声明式)
- 通过 edit 去修改,edit 修改的是存储在 ETCD 中的资源
- 为什么要写资源清单文件:画设计图,按照这个设计图设计
- 创建一个 Pod/资源对象,比如现在需要创建一个期望的 Pod,通过在资源清单文件去规划所需要的东西
1.2 核心迭代
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy
进程,一种 VIP(虚拟IP)的形式;在 Kubernetes v1.8.0 beta.0 中,添加了 ipvs 代理
每个 node 节点都需要的组件:kube-apiServer、kube-proxy
运行的几种方式:
userspace
iptables
ipvs
默认情况下并没有选择以 ipvs 方案去工作
原因是因为 ipvs 这个模块是需要在内核中开启,官方害怕机器由于没有启用 ipvs 规则,进而导致没有办法正常工作。接下来去尝试修改 Kubernetes 集群的配置
# -n:选择命名空间
[root@master 5]# kubectl edit configmap kube-proxy -n kube-system
configmap/kube-proxy edited
# /mode:找到mode所在行,添加 ipvs
[root@master 5]# kubectl edit configmap kube-proxy -n kube-system
configmap/kube-proxy edited
# 基于kube-system这个标签,将当前的 kube-proxy 筛选出来
[root@master 5]# kubectl get pod -n kube-system -l k8s-app=kube-proxy
NAME READY STATUS RESTARTS AGE
kube-proxy-5hvmg 1/1 Running 4 (44h ago) 5d2h
kube-proxy-8mxv8 1/1 Running 5 (44h ago) 5d3h
kube-proxy-wqqdb 1/1 Running 4 (44h ago) 5d2h
由于刚修改了 kube-proxy 的配置参数,但应用程序没有重载,因此需要将这三个应用杀死后重建,从而就可以使用 ipvs 工作模式了
[root@master 5]# kubectl delete pod -n kube-system -l k8s-app=kube-proxy
pod "kube-proxy-5hvmg" deleted
pod "kube-proxy-8mxv8" deleted
pod "kube-proxy-wqqdb" deleted
[root@master 5]# kubectl get pod -n kube-system -l k8s-app=kube-proxy
NAME READY STATUS RESTARTS AGE
kube-proxy-dhrg6 1/1 Running 0 22s
kube-proxy-kzws2 1/1 Running 0 22s
kube-proxy-rdlhb 1/1 Running 0 22s
[root@master 5]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.86.11:6443 Masq 1 1 0
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.224.219.77:9153 Masq 1 0 0
-> 10.224.219.78:9153 Masq 1 0 0
TCP 10.6.85.172:80 rr
-> 10.224.104.18:80 Masq 1 0 0
-> 10.224.104.19:80 Masq 1 0 0
-> 10.224.104.22:80 Masq 1 0 0
-> 10.224.104.27:80 Masq 1 0 0
-> 10.224.104.28:80 Masq 1 0 0
-> 10.224.166.128:80 Masq 1 0 0
-> 10.224.166.132:80 Masq 1 0 0
-> 10.224.166.133:80 Masq 1 0 0
-> 10.224.166.134:80 Masq 1 0 0
-> 10.224.166.136:80 Masq 1 0 0
TCP 10.12.64.215:5473 rr
-> 192.168.86.12:5473 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
传数据 tcp、解析 udp
[root@master 5]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 3h49m
myapp ClusterIP 10.6.85.172 <none> 80/TCP 141m
# 这里的IP对应的规则:
TCP 10.6.85.172:80 rr#轮询 #NAT模式(瓶颈:多了很麻烦),只有NAT模式才能支持端口转换
-> 10.224.104.18:80 Masq 1 0 0
-> 10.224.104.19:80 Masq 1 0 0
-> 10.224.104.22:80 Masq 1 0 0
-> 10.224.104.27:80 Masq 1 0 0
-> 10.224.104.28:80 Masq 1 0 0
-> 10.224.166.128:80 Masq 1 0 0
-> 10.224.166.132:80 Masq 1 0 0
-> 10.224.166.133:80 Masq 1 0 0
-> 10.224.166.134:80 Masq 1 0 0
-> 10.224.166.136:80 Masq 1 0 0
# 对应以下 10 台真实服务器的地址
[root@master 5]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-5846867694-c7fkw 1/1 Running 0 143m 10.224.166.133 node1 <none> <none>
myapp-5846867694-c8hjp 1/1 Running 0 143m 10.224.166.136 node1 <none> <none>
myapp-5846867694-kq76h 1/1 Running 0 143m 10.224.104.27 node2 <none> <none>
myapp-5846867694-nfxm7 1/1 Running 0 144m 10.224.104.19 node2 <none> <none>
myapp-5846867694-nqpmw 1/1 Running 0 143m 10.224.104.18 node2 <none> <none>
myapp-5846867694-p4hr4 1/1 Running 0 143m 10.224.166.134 node1 <none> <none>
myapp-5846867694-vqlkk 1/1 Running 0 143m 10.224.104.22 node2 <none> <none>
myapp-5846867694-w69q5 1/1 Running 0 143m 10.224.166.132 node1 <none> <none>
myapp-5846867694-x7b4h 1/1 Running 0 143m 10.224.104.28 node2 <none> <none>
myapp-5846867694-x9kbv 1/1 Running 0 143m 10.224.166.128 node1 <none> <none>
这个原理就是把当前匹配的 Pod 写到本机的 ipvs 集群。当访问这个 service 的 IP 的时候,相当于访问的是 ipvs 集群,从而就会被负载到了后端的真实服务器
- 轮询效果:
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-c8hjp
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-kq76h
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-vqlkk
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-p4hr4
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-c7fkw
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-w69q5
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-x9kbv
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-x7b4h
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-nfxm7
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-nqpmw
[root@master 5]# curl 10.6.85.172/hostname.html #从第十一台又开始访问到第一台
myapp-5846867694-c8hjp
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-kq76h
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-vqlkk
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-p4hr4
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-c7fkw
[root@master 5]# curl 10.6.85.172/hostname.html
myapp-5846867694-w69q5
二、service 工作模式及使用
2.1 类型与组件协同
ClusterIP
:默认(只在集群内部使用,离开集群不能使用),自动分配一个仅 Cluster 内部可以访问的虚拟 IPNodePort
:在 ClusterIP 基础上 为 Service 在每台机器上绑定一个端口,这样就可以通过 < NodeIP >:NodePort 来访问该服务LoadBalancer
:在 NodePort 的基础上,借助 Cloud Provider 创建一个外部负载均衡器,并将请求转发到< NodelP >:NodePortExternalName
:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持
组件协同:
2.2 ClusterIP(自动分配一个仅 Cluster 内部可以访问的虚拟 IP)
自动分配一个仅 Cluster 内部可以访问的虚拟 IP
模式结构:
IPVS 的工作模式:
NAT 模式
,也叫地址转换模式- 优点是后端端口跟集群端口可以不一样;
- 缺点是不管是入站流量还是出站流量都必须经过 IPVS 调度器。
DR 模式
,也叫直接路由模式- 优点是回程流量不需要经过 IPVS,因此压力会更小;
- 缺点是可能需要对 ARP 响应和通况行为做设定,而且后端端口和集群负载均衡的端口必须一致。
TUN 模式
,也叫隧道模式- 优点是可以跨公网网络进行集群聚化的组建;
- 缺点是需要跨多个物理公网环境,且需要对数据报文做二次封装,因此性能比较低。
在 kubernetes 集群中,默认使用的方式就是 NAT 模式。因为可以明确的发现一个节点的信息就是当前我们 kubernetes 集群创建的 Service,它的集群端口和后端真实服务器端口可以不一致
当前节点的 ipvs 规则只会被当前节点的客户端所使用。另一个节点的客户端并不会访问我机器节点的ipvs规则。这就导致了每一个压力都不会太大,因此就选择了 NAT 模式
[root@master 5]# cd ..
[root@master ~]# mkdir 6
[root@master ~]# cd 6
[root@master 6]# ls
[root@master 6]# vim 1.deployment.yaml
[root@master 6]# cat 1.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-clusterip-deploy
namespace: default
spec:
replicas: 3
template:
metadata:
labels: #定义pod的标签
app: myapp
release: stabel
env: test
svc: clusterip
spec:
containers:
- name: myapp-clusterip-deploy-pod
image: harbor.registry.com/library/myapp:1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
selector: #标签选择器,需要与pod的标签做子集运算
matchLabels:
app: myapp
release: stabel
svc: clusterip
在资源清单中对 mainc 做一个就绪探测,探测的是 80 端口 index1.html 的页面
- 目前都为未就绪状态:
[root@master 6]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-57psb 0/1 Running 0 13s
myapp-clusterip-deploy-75f569678d-62xd6 0/1 Running 0 13s
myapp-clusterip-deploy-75f569678d-qk77t 0/1 Running 0 13s
来创建 Service 资源清单文件:
[root@master 6]# vim 2.svc.yaml
[root@master 6]# cat 2.svc.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-cluterip
namespace: default
spec:
type: ClusterIP
selector:
app: myapp
release: stabel
svc: clusterip
ports:
- name: http
port: 80
targetPort: 80
[root@master 6]# kubectl create -f 2.svc.yaml
service/myapp-cluterip created
[root@master 6]# kubectl get svc
#svc 的工作模式 #集群给它分配的IP地址(这个IP地址就是 IPVS 集群的 VIP,或叫集群IP)
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)#集群端口 AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16m
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 5s
EXTERNAL-IP:#外部IP地址,需要工作模式为 ExternalName 文件
2.2.1 service 匹配到 pod
如果 Service 想匹配到 Pod 需要满足两个条件:
- 一是就绪
- 二是满足标签子集运算(同一个名字空间下)
这几个 Pod 虽然达到标签子集运算匹配要求,但由于没有就绪,所以真实服务器的配置规则为空
[root@master 6]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.86.11:6443 Masq 1 0 0
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.224.219.77:9153 Masq 1 0 0
-> 10.224.219.78:9153 Masq 1 0 0
TCP 10.10.98.3:80 rr # tcp 的集群,地址是10.10.98.3,端口是80,算法是轮询,但是没有真实服务器的配置规则;对应上面service的IPVS集群的虚拟IP
TCP 10.12.64.215:5473 rr
-> 192.168.86.12:5473 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
# 进入 Pod 中,将 index1.html 添加上
[root@master 6]# kubectl exec -it myapp-clusterip-deploy-75f569678d-57psb -- /bin/sh
/ # cd /usr/local/nginx/html/
/usr/local/nginx/html # ls
50x.html hostname.html index.html
/usr/local/nginx/html # echo myapp-clusterip-deploy-75f569678d-57psb > index1.html
/usr/local/nginx/html # exit
[root@master 6]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-57psb 1/1 Running 0 60s
myapp-clusterip-deploy-75f569678d-62xd6 0/1 Running 0 60s
myapp-clusterip-deploy-75f569678d-qk77t 0/1 Running 0 60s
将其他 pod 的 index1.html 添加上
[root@master 6]# kubectl exec -it myapp-clusterip-deploy-75f569678d-62xd6 -- /bin/sh
/ # cd /usr/local/nginx/html/
/usr/local/nginx/html # ls
50x.html hostname.html index.html
/usr/local/nginx/html # echo "index1.html" > index1.html
/usr/local/nginx/html # exit
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-57psb 1/1 Running 0 8m54s
myapp-clusterip-deploy-75f569678d-62xd6 1/1 Running 0 8m54s
myapp-clusterip-deploy-75f569678d-qk77t 0/1 Running 0 8m54s
[root@master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.86.11:6443 Masq 1 0 0
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.224.219.77:9153 Masq 1 0 0
-> 10.224.219.78:9153 Masq 1 0 0
TCP 10.10.98.3:80 rr
-> 10.224.104.23:80 Masq 1 0 0
-> 10.224.166.135:80 Masq 1 0 0
TCP 10.12.64.215:5473 rr
-> 192.168.86.12:5473 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
[root@master ~]# kubectl exec -it myapp-clusterip-deploy-75f569678d-qk77t -- /bin/sh
/ # echo "index1.html" > /usr/local/nginx/html/index1.html
/ # exit
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-57psb 1/1 Running 0 10m
myapp-clusterip-deploy-75f569678d-62xd6 1/1 Running 0 10m
myapp-clusterip-deploy-75f569678d-qk77t 1/1 Running 0 10m
[root@master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.86.11:6443 Masq 1 0 0
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.224.219.77:9153 Masq 1 0 0
-> 10.224.219.78:9153 Masq 1 0 0
TCP 10.10.98.3:80 rr #成功实现真实服务器的负载均衡
-> 10.224.104.21:80 Masq 1 0 0
-> 10.224.104.23:80 Masq 1 0 0
-> 10.224.166.135:80 Masq 1 0 0
TCP 10.12.64.215:5473 rr
-> 192.168.86.12:5473 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
每一个 service 在创建完成以后,都会有一个 DNS 的域名在插件中被解析,解析的结果就是当前此 IP
一个 pod 要加入到 service 负载均衡的集群中,需满足两个条件:
- 标签匹配
- pod本身正常运行
只有能够被 service 的标签选择器匹配到的 pod 才会被加入到 负载均衡的集群中
[root@master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
myapp-clusterip-deploy-75f569678d-57psb 1/1 Running 0 12m app=myapp,env=test,pod-template-hash=75f569678d,release=stabel,svc=clusterip
myapp-clusterip-deploy-75f569678d-62xd6 1/1 Running 0 12m app=myapp,env=test,pod-template-hash=75f569678d,release=stabel,svc=clusterip
myapp-clusterip-deploy-75f569678d-qk77t 1/1 Running 0 12m app=myapp,env=test,pod-template-hash=75f569678d,release=stabel,svc=clusterip
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp-clusterip-deploy-75f569678d 3 3 3 12m
## hash值
pod 之间相通
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-clusterip-deploy-75f569678d-57psb 1/1 Running 0 15m 10.224.166.135 node1 <none> <none>
myapp-clusterip-deploy-75f569678d-62xd6 1/1 Running 0 15m 10.224.104.23 node2 <none> <none>
myapp-clusterip-deploy-75f569678d-qk77t 1/1 Running 0 15m 10.224.104.21 node2 <none> <none>
[root@master ~]# kubectl exec -it myapp-clusterip-deploy-75f569678d-qk77t -- /bin/sh
/ # ping 10.224.104.23
PING 10.224.104.23 (10.224.104.23): 56 data bytes
64 bytes from 10.224.104.23: seq=0 ttl=63 time=0.123 ms
64 bytes from 10.224.104.23: seq=1 ttl=63 time=0.081 ms
64 bytes from 10.224.104.23: seq=2 ttl=63 time=0.088 ms
64 bytes from 10.224.104.23: seq=3 ttl=63 time=0.063 ms
^C
--- 10.224.104.23 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.063/0.088/0.123 ms
/ #
2.2.2 域名解析
在 master 安装一个 bind 包 dnf install -y bind-utils
解析 dns 的 pod:
- 查看 svc
- 查看 dns 插件的IP
- 查看这两个 dns 插件对应的虚拟 IP,对于 dns 来说
- tcp 用于数据同步
- udp用于解析
- 如果多次 udp 解析不通过,也会允许使用 tcp 解析
- 解析域名
每一个 Service 创建好后就域名,格式为:
Service名称.所在名字空间.svc.cluster.local
[root@master 6]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16m
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 5s
[root@master ~]# kubectl get pod -n kube-system -o wide | grep dns
coredns-674b8bbfcf-62zb7 1/1 Running 4 (45h ago) 5d4h 10.224.219.78 master <none> <none>
coredns-674b8bbfcf-k2w42 1/1 Running 4 (45h ago) 5d4h 10.224.219.77 master <none> <none>
[root@master ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.86.11:6443 Masq 1 0 0
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.224.219.77:9153 Masq 1 0 0
-> 10.224.219.78:9153 Masq 1 0 0
TCP 10.10.98.3:80 rr
-> 10.224.104.21:80 Masq 1 0 0
-> 10.224.104.23:80 Masq 1 0 0
-> 10.224.166.135:80 Masq 1 0 0
TCP 10.12.64.215:5473 rr
-> 192.168.86.12:5473 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
# 它的虚拟IP:10.0.0.10,域名:myapp-cluterip.default.svc.cluster.local,服务名称.名字空间.svc.cluster.local
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
# 通过虚拟 IP 解析
[root@master ~]# dig -t A myapp-cluterip.default.svc.cluster.local @10.0.0.10
; <<>> DiG 9.16.23-RH <<>> -t A myapp-cluterip.default.svc.cluster.local @10.0.0.10
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27991
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: b27599955dcaebe8 (echoed)
;; QUESTION SECTION:
;myapp-cluterip.default.svc.cluster.local. IN A
;; ANSWER SECTION:
myapp-cluterip.default.svc.cluster.local. 30 IN A 10.10.98.3 #这里解析的就是
# 这里的域名和 10.10.98.3 IP绑定
;; Query time: 24 msec
;; SERVER: 10.0.0.10#53(10.0.0.10)
;; WHEN: Mon Jul 14 15:02:11 CST 2025
;; MSG SIZE rcvd: 137
[root@master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 32m
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 16m
由于 kubernetes 集群内部的 Pod 默认 DNS 都是指向到这两个 DNS 插件的 IP 上的,所以不需要配置它就可以解析通过
[root@master 6]# vim 3.dnstest.yaml
[root@master 6]# cat 3.dnstest.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
spec:
containers:
- name: busybox-1
image: harbor.registry.com/library/busybox:1.0
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
[root@master 6]# kubectl create -f 3.dnstest.yaml
pod/pod-demo created
[root@master 6]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-57psb 1/1 Running 0 58m
myapp-clusterip-deploy-75f569678d-62xd6 1/1 Running 0 58m
myapp-clusterip-deploy-75f569678d-qk77t 1/1 Running 0 58m
pod-demo 1/1 Running 0 13s
以 pod-demo 这个 pod 当客户端,去访问当前的域名,能解析通过
[root@master 6]# kubectl exec -it pod-demo -- /bin/sh
/ # wget myapp-cluterip.default.svc.cluster.local/hostname.html && cat hostname.html && rm -rf
hostname.html
Connecting to myapp-cluterip.default.svc.cluster.local (10.10.98.3:80)
hostname.html 100% |**********************************************| 40 0:00:00 ETA
myapp-clusterip-deploy-75f569678d-7x4zc
/ # wget myapp-cluterip.default.svc.cluster.local/hostname.html && cat hostname.html && rm -rf
hostname.html
Connecting to myapp-cluterip.default.svc.cluster.local (10.10.98.3:80)
hostname.html 100% |**********************************************| 40 0:00:00 ETA
myapp-clusterip-deploy-75f569678d-lx25h
/ # wget myapp-cluterip.default.svc.cluster.local/hostname.html && cat hostname.html && rm -rf
hostname.html
Connecting to myapp-cluterip.default.svc.cluster.local (10.10.98.3:80)
hostname.html 100% |**********************************************| 40 0:00:00 ETA
myapp-clusterip-deploy-75f569678d-4n69r
/ # wget myapp-cluterip.default.svc.cluster.local/hostname.html && cat hostname.html && rm -rf
hostname.html
Connecting to myapp-cluterip.default.svc.cluster.local (10.10.98.3:80)
hostname.html 100% |**********************************************| 40 0:00:00 ETA
myapp-clusterip-deploy-75f569678d-7x4zc
/ #
#### 域名访问,轮询
service 访问:IP方式、域名方式
2.2.3 internalTrafficPolicy (内部通信值)
通过设置 svc.spec.internalTrafficPolicy 的值为 Cluster 或者 Local,决定服务是通过什么方式访问
Cluster:内部+外部 都可访问(默认为Cluster)
- 内部: 进入 pod 内部
- 外部: 虚拟 IP(kubectl get svc)
Local:内部(进入到 pod 内部,通过域名访问)
kubectl explain svc.spec.internalTrafficPolicy
命令查看 internalTrafficPolicy 的用法
[root@master 6]# kubectl explain svc.spec.internalTrafficPolicy
KIND: Service
VERSION: v1
FIELD: internalTrafficPolicy <string>
ENUM: # 枚举值:
Cluster
Local
DESCRIPTION:
InternalTrafficPolicy describes how nodes distribute service traffic they
receive on the ClusterIP. If set to "Local", the proxy will assume that pods
only want to talk to endpoints of the service on the same node as the pod,
dropping the traffic if there are no local endpoints. The default value,
"Cluster", uses the standard behavior of routing to all endpoints evenly
(possibly modified by topology and other features).
Possible enum values:
- `"Cluster"` routes traffic to all endpoints.
- `"Local"` routes traffic only to endpoints on the same node as the client
pod (dropping the traffic if there are no local endpoints).
[root@master 6]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 81m
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 65m
[root@master 6]# kubectl edit svc myapp-cluterip
service/myapp-cluterip edited #修改internalTrafficPolicy为 Local
# pod内部可以通过域名访问,外部访问不了
[root@master 6]# curl 10.10.98.3
curl: (7) Failed to connect to 10.10.98.3 port 80: Connection refused
[root@master 6]# kubectl exec -it pod-demo -- /bin/sh
/ # wget myapp-cluterip.default.svc.cluster.local/hostname.html && cat hostname.html && rm -rf
hostname.html
Connecting to myapp-cluterip.default.svc.cluster.local (10.10.98.3:80)
hostname.html 100% |**********************************************| 40 0:00:00 ETA
myapp-clusterip-deploy-75f569678d-7x4zc
## 将 internalTrafficPolicy 值改回来 Cluster(外部IP+内部域名都可访问)
[root@master 6]# kubectl edit svc myapp-cluterip
service/myapp-cluterip edited
[root@master 6]# curl 10.10.98.3
hello jock | welcome to nginx! | version 1.0
如果确定这个 ClusterIP 只需要被 Pod 访问,建议把它改成 Local 类型,这样可以提高性能,减少资源开销
2.2.4 sessionAffinity 会话保持(IPVS持久化连接)
ipvs 持久化连接:可以将 用户请求 在有限时间内 定向在一台机器上
要实现这样的功能,只需要加一个 -p 选项即可:
ipvsadm -A -t 192.168.10.100:80 -s rr -p 120
ipvsadm 命令用于在 Linux 内核的 IPVS(IP Virtual Server)中添加一个虚拟服务
-A:添加(Add) 一个虚拟服务
-t:指定 tcp 协议
192.168.10.100:虚拟IP
-s:设置负载均衡调度算法,-s 表示调度算法(Scheduler),rr 是轮询(Round Robin),即请求会按顺序轮流分配给后端真实服务器
-p:启用持久连接,-p 后面的 120 表示超时时间(单位:秒);意味着来自同一客户端的请求在 120 秒内会被分配到同一台后端服务器
通过设置 svc.spec.sessionAffinity 的值为 ClusterIP 或者 None,决定是否开启持久化
- ClusterIP:开启持久化连接
- None:默认值
查看会话保持(sessionAffinity)的配置:kubectl explain svc.spec.sessionAffinity
[root@master 6]# kubectl explain svc.spec.sessionAffinity
KIND: Service
VERSION: v1
FIELD: sessionAffinity <string>
ENUM:
ClientIP
None
DESCRIPTION:
Supports "ClientIP" and "None". Used to maintain session affinity. Enable
client IP based session affinity. Must be ClientIP or None. Defaults to
None. More info:
https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
Possible enum values:
- `"ClientIP"` is the Client IP based. #如果 sessionAffinity 指定为 ClientIP,则默认值为 3 小时
- `"None"` - no session affinity. #默认不持久化
- sessionAffinity: 改为 Client
[root@master 6]# kubectl edit svc myapp-cluterip
service/myapp-cluterip edited
[root@master 6]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.86.11:6443 Masq 1 0 0
TCP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.224.219.77:9153 Masq 1 0 0
-> 10.224.219.78:9153 Masq 1 0 0
TCP 10.10.98.3:80 rr persistent 10800 # 多了persistent 10800,默认三小时
-> 10.224.104.20:80 Masq 1 0 0
-> 10.224.104.32:80 Masq 1 0 0
-> 10.224.166.140:80 Masq 1 0 0
TCP 10.12.64.215:5473 rr
-> 192.168.86.12:5473 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.224.219.77:53 Masq 1 0 0
-> 10.224.219.78:53 Masq 1 0 0
[root@master 6]# curl 10.10.98.3/hostname.html #一直访问一台主机,定向在了同一个机器上
myapp-clusterip-deploy-75f569678d-lx25h
[root@master 6]# curl 10.10.98.3/hostname.html
myapp-clusterip-deploy-75f569678d-lx25h
[root@master 6]# curl 10.10.98.3/hostname.html
myapp-clusterip-deploy-75f569678d-lx25h
[root@master 6]# curl 10.10.98.3/hostname.html
myapp-clusterip-deploy-75f569678d-lx25h
[root@master 6]# curl 10.10.98.3/hostname.html
myapp-clusterip-deploy-75f569678d-lx25h
[root@master 6]# curl 10.10.98.3/hostname.html
myapp-clusterip-deploy-75f569678d-lx25h
[root@master 6]# curl 10.10.98.3/hostname.html
myapp-clusterip-deploy-75f569678d-lx25h
2.3 NodePort(将集群内部的服务暴露给集群外部访问)
将集群内部的服务器暴露给集群外部访问
NodePort 是一种升级版的 ClusterIP,不仅可以做到 ClusterIP 拥有的功能,还支持在物理网卡上去绑定一个物理端口,以此去实现外部访问
- NodePort 类型结构如下图:
- 首先底层通过 Deployment 控制器创建了几个 Pod。
- 其次给这些 Pod 创建了一个 IPVS 对应的 ClusterIP 类型的 SVC。
- 接下来再创建了一个 Deployment 控制器,用于运行 nginx 服务,这些 nginx 被类型为 NodePort 的 SVC 所匹配关联,再绑定在当前节点对应物理网卡的物理端口之上
一般是大于 3 万,如 30010。当然,这个值是可以通过 kube-apiserver 在启动的时候去定义一个端口范围的。
模式演示
- 创建 Deployment 资源清单文件 deploy.yaml
- 创建 svc 资源清单 nodeport.yaml
- port: 80 ----- 集群内部访问端口
- targetPort: 80 ----- 真实服务器访问端口
- nodePort: 30010 ----- 集群外部访问端口
[root@master 6]# vim 5.deployment.yaml
[root@master 6]# cat 5.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-nodeport-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: stabel
svc: nodeport
template:
metadata:
labels:
app: myapp
release: stabel
svc: nodeport
env: test
spec:
containers:
- name: myapp-nodeport-deploy-pod
image: harbor.registry.com/library/myapp:1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
[root@master 6]# kubectl create -f 5.deployment.yaml
deployment.apps/myapp-nodeport-deploy created
[root@master 6]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-4n69r 1/1 Running 0 36m
myapp-clusterip-deploy-75f569678d-7x4zc 1/1 Running 0 36m
myapp-clusterip-deploy-75f569678d-lx25h 1/1 Running 0 36m
myapp-nodeport-deploy-db68f76df-52h5d 1/1 Running 0 6s
myapp-nodeport-deploy-db68f76df-982gm 1/1 Running 0 6s
myapp-nodeport-deploy-db68f76df-mgmkn 1/1 Running 0 6s
pod-demo 1/1 Running 0 37m
[root@master 6]# vim 6.nodeport.yaml
[root@master 6]# cat 6.nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-nodeport
namespace: default
spec:
type: NodePort
selector:
app: myapp
release: stabel
svc: nodeport
ports:
- name: http
port: 80 #集群内部访问端口
targetPort: 80 #真实服务器访问端口
nodePort: 30010 #集群外部访问端口,必须 30000 以上
[root@master 6]# kubectl create -f 6.nodeport.yaml
service/myapp-nodeport created
[root@master 6]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 110m
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 94m
myapp-nodeport NodePort 10.2.116.131 <none> 80:30010/TCP 8s
# nodeport 服务已经被创建
# 外部访问集群端口号:30010,是在物理网卡的访问端口
# 集群内部如果需要访问这个svc的端口号:80
私有IP和私有端口,就可在集群内部以负载均衡的方案访问
可通过物理网卡在集群外部访问:
[root@master 6]# curl 10.2.116.131
hello jock | welcome to nginx! | version 1.0
[root@master 6]# curl 10.2.116.131/hostname.html
myapp-nodeport-deploy-db68f76df-52h5d
[root@master 6]# curl 10.2.116.131/hostname.html
myapp-nodeport-deploy-db68f76df-mgmkn
[root@master 6]# curl 10.2.116.131/hostname.html
myapp-nodeport-deploy-db68f76df-982gm
[root@master 6]# curl 10.2.116.131/hostname.html
myapp-nodeport-deploy-db68f76df-52h5d
[root@master 6]# curl 10.2.116.131/hostname.html
myapp-nodeport-deploy-db68f76df-mgmkn
[root@master 6]# ipvsadm -Ln | grep 30010
TCP 172.17.0.1:30010 rr
TCP 192.168.86.11:30010 rr
[root@node1 ~]# ipvsadm -Ln | grep 30010
TCP 172.17.0.1:30010 rr
TCP 192.168.86.12:30010 rr
#把物理网卡 192.168.86.11 的 30010 端口做了一个负载均衡集群,绑定的依然是当前的每个节点的真实服务器。
#其次还把 172.17.0.1 也做了负载均衡,这都是可用的网卡信息
所以你的机器有多块网卡的话,它会把当前机器的每一块可用网卡的地址都写一个 IPVS 集群。
所以 NodePort 是将集群内部暴露到集群以外的用户访问。注意,是所有节点的物理 IP 加 30010 端口都能够访问
外部访问:
所以只要是在 Kubernetes 节点,只要创建的是 NodePort 类型,那么每个节点每个物理有效的网卡 IP 都可以进行外部访问。
这也是为什么要在真正的生产环境中,需要在外部再加一个调度器,去负载到当前的每个节点,以此保证当前任何一个节点死亡,不会造成用户访问中断
externalTrafficPolicy(外部访问策略)
通过设置 svc.spec.externalTrafficPolicy 的值为 Cluster 或者 Local,决定外部的访问的策略
- Cluster:允许集群以内集群以外共同访问的(默认为Cluster)
- Local:仅仅只是保证在集群内部访问
kubectl explain svc.spec.externalTrafficPolicy
命令查看 externalTrafficPolicy 的用法
ClusterIP 的 internalTrafficPolicy 代表的是集群以内对它的访问
Cluster
是默认类型:代表集群节点的工具可以通过虚拟 IP 进行访问,集群内部的 Pod 可以通过虚拟 IP 进行访问- 改为
Local
类型时:,仅仅只支持集群内部的 Pod 可以通过虚拟 IP 进行访问NodePort 的 externalTrafficPolicy 是代表集群以外对它的访问
Cluster
:集群以外的客户端可以通过节点的物理网卡的物理IP对应的端口进行访问,也支持集群节点的工具可以通过节点的物理网卡的物理 IP 对应的端口进行访问Local
:仅仅只支持集群节点的工具可以通过节点的物理网卡的物理 IP 对应的端口进行访问
2.4 LoadBalancer(解决高可用 – 云服务)
LoadBalancer 解决高可用的问题(只能以云的环境中去使用)
在每个节点上都创建 NodePort 模式的 Service,它们都会在对应的节点的物理网卡开启对应的端口。用户需要知道这些物理 IP 和端口才可以正常访问,但如果某个节点死了,那么用户的访问就会中断。(无法实现高可用)
在前面架设一个调度器,可以是四层的,也可以是七层的,还可以是二层的 F5
当用户请求过来以后,会被负载到第一个端口,第二个端口,第三个端口等。那怕有一天第一个节点死了,由于还有两个端口可用,所以依然可以通过后两个端口的负载来提供给用户访问。(必须工作在云的环境中。比如阿里云、比如百度云、比如华为云等等)
2.5 ExternalName(域名的别名机制)
ClusterIP、NodePort 还是 LoadBalancer,这三种 SVC 类型都需要底层 IPVS 参与,ExternalName 它并不需要 IPVS 参与,仅仅只是靠 DNS 的插件就可以实现
ExternalName:把外部的东西拿进来(对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务)
没有 selector,也没有定义任何的端口和 Endpoint
- 模试演示:
[root@master 6]# vim 7.ensvc.yaml
[root@master 6]# cat 7.ensvc.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service-1
namespace: default
spec:
type: ExternalName
externalName: www.baidu.com
[root@master 6]# kubectl create -f 7.ensvc.yaml
service/my-service-1 created
[root@master 6]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 125m
my-service-1 ExternalName <none> www.baidu.com <none> 5s
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 109m
myapp-nodeport NodePort 10.2.116.131 <none> 80:30010/TCP 15m
[root@master 6]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-clusterip-deploy-75f569678d-4n69r 1/1 Running 0 56m
myapp-clusterip-deploy-75f569678d-7x4zc 1/1 Running 0 57m
myapp-clusterip-deploy-75f569678d-lx25h 1/1 Running 0 56m
myapp-nodeport-deploy-db68f76df-52h5d 1/1 Running 0 20m
myapp-nodeport-deploy-db68f76df-982gm 1/1 Running 0 20m
myapp-nodeport-deploy-db68f76df-mgmkn 1/1 Running 0 20m
pod-demo 1/1 Running 0 58m
[root@master 6]# kubectl exec -it pod-demo -- /bin/sh
/ # ping -c 3 my-service-1.default.svc.cluster.local
PING my-service-1.default.svc.cluster.local (183.2.172.17): 56 data bytes
64 bytes from 183.2.172.17: seq=0 ttl=126 time=60.115 ms
64 bytes from 183.2.172.17: seq=1 ttl=126 time=41.066 ms
64 bytes from 183.2.172.17: seq=2 ttl=126 time=75.883 ms
--- my-service-1.default.svc.cluster.local ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 41.066/59.021/75.883 ms
/ #
## 成功访问外部
ClusterIP没有分配,但是External IP
三、EndpointSlice 端点
EndpointSlice 是 Service 的底层模型,有了它以后, Service 才能够去建立底层 IPVS 实际的运行关联
3.1 Endpoint 与 Service 和 Pod 间的关联
Endpoint 与 Service 和 Pod 间的关联:
Kubernetes 中的 Service,它定义了一组 Pods 的逻辑集合和一个用于访问它们的策略。
一个 Service 的目标 Pod 集合通常是由 Label Selector 来决定的
Endpoints 是一组实际服务的端点集合。一个 Endpoint 是一个可被访问的服务端点,即 一个状态为 running 的 pod 的可访问端点 。一般 Pod 都不是一个独立存在,所以一组 Pod 的端点合在一起称为 EndPoints。
只有被 Service Selector 匹配选中 并且 状态为 Running 的才会被加入到和 Service 同名的 Endpoints 中
对于当前的 Endpoints 对象来说,有两个类型:
- 自动关联体系:配置 selector(默认类型)—> 当定义了 Service ,它会自动创建一个 Endpoints
- 通过 selector 标签选择器
- 创建 deployment
- 创建 service,自动创建一个 endpoints --> 管理 pod
- 通过 selector 标签选择器
- 手动关联体系:无配置 selector —> 创建了 service,并没有创建端点对象,而是需要手动的去完成端点对象书写
- 创建 svc ,没有指定标签选择器 selector
- 创建 endpoints。通过 subsets 来指定要绑定进来的真实服务器的 IP 地址,并且需要注意 endpoints 的 name 与 service 的 name 保持一致
3.2 配置 Selector(自动关联体系)
Sercice:调用规则(ipvs)
EndpointSlice:将每个 pod 的 IP 地址、端口号收集起来,ipvs(LVS-负载均衡),将信息同步给kubelet
Pod:pod 里面跑的是应用程序,每个都有 IP、端口号
自动关联演示:
- 有自带的标签功能
[root@master 6]# vim 1.deployment.yaml
[root@master 6]# cat 1.deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-clusterip-deploy
namespace: default
spec:
replicas: 3
template:
metadata:
labels:
app: myapp
release: stabel
env: test
svc: clusterip
spec:
containers:
- name: myapp-clusterip-deploy-pod
image: harbor.registry.com/library/myapp:1.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
selector:
matchLabels:
app: myapp
release: stabel
svc: clusterip
[root@master 6]# vim 2.svc.yaml
[root@master 6]# cat 2.svc.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-cluterip
namespace: default
spec:
type: ClusterIP
selector:
app: myapp
release: stabel
svc: clusterip
ports:
- name: http
port: 80
targetPort: 80
有标签的自动关联体系,也就意味着当 Service 创建完成以后,它会自
动出现一个同名的 endpoints
[root@master 6]# kubectl get pod -o wide -l "app=myapp,release=stabel,svc=clusterip"
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
myapp-clusterip-deploy-75f569678d-4n69r 1/1 Running 0 71m 10.224.104.32 node2 <none> <none>
myapp-clusterip-deploy-75f569678d-7x4zc 1/1 Running 0 72m 10.224.166.140 node1 <none> <none>
myapp-clusterip-deploy-75f569678d-lx25h 1/1 Running 0 71m 10.224.104.20 node2 <none> <none>
[root@master 6]# kubectl get endpoints
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME ENDPOINTS AGE
kubernetes 192.168.86.11:6443 134m
myapp-cluterip 10.224.104.20:80,10.224.104.32:80,10.224.166.140:80 118m
三个 endpoint 分别对应三个 Pod 的虚拟 IP
3.3 无配置 Selector
Kubernetes 内部的应用依然会通过 Service 发起访问,Service 最终还是通过 IPVS 将请求分散到后端的真实的 Pod 服务
[root@master 6]# vim 8.svc.yaml
[root@master 6]# cat 8.svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-noselector
spec:
ports:
- protocol: TCP
port: 6666
targetPort: 80
[root@master 6]# kubectl create -f 8.svc.yaml
service/nginx-noselector created
[root@master 6]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 146m
my-service-1 ExternalName <none> www.baidu.com <none> 20m
myapp-cluterip ClusterIP 10.10.98.3 <none> 80/TCP 130m
myapp-nodeport NodePort 10.2.116.131 <none> 80:30010/TCP 36m
nginx-noselector ClusterIP 10.8.243.133 <none> 6666/TCP 49s #已创建
#默认是Clusterip
[root@master 6]# kubectl get endpoints
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME ENDPOINTS AGE
kubernetes 192.168.86.11:6443 147m
myapp-cluterip 10.224.104.20:80,10.224.104.32:80,10.224.166.140:80 131m
myapp-nodeport 10.224.104.29:80,10.224.104.30:80,10.224.166.139:80 36m
[root@master 6]# ipvsadm -Ln
..........
TCP 10.8.243.133:6666 rr #规则下并没有真实的服务器信息
TCP 10.10.98.3:80 rr persistent 10800
-> 10.224.104.20:80 Masq 1 0 0
-> 10.224.104.32:80 Masq 1 0 0
-> 10.224.166.140:80 Masq 1 0 0
..........
创建 endpoints:
[root@master 6]# vim 9.ep.yaml
[root@master 6]# cat 9.ep.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: nginx-noselector
subsets:
- addresses:
- ip: 192.168.86.12
ports:
- port: 80
[root@master 6]# kubectl apply -f 9.ep.yaml
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
endpoints/nginx-noselector created
[root@master 6]# kubectl get endpoints
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME ENDPOINTS AGE
kubernetes 192.168.86.11:6443 151m
myapp-cluterip 10.224.104.20:80,10.224.104.32:80,10.224.166.140:80 135m
myapp-nodeport 10.224.104.29:80,10.224.104.30:80,10.224.166.139:80 40m
nginx-noselector 192.168.86.12:80 38s
[root@master 6]# ipvsadm -Ln
............
TCP 10.8.243.133:6666 rr
-> 192.168.86.12:80 Masq 1 0 0
............
这个端点值已经写入了 IPVS 的负载均衡里了
EndpointSlice 自动关联和手动关联
- 自动关联:是根据标签选择器来实现的
- 在创建 Service 的同时会创建 EndpointSlice 对象,这个对象会将满足条件(标签的子集和处理正常运行状态的Pod)的 Pod 的 IP 和端口 加入到列表中 ,并 同步给当前节点上的 kubelet 组件 ,让这个组件将列数据转换为负载均衡规则。
- 手动关联:在 service 中没有定义标签选择器
- 在创建 Service 的时候也不会创建 EndpointSlice 对象,这个对象需要自己去创建,并绑定外部的 IP 和端口。
- 然后在外部启动相应的应用来访问
3.4 publishNotReadyAddresses(未就绪,但标签匹配)
publishNotReadyAddresses 的作用是:捕获那些那怕未就绪的 Pod,只要标签匹配就可
以抓取创建
- Service 和 Pod 之间 的中间关联(或叫端点)
在创建 Service 时,如果提供了选择器,并且能够成功匹配到对应的 Pod 后,就会创建一个与 Service 同名字的端点对象,以此去记录后端 Pod 的端点值,即地址和端口。 然后对应的每个节点上的
kubelet 再将这个端点对象同步到本节点的 IPVS 的规则中去,进而就实现负载均衡的局面
如果一个 Service 能够成功匹配到 Pod 的话必须有两个指标:
标签选择器
必须是Pod 标签
的子集- Pod 必须处于就绪状态
编写资源清单文件:
[root@master 6]# vim 15.pod.yaml
[root@master 6]# cat 15.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
labels:
app: myapp
env: test
spec:
containers:
- name: readiness-httpget-container
image: harbor.registry.com/library/myapp:1.0
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /index1/html
initialDelaySeconds: 1 #延迟1秒以后开始探测
periodSeconds: 3 #间隔3秒探测一次
[root@master 6]# kubectl apply -f 15.pod.yaml
pod/readiness-httpget-pod created
[root@master 6]# kubectl get pod
NAME READY STATUS RESTARTS AGE
readiness-httpget-pod 0/1 Running 0 8s
Pod 有一个标签为 app=myapp
[root@k8s-master01 6]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
readiness-httpget-pod 0/1 Running 0 13m app=myapp,env=test
可以创建一个名称为 myapp 的 Service 资源对象来与之匹配关联:
[root@master 6]# kubectl create svc clusterip myapp --tcp=80:80
service/myapp created
[root@master 6]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 10m
myapp ClusterIP 10.14.148.143 <none> 80/TCP 6s
# svc 对象已经创建成功,并且分配了一个集群内部访问的 IP 地址
[root@master 6]# curl 10.14.148.143
curl: (7) Failed to connect to 10.14.148.143 port 80: Connection refused
无法访问成功,原因是对应的真实服务器(Pod)当前处于未就绪状态,不满足匹配条件:子集和就绪
如果有特殊要求:不管 Pod 是否就绪都将其添加到负载均衡规则中,那就需要去开启一个特殊选项——将当前 Service 对象中
publishNotReadyAddresses
的值改成 true 就可以
[root@master 6]# kubectl patch service myapp -p '{"spec":{"publishNotReadyAddresses":true}}'
service/myapp patched
# 执行如下命令来查看是否修改成功
[root@master 6]# kubectl edit svc myapp
Edit cancelled, no changes made.
[root@master 6]# curl 10.14.148.143
readiness-httpget-pod
将此选项开启以后,就可以去捕获那些那怕未就绪的 Pod,只要标签匹配就可以抓取创建