21.B站薪享宏福笔记——第六章 k8s Service
6 k8s Service
6.1 Service 概念原理
—— 集群中服务外露的重要方式
6.1.1 Service 概述
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问他们的策略 —— 通常称为微服务。这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector

1.Service 对外暴露一个端口,用户通过 443 端口访问 Service。
2.Deployment 控制器通过标签控制产生 Pod,Pod 带有标签。
3.Service 通过匹配后端 Pod 的标签,将符合自己标签的 Pod 动态加入到自己的负载集群中。
4.即使 Pod 挂掉,Deployment 控制器也会再启动相同标签的 Pod,Service 再动态将 Pod 加入负载。
6.1.2 Service 的作用

1.以前的负载均衡,使用 nginx 和 tomcat 集合,nginx 静态、tomcat 动态
2.nginx 代理后端的 tomcat Pod 中各容器的 IP 地址
3.当有一天 tomcat Pod 挂了,nginx 中有对七层服务的探测能力,可以对后端 Pod 探测,死亡后不再负载到其上
4.Deployment-T 控制器会再重构一个 tomcat Pod,但是 nginx 不会自动将新的 tomcat Pod 的 IP 地址加入到集群中
5.需要写一个脚本,获取新的 tomcat Pod 的 IP 地址加入到集群中,并重启 nginx 的 Pod,才能生效

1.增加中间层 Service ,前后解藕,nginx Pod 只需要访问 service ,资源池中写 Service 的 IP 地址即可
2.Service 会根据两个条件动态匹配:1.Pod 就绪、2.标签匹配,符合条件,将 tomcat Pod 抓取放到自己的负载均衡集群中( Service 会 Pod 可用添加,不可用剔除)
6.1.3 Service 核心原理
(1)网络模型
在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP (虚拟IP)的形式
在 Kubernetes v1.0 版本,代理完全在 userspace。在 Kubernetes v1.1 版本,新增了 iptables 代理,但并不是默认的运行模式。从 Kubernetes v1.2 起,默认就是 iptables 代理。在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理。
(目前默认仍然使用 iptables 规则,ipvs 比 iptables 高访问量时性能更好,但 k8s 官网没有默认支持 ipvs。原因:1.ipvs 需要在内核中开启,官方担心你没开启,2.目前云厂商阉割了这个服务模块,ipvs 模块和云厂商的 LSB 是竞聘,都可以做负载均衡。)
# 验证默认使用 iptables , usespace 已经被移除,实验中没有产生 ipvs 规则 [root@k8s-master01 ~]# kubectl create deployment myapp --image=myapp:v1.0 deployment.apps/myapp created [root@k8s-master01 ~]# kubectl scale deployment myapp --replicas=3 deployment.apps/myapp scaled [root@k8s-master01 ~]# kubectl get pod NAME READY STATUS RESTARTS AGE myapp-77d465c645-6krm5 1/1 Running 0 25s myapp-77d465c645-892ks 1/1 Running 0 25s myapp-77d465c645-xnxqd 1/1 Running 0 79s [root@k8s-master01 ~]# kubectl create svc clusterip myapp --tcp=80:80 service/myapp created [root@k8s-master01 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 12d myapp ClusterIP 10.5.180.56 <none> 80/TCP 12s [root@k8s-master01 ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn
(2)一代 userspace 用户空间模式

userspace 工作模式下的 kube-proxy:
1.每台节点上的 kube-proxy 都需要去监听 kube-ApiServcer,监听当前需要改变的 service 的对象信息,修改成本地的 iptables 规则
2.代理来自当前节点 Pod 的用户请求(Client pod 访问本地的 iptables 规则,iptables 将流量转发至当前节点或其他节点的 kube-proxy,kube-proxy 代理 Server Pod 返回给 Client pod)
缺点:当规模较大时,kube-proxy 压力可能会比较大,做了两件事,不便于功能解藕
(3)二代 iptables

iptables 工作模式下的 kube-proxy:
1.每台节点上的 kube-proxy 都需要去监听 kube-apiServcer,监听当前需要改变的 service 的对象信息,修改成本地的 iptables 规则
优点:
相对于 userspace,kube-proxy 功能解藕,压力较小
Client pod 访问本地的 iptables 规则,iptables 将流量转发给本地的 Server pod 或其他节点 iptables
(4)三代 ipvs

ipvs 工作模式下的 kube-proxy:
1.每台节点上的 kube-proxy 都需要去监听 kube-apiServcer,监听当前需要改变的 service 的对象信息,修改成本地的 ipvs 规则
优点:
相对于 iptables,ipvs 是基于内核的四层负载,集群规模增大,效率仍旧很高
Client pod 访问本地的 ipvs 规则,ipvs 将流量转发给本地的 Server pod 或其他节点 ipvs
(5)将 iptables 修改为 ipvs
a.edit 修改
# edit 修改,k8s 集群信息通过 API Service 存储在 etcd 中,之前修改 patch、set image、apply 都是通过 kubectl 修改 API Service,再去调整 etcd,而 edit 相当于直接修改 etcd 中的数据(本源) # 通过 edit 修改 myapp,可直接进行 myapp 的升级 [root@k8s-master01 6]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 12d myapp ClusterIP 10.5.180.56 <none> 80/TCP 3h14m [root@k8s-master01 5]# curl 10.5.180.56 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a> [root@k8s-master01 5]# kubectl edit deployment myapp .......... spec: containers: - image: myapp:v2.0 imagePullPolicy: IfNotPresent .......... "/tmp/kubectl-edit-2801732894.yaml" 66L, 1785B written deployment.apps/myapp edited [root@k8s-master01 5]# curl 10.5.180.56 Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
b.修改ipvs
# 修改第 57 行的 mode 空 改为 ipvs [root@k8s-master01 6]# kubectl edit configmap kube-proxy -n kube-system .......... 57 mode: "ipvs" .......... configmap/kube-proxy edited # 查找 kube-proxy 组件 Pod,并删除,因为上面修改了配置文件 configmap,但是组件 Pod 没有重载,所以不生效(不是热加载) [root@k8s-master01 6]# kubectl get pod -n kube-system --show-labels -l k8s-app=kube-proxy NAME READY STATUS RESTARTS AGE LABELS kube-proxy-5xdm2 1/1 Running 15 (5h57m ago) 12d controller-revision-hash=779547c8f9,k8s-app=kube-proxy,pod-template-generation=1 kube-proxy-78cq2 1/1 Running 15 (5h57m ago) 12d controller-revision-hash=779547c8f9,k8s-app=kube-proxy,pod-template-generation=1 kube-proxy-hfspv 1/1 Running 15 (5h57m ago) 12d controller-revision-hash=779547c8f9,k8s-app=kube-proxy,pod-template-generation=1 [root@k8s-master01 6]# kubectl delete pod -n kube-system -l k8s-app=kube-proxy pod "kube-proxy-5xdm2" deleted pod "kube-proxy-78cq2" deleted pod "kube-proxy-hfspv" deleted [root@k8s-master01 6]# kubectl get pod -n kube-system --show-labels -l k8s-app=kube-proxy NAME READY STATUS RESTARTS AGE LABELS kube-proxy-fg4nf 1/1 Running 0 7s controller-revision-hash=779547c8f9,k8s-app=kube-proxy,pod-template-generation=1 kube-proxy-frk9v 1/1 Running 0 7s controller-revision-hash=779547c8f9,k8s-app=kube-proxy,pod-template-generation=1 kube-proxy-nrfww 1/1 Running 0 7s controller-revision-hash=779547c8f9,k8s-app=kube-proxy,pod-template-generation=1 # 查看 ipvs 路由规则,svc 的 IP 负载后端 Pod 的 IP 地址 [root@k8s-master01 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.66.11:6443 Masq 1 1 0 TCP 10.0.0.10:53 rr -> 10.244.32.161:53 Masq 1 0 0 -> 10.244.32.162:53 Masq 1 0 0 TCP 10.0.0.10:9153 rr -> 10.244.32.161:9153 Masq 1 0 0 -> 10.244.32.162:9153 Masq 1 0 0 TCP 10.5.180.56:80 rr -> 10.244.58.216:80 Masq 1 0 0 -> 10.244.58.218:80 Masq 1 0 0 -> 10.244.85.209:80 Masq 1 0 0 TCP 10.11.198.102:5473 rr -> 192.168.66.11:5473 Masq 1 0 0 UDP 10.0.0.10:53 rr -> 10.244.32.161:53 Masq 1 0 0 -> 10.244.32.162:53 Masq 1 0 0 [root@k8s-master01 6]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 12d myapp ClusterIP 10.5.180.56 <none> 80/TCP 3h40m [root@k8s-master01 6]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-6b578f7d66-77nbm 1/1 Running 0 23m 10.244.85.209 k8s-node01 <none> <none> myapp-6b578f7d66-jm6ld 1/1 Running 0 23m 10.244.58.218 k8s-node02 <none> <none> myapp-6b578f7d66-pzxg5 1/1 Running 0 23m 10.244.58.216 k8s-node02 <none> <none>
6.2 Service 工作原理及使用
—— 适合的才是好的
6.2.1 Service 原理
(1)分类
ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 <NodeIP>:<NodePort> 来访问该服务
LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到 <NodeIP>:<NodePort>
ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只是 kubernetes 1.7 或更高版本的 kube-dns 才支持
(2) ClusterIp 类型

未出现 Service 之前:
1.在没有 Service 时,Deployment-N 控制器产生的 Pod 需要指定后端 Deployment-T 控制器产生 Pod 的 IP 地址,这样才能负载到后端
2.其中一个 Pod 死亡,app=nginx 的 Pod 不在向上调度负载,Deployment-T 控制器会新建 Pod,但是 app=nginx 的 Pod 不会再向上进行负载。(耦合性过强)
出现 Service 之后:
1.Deployment-N 控制器只要绑定 Service 服务通过 IPVS 创建的虚拟 IP 既可(ClusterIP 创建虚拟 VIP ),Service 根据标签匹配负载到后端 Pod
2.其中一个 Pod 死亡,Service 会自动将其剔除,Deployment-T 控制器新建 Pod,Service 根据标签,符合子集运算,又将新 Pod 加入到负载中
(3) NodePort 类型

1.当用户是通过集群外访问时,因为 Pod 是扁平化网络,外部网络访问不到集群内
2.NodePort 内部以 ClusterIp 为基础, 外部通过绑定物理机网卡和端口(端口值在30000—32767之间)使其成为集群的 VIP (当前集群的所有物理网卡都会启动这个端口)
3.NodePort 的 Service 前端通过绑定物理网卡的 VIP,后端通过标签匹配的方式匹配 Pod,使用户可以访问集群内部
4.整个集群是 4—7—4 负载形式,Service NodePort 4层绑定物理 IP+端口 负载到集群匹配标签的 nginx Pod 上,nginx Pod 7层负载到 Service ClusterIp 上,Service ClusterIP 通过标签负载到后端匹配标签的 Pod 上
(4)LoadBalancer
a.自建机房的高可用

1.用户访问 ipvs 形成的虚拟 IP,通过 Keepalived 形成心跳同步的高可用
2.整体用户访问 —> IPVS(keepalived 形成高可用) —> ens33(节点高可用)—> IPVS (Service NodePort 一种资源,集群不死就不会死)—> Pod app=nginx (Deployment-N 控制器高可用)—> IPVS (Service ClusterIP 一种资源,集群不死就不会死)—> Pod app=tomcat (Deployment-T 控制器高可用)
b.LoadBalancer 云上高可用

1.Kubernetes 集群的 API Server 向云厂商提供的 api 接口提供创建负载均衡的请求
2.云厂商通过 API 收到请求后会自动创建 负载均衡 LAAS (负载均衡即服务)与后端应用的服务 Service NodePort 进行关联
(5)ExternalName

1.集群外部安装两个 MySqL,一个用于测试 Test DB,一个用于生产 Stable DB
2.集群中应用 Pod app 刚开始连接测试 Test DB 数据库,经过测试轮后,上线需要连接生产 Stable DB
3.当应用 Pod app 过多时,该怎样修改连接后端的数据库呢?1.一个一个改?2.重新封装镜像?3....(或许下一章存储的 ConfigMap 可以解决?)
4.基于当前集群的 CoreDNS 进行解析,可以创建 Service 的 ExternalName,ExternalName名、所在名字空间下、后端的域名或 IP(代理的集群外部域名或 IP)
5.应用 Pod app 连接解析 Service ExternalName 创建的默认域名,格式是 db.default.svc.cluster.local. 从而连接对应的 IP 地址,通过 kubectl edit 修改资源中的 IP 地址,实现连接不同环境数据库
6.底层通过 DNS 别名机制实现( 给 ExternalName 一个域名让其解析 IP,ExternalName 返回另一个域名或 IP ),并非依靠 IPVS 实现
(6)组件协同

1.kubectl 命令行发送命令给集群主节点 master 的 ApiServer
2.ApiServer 验证安全后,将信息存储到 ETCD 数据库中
3.kube-proxy 时时监听 ApiServer,发现有 Service 的创建
4.kube-proxy 会落对应的 ipvs 规则(底层是 ipvs 落 ipvs 规则、底层是 iptables 落 iptables 规则)
(7)IPVS 的工作模式
NAT:优点:后端端口和集群端口可以不一样、缺点:当前的流量必须经过 ipvs 调度器( kube-proxy 采用的工作模式 )
DR: 优点:回程流量不需要经过负载 ipvs 调度器,压力小、缺点:1.需要对当前 ARP 响应和 通况行为做设定。2.后端端口和集群端口必须一致
TUN(隧道模式):优点:可以跨公网网络进行集聚化组建、缺点:性能低,需要跨多个物理公网环境,还需对数据报文二次封装
6.2.2 ClusterIP
(1)ClusterIP 结构

1.前端 Pod nginx 通过配置文件绑定 Service 的 IP,连接 Service
2.Service 通过标签匹配相同标签的后端 Pod 进行负载
3.后端 Pod 通过标签被 Deployment 控制器所管理,有死亡会重构一个容器,Service 会剔除死亡容器
4.新容器被 Deployment 所重构,会有 Deployment 固定的标签印记,再被 Service 匹配,添加到负载集群( Pod 已就绪、同一名称空间下)
(2)ClusterIP
# 创建 Deployment 控制器 [root@k8s-master01 7]# cat 1.clusterip-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-clusterip-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: stabel svc: clusterip template: metadata: labels: app: myapp release: stabel env: test svc: clusterip spec: containers: - name: myapp-container image: myapp:v1.0 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 periodSeconds: 3
4.期望:副本数:选择器:Deployment 标签、标签值、Pod 模板:元数据:Pod 标签:标签、标签值、Pod 期望:容器组:容器名、基于镜像版本、镜像拉取策略、端口:端口名称、端口值、就绪探测:http 探针、探测端口值、探测路径、延迟检测时间1秒、每间隔3秒重复探测
# 创建 ClusterIP 的 service [root@k8s-master01 7]# cat 1.service.yaml apiVersion: v1 kind: Service metadata: name: myapp-clusterip namespace: default spec: type: ClusterIP selector: app: myapp release: stabel svc: clusterip ports: - name: http port: 80 targetPort: 80
1.接口组版本:核心组 v1 版 2.类别:Service 类 3.元数据:Service 名称、所属名称空间 4.期望:Service 类型(默认)、选择器:标签、标签值、端口:端口名称、负载均衡端口值、后端真实服务器的端口值
(3)ClusterIP 使用 IP 方式访问
# 第一种访问 Service IP 的方式 # 创建 deployment 和 service 资源清单 [root@k8s-master01 7]# kubectl create -f 1.service.yaml service/myapp-clusterip created [root@k8s-master01 7]# kubectl apply -f 1.clusterip-deploy.yaml deployment.apps/myapp-clusterip-deploy created # 探针显示需要检测 index1.html ,所以未就绪 [root@k8s-master01 7]# kubectl get pod NAME READY STATUS RESTARTS AGE myapp-clusterip-deploy-7bbd4cf949-595dh 0/1 Running 0 7s myapp-clusterip-deploy-7bbd4cf949-ctfgd 0/1 Running 0 7s myapp-clusterip-deploy-7bbd4cf949-v49vt 0/1 Running 0 7s # CLUSTER-IP 是 ipvs 创建集群负载的 虚拟 VIP [root@k8s-master01 7]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 14d myapp-clusterip ClusterIP 10.8.136.182 <none> 80/TCP 25s # 因为 Pod 未就绪,所以 service 未将其归为负载,访问失败,验证只有启动成功才会将其归为负载 [root@k8s-master01 7]# curl 10.8.136.182 curl: (7) Failed to connect to 10.8.136.182 port 80: Connection refused # 由 ipvs 创建的虚拟 VIP 10.8.136.182 后端没有负载 [root@k8s-master01 7]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) .......... TCP 10.8.136.182:80 rr .......... # 添加一个就绪探测,满足探针要求 [root@k8s-master01 7]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-clusterip-deploy-7bbd4cf949-595dh 0/1 Running 0 9m1s 10.244.58.225 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-ctfgd 0/1 Running 0 9m1s 10.244.58.223 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-v49vt 0/1 Running 0 9m1s 10.244.85.217 k8s-node01 <none> <none> [root@k8s-master01 7]# kubectl exec -it myapp-clusterip-deploy-7bbd4cf949-595dh -- /bin/sh / # cd /usr/share/nginx/html/ /usr/share/nginx/html # date > index1.html /usr/share/nginx/html # ls 50x.html index.html index1.html /usr/share/nginx/html # exit [root@k8s-master01 7]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-clusterip-deploy-7bbd4cf949-595dh 1/1 Running 0 10m 10.244.58.225 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-ctfgd 0/1 Running 0 10m 10.244.58.223 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-v49vt 0/1 Running 0 10m 10.244.85.217 k8s-node01 <none> <none> # 可以访问,并且访问的 Pod 与就绪的 Pod 名一致 [root@k8s-master01 7]# curl 10.8.136.182 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a> [root@k8s-master01 7]# curl 10.8.136.182/hostname.html myapp-clusterip-deploy-7bbd4cf949-595dh # Pod 的 ip 也被 ipvs 加入到负载的路由规则中 [root@k8s-master01 7]# ipvsadm -Ln .......... TCP 10.8.136.182:80 rr -> 10.244.58.225:80 Masq 1 0 2 ..........
(4)ClusterIP 使用内部域名方式访问
# 安装解析工具 [root@k8s-master01 7]# yum -y install bind-utils .......... Complete! # kubernetes 集群中 dns 解析 涉及的两个 Pod 组件 [root@k8s-master01 ~]# kubectl get pod -o wide -n kube-system|grep dns coredns-857d9ff4c9-ftpzf 1/1 Running 17 (7h51m ago) 14d 10.244.32.168 k8s-master01 <none> <none> coredns-857d9ff4c9-pzjfv 1/1 Running 17 (7h51m ago) 14d 10.244.32.167 k8s-master01 <none> <none> # 路由规则将两个 dns 的 IP地址 添加到负载中,有tcp、udp 两种,默认 tcp 用于数据同步,udp 用于解析(如果 udp 多次解析不通过,也会允许 tcp 解析) [root@k8s-master01 ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) ......... TCP 10.0.0.10:53 rr -> 10.244.32.167:53 Masq 1 0 0 -> 10.244.32.168:53 Masq 1 0 0 UDP 10.0.0.10:53 rr -> 10.244.32.167:53 Masq 1 0 0 -> 10.244.32.168:53 Masq 1 0 0 ......... # -t tcp进行解析、A 记录、myapp-clusterip.defalut.svc.cluster.local. 集群内域名方式,cluster.local 是默认的,安装时可以修改、@ 解析地址 [root@k8s-master01 7]# dig -t A myapp-clusterip.default.svc.cluster.local @10.244.32.168 ; <<>> DiG 9.16.23-RH <<>> -t A myapp-clusterip.default.svc.cluster.local @10.244.32.168 ;; 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: 45205 ;; 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: 5f3467e5c0408c8b (echoed) ;; QUESTION SECTION: ;myapp-clusterip.default.svc.cluster.local. IN A ;; ANSWER SECTION: myapp-clusterip.default.svc.cluster.local. 25 IN A 10.8.136.182 ;; Query time: 3 msec ;; SERVER: 10.244.32.168#53(10.244.32.168) ;; WHEN: Wed Jun 11 16:38:29 CST 2025 ;; MSG SIZE rcvd: 139 # 解析的地址和 Svc 的地址一致,k8s 集群中默认使用 CoreDns 进行解析 [root@k8s-master01 7]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 14d myapp-clusterip ClusterIP 10.8.136.182 <none> 80/TCP 36m # 再启动一个 Pod ,充当客户端 [root@k8s-master01 7]# cat pod.demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default spec: containers: - name: pod-demo image: busybox:1.28.1 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","sleep 3600;"] [root@k8s-master01 7]# kubectl create -f pod.demo.yaml pod/pod-demo created [root@k8s-master01 7]# kubectl get pod NAME READY STATUS RESTARTS AGE myapp-clusterip-deploy-7bbd4cf949-595dh 1/1 Running 0 44m myapp-clusterip-deploy-7bbd4cf949-ctfgd 0/1 Running 0 44m myapp-clusterip-deploy-7bbd4cf949-v49vt 0/1 Running 0 44m pod-demo 1/1 Running 0 4s # 进入 pod-demo Pod 内,可以直接通过域名方式浏览 svc 负载的 Pod,k8s 默认使用 coreDNS 进行解析, [root@k8s-master01 7]# kubectl exec -it pod-demo -- /bin/sh / # wget http://myapp-clusterip.default.svc.cluster.local./hostname.html && cat hostname.html && rm -rf hostname.html Connecting to myapp-clusterip.default.svc.cluster.local. (10.8.136.182:80) hostname.html 100% |********************************************************************************************************************************************************************************************| 40 0:00:00 ETA myapp-clusterip-deploy-7bbd4cf949-595dh
利弊分析:
Service IP 方式:优点:1.可以直接查看 IP 地址、2.不需要拼写很长一段域名。缺点: Service 没有创建出来是不知道 IP 地址。(IP 更简单)
Service 域名方式:优点:1.即使 Service 未创建也可以提前在组件中写固定域名。缺点:需要拼很长一段地址域名。(域名 更前置化)
域名拼写方式:svcName.nsName.svc.domainName.
domainName:默认是 cluster.local
(5)ClusterIP local 方式
[root@k8s-master01 ~]# kubectl explain svc.spec.internalTrafficPolicy KIND: Service VERSION: v1 FIELD: internalTrafficPolicy <string> 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@k8s-master01 ~]# kubectl get svc -o yaml .......... spec: clusterIP: 10.0.0.1 clusterIPs: - 10.0.0.1 internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - name: https port: 443 protocol: TCP targetPort: 6443 sessionAffinity: None type: ClusterIP ..........
当前集群 master01、node01、node02 三个节点都可以访问,都可以 curl 并且三个节点都可以访问两个就绪的 Pod

[root@k8s-master01 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 15d myapp-clusterip ClusterIP 10.8.136.182 <none> 80/TCP 23h [root@k8s-master01 ~]# kubectl edit svc myapp-clusterip ......... internalTrafficPolicy: Local ......... service/myapp-clusterip edited [root@k8s-master01 ~]#

# 通过上面的案例,master01 和 node01 都无法访问 Pod,node02 可以访问 Pod
# 将另外一个 Pod 准备成就绪 [root@k8s-master01 ~]# kubectl exec -it myapp-clusterip-deploy-7bbd4cf949-v49vt -- /bin/sh / # cd /usr/share/nginx/html/ /usr/share/nginx/html # date > index1.html /usr/share/nginx/html # exit [root@k8s-master01 ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-clusterip-deploy-7bbd4cf949-595dh 1/1 Running 1 (6h32m ago) 23h 10.244.58.228 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-ctfgd 1/1 Running 1 (6h32m ago) 23h 10.244.58.229 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-v49vt 1/1 Running 1 (6h32m ago) 23h 10.244.85.219 k8s-node01 <none> <none> pod-demo 1/1 Running 7 (31m ago) 22h 10.244.58.231 k8s-node02 <none> <none> # maste01 仍旧不能访问,node01 节点可以访问,并且持续是同一个Pod,node02节点可以访问,也是两个Pod的循环 [root@k8s-master01 ~]# curl 10.8.136.182 curl: (7) Failed to connect to 10.8.136.182 port 80: Connection refused
[root@k8s-node01 ~]# curl 10.8.136.182 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a> [root@k8s-node01 ~]# curl 10.8.136.182/hostname.html myapp-clusterip-deploy-7bbd4cf949-v49vt [root@k8s-node01 ~]# curl 10.8.136.182/hostname.html myapp-clusterip-deploy-7bbd4cf949-v49vt [root@k8s-node01 ~]# curl 10.8.136.182/hostname.html myapp-clusterip-deploy-7bbd4cf949-v49vt
Local:只会路由所在节点的 Pod,master01 路由启动在 master01 上的 Pod、node01 路由启动在 node01 上的 Pod、node02 路由启动在 node02 上的 Pod。
Master01 上没有 Pod 所以访问不通,Node01 上只有一个 Pod,所以一直访问 Node01 上的 Pod,node02 上有两个 Pod ,所以可以完成两个 Pod 的负载。
(6)LVS 持久化连接
ipvsadm -A -t 192.168.66.100:80 -s rr -p 120
应用场景:HTTPS 请求
可以定义连接时长,在 120 秒内,后端连接持久化,在这之间,再建立连接,继续更新成 120 秒,当时间耗尽,重新负载,继续遵循 120 秒持久化连接(因为每次建立新的连接会需要认证等一系列操作,会话保持可以节省时间和节省资源 )
对比 SH ,遵循 hash 算法,只有 hash 值到期,才会重新负载
# 会话时间 在 0-86400s 之间,默认 10800s [root@k8s-master01 ~]# kubectl explain service.spec.sessionAffinityConfig.clientIP KIND: Service VERSION: v1 FIELD: clientIP <ClientIPConfig> DESCRIPTION: clientIP contains the configurations of Client IP based session affinity. ClientIPConfig represents the configurations of Client IP based session affinity. FIELDS: timeoutSeconds <integer> timeoutSeconds specifies the seconds of ClientIP type session sticky time. The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP". Default value is 10800(for 3 hours). # 修改如下配置,基于上个实验把 local 改回 ClientIP,增加会话配置和会话时间 [root@k8s-master01 7]# kubectl edit svc myapp-clusterip .......... spec: internalTrafficPolicy: Cluster .......... sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 60 type: ClusterIP .......... [root@k8s-master01 ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 15d myapp-clusterip ClusterIP 10.11.111.192 <none> 80/TCP 15m # 这里正常是保持会话时间 60 秒,但是可能不支持这么小的,实验老师使用的是 10800,也可以将时间调整成 10800 [root@k8s-master01 ~]# for i in `seq 10`;do curl 10.11.111.192/hostname.html;sleep 65;done # 查看 路由规则,只有添加会话保持的有 保持时长 ipvsadm -lnc,可以查看会话保持剩余时间 [root@k8s-master01 7]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn ......... TCP 10.11.111.192:80 rr persistent 60 -> 10.244.58.228:80 Masq 1 0 0 -> 10.244.58.229:80 Masq 1 0 0 -> 10.244.85.219:80 Masq 1 0 2 .........
6.2.3 NodePort
(1)NodePort 结构

1.集群外通信可以使用 NodePort,如果是集群内,更建议使用 ClusterIP
2.NodePort 是一种升级版的 ClusterIP,不仅支持 ClusterIP 拥有的功能,还支持在当前物理网卡上绑定物理端口,以此实现外部访问
3.功能越多,代价越多,如果不需要那么多功能,却开启了,会造成资源浪费
(2)NodePort 实验
# 创建 Deployment
[root@k8s-master01 7]# cat 2.nodepoort.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 env: test svc: nodeport spec: containers: - name: myapp-container image: myapp:v1.0 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80
4.Deployment 控制器期望:副本数、选择器、匹配符:标签、标签值、Pod 模板、Pod 元数据、Pod 标签:标签、标签值、Pod 期望:容器组:容器名、基于镜像版本、镜像拉取策略、端口:端口名、端口值
# 创建 NodePort 类型的 Service
[root@k8s-master01 7]# cat 2.svc.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
1.接口组版本:核心组 v1 版 2.类别:Service 类型 3.元数据:Service 名、Service 所在名称空间 4.期望:Service 类型、Service 选择器:标签、标签值、集群端口:端口名(可以定义多个)、集群内部访问负载调度器端口(ClusterIP 相同)、后端服务端口、集群端口(物理网卡启动的端口、默认是30000以上,理想是不写,集群自动分配)
[root@k8s-master01 7]# kubectl apply -f 2.nodepoort.yaml deployment.apps/myapp-nodeport-deploy created [root@k8s-master01 7]# kubectl apply -f 2.svc.yaml service/myapp-nodeport created [root@k8s-master01 7]# kubectl get deployment,svc,pod -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/myapp-nodeport-deploy 3/3 3 3 71s myapp-container myapp:v1.0 app=myapp,release=stabel,svc=nodeport NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 15d <none> service/myapp-nodeport NodePort 10.9.196.246 <none> 80:30010/TCP 61s app=myapp,release=stabel,svc=nodeport NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/myapp-nodeport-deploy-d56784f8b-62679 1/1 Running 0 71s 10.244.58.242 k8s-node02 <none> <none> pod/myapp-nodeport-deploy-d56784f8b-jjc88 1/1 Running 0 71s 10.244.58.230 k8s-node02 <none> <none> pod/myapp-nodeport-deploy-d56784f8b-rb9r9 1/1 Running 0 71s 10.244.85.224 k8s-node01 <none> <none> # 集群内部访问 [root@k8s-master01 7]# curl 10.9.196.246 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a> # 集群外部访问 [root@k8s-master01 7]# curl 192.168.66.11:30010 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a> # 回环网卡 docker 0 、物理网卡 集群外部 和 集群内部 ipvs 路由规则 [root@k8s-master01 7]# ipvsadm -Ln .......... TCP 172.17.0.1:30010 rr -> 10.244.58.230:80 Masq 1 0 0 -> 10.244.58.242:80 Masq 1 0 0 -> 10.244.85.224:80 Masq 1 0 0 TCP 192.168.66.11:30010 rr -> 10.244.58.230:80 Masq 1 1 0 -> 10.244.58.242:80 Masq 1 1 0 -> 10.244.85.224:80 Masq 1 0 0 .......... TCP 10.9.196.246:80 rr -> 10.244.58.230:80 Masq 1 0 1 -> 10.244.58.242:80 Masq 1 0 0 -> 10.244.85.224:80 Masq 1 0 0 .......... # 集群其他节点node01、node02的 物理网卡和回环网卡也都被分配的路由规则 [root@k8s-node01 ~]# ipvsadm -Ln|grep 30010 TCP 172.17.0.1:30010 rr TCP 192.168.66.12:30010 rr [root@k8s-node02 ~]# ipvsadm -Ln|grep 30010 TCP 172.17.0.1:30010 rr TCP 192.168.66.13:30010 rr
再次验证,通过浏览器可以外部访问集群内部。

(3)NodePort local 方式
[root@k8s-master01 7]# kubectl apply -f 2.nodepoort.yaml deployment.apps/myapp-nodeport-deploy created [root@k8s-master01 7]# kubectl apply -f 2.svc.yaml service/myapp-nodeport created [root@k8s-master01 ~]# kubectl get deploy,svc,pod -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/myapp-nodeport-deploy 3/3 3 3 17h myapp-container myapp:v1.0 app=myapp,release=stabel,svc=nodeport NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16d <none> service/myapp-nodeport NodePort 10.9.196.246 <none> 80:30010/TCP 17h app=myapp,release=stabel,svc=nodeport NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/myapp-nodeport-deploy-d56784f8b-62679 1/1 Running 1 (6h37m ago) 17h 10.244.58.239 k8s-node02 <none> <none> pod/myapp-nodeport-deploy-d56784f8b-jjc88 1/1 Running 1 (6h37m ago) 17h 10.244.58.240 k8s-node02 <none> <none> pod/myapp-nodeport-deploy-d56784f8b-rb9r9 1/1 Running 1 (6h37m ago) 17h 10.244.85.228 k8s-node01 <none> <none>
打开浏览器的无痕模式,每个节点都可以被 30010 端口负载

修改 externalTrafficPolicy: Local 为 Local,再通过浏览器无痕浏览,各节点端口指定固定的服务器,后端没有服务 Pod,返回 找不到网页
[root@k8s-master01 ~]# kubectl edit svc myapp-nodeport
..........
externalTrafficPolicy: Local
..........
service/myapp-nodeport edited

(4)Cluster 和 NodePort 的 Local 流量规则
SVC
CLUSTERIP
internalTrafficPolicy
Cluster:默认值
Local:
流量只会通向访问节点所在的 pod,如果当前节点没有运行 pod ,当前请求会被 Drop 而不是 Reject
NodePort
externalTrafficPolicy
Cluster:默认值
Local:
流量只会通向访问节点所在的 pod,如果当前节点没有运行 pod ,当前请求会被 Drop 而不是 Reject
6.2.4 LoadBalancer
(1)LoadBalancer 结构

1.后端服务器进入 ens33 A物理服务器后,如果 ens33 A 物理服务器死了,用户访问中断
2.在两台 ens33 物理服务器 前端架设调度器 LAAS/cloud provider(内部是自建调度器 LAAS、云上是 cloud provider ,即 Service 使用 LoadBalancer)
(2)LoadBalancer 解读
apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "${YOUR_LOADBALANCER_ID}" service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners: "true" labels: app: nginx name: my-nginx-svc namespace: default spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer
1.接口组版本:核心组 v1 版 2.类别:Service 类 3.元数据:扩展:阿里云id、同意协议、标签:标签、标签值、Service 名、Service 所在名字空间 4.期望:端口:端口号、协议、后端服务器端口号、选择匹配:匹配标签:标签、标签值、Service 类型 annotations:扩展第三方功能,被第三方组件或软件识别后,可以去确认想配置的结果。
6.2.5 ExternalName
(1)ExternalName 结构

ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务
1.Tomcat-pod 直接连接数据库,当数据库地址发生更改,重新构建镜像或每个 Pod 更改 数据库 IP 地址
2.当 Tomcat-pod 使用 CNAME 的域名连接时,CoreDNS 会解析返回 Tomcat-pod 一个 外部地址,然后 Tomcat-pod 去连接提供的地址
(2)ExternalName 实验
# 顺序不影响启动,层级顺序影响,需要遵循 [root@k8s-master01 7]# cat ExternalName.yaml kind: Service apiVersion: v1 metadata: name: my-service-1 namespace: default spec: type: ExternalName externalName: www.baidu.com
1.类别:Service 类 2.接口组版本:核心组 v1 版 3.元数据:Service 名、Service 所在空间下 4.期望:Service 类型 ExternalName、ExternalName 值(外部名)
# 当集群内 Pod 对名为 my-service-1 的 Service 发起内部域名访问(my-service-1.default.svc.cluster.local.),当 Service 是 ExternalName 走内部的 DNS,DNS 会将目标改成 www.baidu.com,DNS 解析 www.baidu.com,再将解析的 IP 返回给 Pod,Pod 再连接 IP 地址
[root@k8s-master01 7]# kubectl apply -f ExternalName.yaml service/my-service-1 unchanged # EXTERNAL-IP 外部的地址 [root@k8s-master01 7]# kubectl get deploy,svc,pod NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16d service/my-service-1 ExternalName <none> www.baidu.com <none> 12s # 启动一个 Pod 充当客户端,在 Pod 内部解析 my-service-1.default.svc.cluster.local. 地址,出现了 百度的 IP(此方法一定是集群内部的 Pod 或组件使用,外部的服务不使用集群内的 DNS 解析) [root@k8s-master01 7]# cat pod.demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default spec: containers: - name: pod-demo image: busybox:1.28.1 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","sleep 3600;"] [root@k8s-master01 7]# kubectl apply -f pod.demo.yaml pod/pod-demo created [root@k8s-master01 7]# kubectl get pod NAME READY STATUS RESTARTS AGE pod-demo 1/1 Running 0 7s [root@k8s-master01 7]# kubectl exec -it pod-demo -- /bin/sh / # ping my-service-1.default.svc.cluster.local. PING my-service-1.default.svc.cluster.local. (110.242.70.57): 56 data bytes 64 bytes from 110.242.70.57: seq=0 ttl=126 time=25.845 ms 64 bytes from 110.242.70.57: seq=1 ttl=126 time=13.433 ms 64 bytes from 110.242.70.57: seq=2 ttl=126 time=13.733 ms ^C --- my-service-1.default.svc.cluster.local. ping statistics ---

6.3 Endpoints
—— Service 的底层模型
(1)Endpoints 与 Service 和 Pod 间的关联

Kubernetes 中的 Service,它定义了一组 Pods 的逻辑集合和一个用于访问它们的策略。一个 Service 的目标 Pod 集合通常是由 Label Selector 来决定的。
Endpoints 是一组实际服务的端点集合。一个 Endpoints 是一个可被访问的服务端点,即一个状态为 running 的 pod 的可访问端点。一般 Pod 都不是一个独立存在,所以一组 Pod 的端点合在一起称为 Endpoints。只有被 Service Selector 匹配选中并且状态为 Running 的才会被加入到和 Service 同名的 Endpoints 中。
(2)自动关联体系:配置 selector

1.k8s 内部通过 svc 发起请求,真实请求被导向到标签匹配的 Pod或其他服务 上(分配原理基于ipvs、rr、nat)
2.当 Service 被定义一个标签选择器后,标签选择器动态监测符合需求的 Pod,并将符合 Pod 的 IP 抓取到资源对象 endpoints 中
3.endpoints 名和 Service 名相同,kubelet 将当前的 endpoints 维护到当前所在节点的 ipvs 中既可
# 以下 1.clusterip-deploy.yaml 1.service.yaml 均是上面clusterip 中实验所使用的 [root@k8s-master01 7]# kubectl apply -f 1.clusterip-deploy.yaml deployment.apps/myapp-clusterip-deploy created [root@k8s-master01 7]# kubectl get deployment,svc,endpoints,pod NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/myapp-clusterip-deploy 0/3 3 0 22s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16d NAME ENDPOINTS AGE endpoints/kubernetes 192.168.66.11:6443 16d NAME READY STATUS RESTARTS AGE pod/myapp-clusterip-deploy-7bbd4cf949-7q2pd 0/1 Running 0 22s pod/myapp-clusterip-deploy-7bbd4cf949-cdm7k 0/1 Running 0 22s pod/myapp-clusterip-deploy-7bbd4cf949-llxfg 0/1 Running 0 22s # 使 其中一个 Pod 满足就绪条件 [root@k8s-master01 7]# kubectl exec -it pod/myapp-clusterip-deploy-7bbd4cf949-7q2pd -- /bin/sh -c "date > /usr/share/nginx/html/index1.html" [root@k8s-master01 7]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-clusterip-deploy-7bbd4cf949-7q2pd 1/1 Running 0 3m58s 10.244.85.233 k8s-node01 <none> <none> myapp-clusterip-deploy-7bbd4cf949-cdm7k 0/1 Running 0 3m58s 10.244.58.243 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-llxfg 0/1 Running 0 3m58s 10.244.58.245 k8s-node02 <none> <none> # 创建 service , 发现自动创建了同名的 endpoints,并且绑定了已就绪的 Pod 的 IP [root@k8s-master01 7]# kubectl apply -f 1.service.yaml service/myapp-clusterip created [root@k8s-master01 7]# kubectl get svc,endpoints NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16d service/myapp-clusterip ClusterIP 10.14.149.181 <none> 80/TCP 11s NAME ENDPOINTS AGE endpoints/kubernetes 192.168.66.11:6443 16d endpoints/myapp-clusterip 10.244.85.233:80 11s # 再就绪一个 Pod,发现 endpoints 又绑定了 Pod 的 IP [root@k8s-master01 7]# kubectl exec -it myapp-clusterip-deploy-7bbd4cf949-cdm7k -- /bin/sh -c "date > /usr/share/nginx/html/index1.html" [root@k8s-master01 7]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-clusterip-deploy-7bbd4cf949-7q2pd 1/1 Running 0 8m22s 10.244.85.233 k8s-node01 <none> <none> myapp-clusterip-deploy-7bbd4cf949-cdm7k 1/1 Running 0 8m22s 10.244.58.243 k8s-node02 <none> <none> myapp-clusterip-deploy-7bbd4cf949-llxfg 0/1 Running 0 8m22s 10.244.58.245 k8s-node02 <none> <none> [root@k8s-master01 7]# kubectl get endpoints NAME ENDPOINTS AGE kubernetes 192.168.66.11:6443 16d myapp-clusterip 10.244.58.243:80,10.244.85.233:80 2m14s
(3)手动关联体系:未配置 selector

1.k8s 内部通过 svc 发起请求,真实请求被导向到标签匹配的 Pod或其他服务 上(分配原理基于ipvs、rr、nat)
2.管理员手动创建 Service 同名 endpoints ,动态监测符合需求的 Pod,并将符合 Pod 的 IP 抓取到资源对象 endpoints 中
3.endpoints 名和 Service 名相同,kubelet 将当前的 endpoints 维护到当前所在节点的 ipvs 中既可
[root@k8s-master01 7]# cat 3.noselect.yaml apiVersion: v1 kind: Service metadata: name: nginx-noselectt spec: ports: - protocol: TCP port: 6666 targetPort: 80
4.期望:端口:端口协议、集群端口值、后端服务的端口值
[root@k8s-master01 7]# kubectl apply -f 3.noselect.yaml service/nginx-noselectt created # 并未创建 service 同名的 endpoints [root@k8s-master01 7]# kubectl get svc,endpoints NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16d service/nginx-noselectt ClusterIP 10.1.214.208 <none> 6666/TCP 105s NAME ENDPOINTS AGE endpoints/kubernetes 192.168.66.11:6443 16d # 查看 ipvs 的路由规则,并没有后端的 IP 规则 [root@k8s-master01 7]# ipvsadm -Ln .......... TCP 10.1.214.208:6666 rr ..........
[root@k8s-master01 7]# cat 3.endpoints.yaml apiVersion: v1 kind: Endpoints metadata: name: nginx-noselectt subsets: - addresses: - ip: 192.168.66.12 ports: - port: 80
1.接口组版本:核心组 v1 版 2.类别:Endpoints 类 3.元数据:Endpoints 资源名称 4.指定地址:目标地址:ip、目标端口:端口值
[root@k8s-master01 7]# kubectl apply -f 3.endpoints.yaml endpoints/nginx-noselectt created # 增加 endpoints ,查看路由规则,是自己定义的 路由规则 [root@k8s-master01 7]# kubectl get svc,ep NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 16d service/nginx-noselectt ClusterIP 10.1.214.208 <none> 6666/TCP 40m NAME ENDPOINTS AGE endpoints/kubernetes 192.168.66.11:6443 16d endpoints/nginx-noselectt 192.168.66.12:80 34m [root@k8s-master01 7]# ipvsadm -Ln .......... TCP 10.1.214.208:6666 rr -> 192.168.66.12:80 Masq 1 0 0 .......... # 在 node01 节点启动一个容器,可以通过 service 访问固定的 集群内或外部的地址 [root@k8s-master01 7]# curl 10.1.214.208:6666 curl: (7) Failed to connect to 10.1.214.208 port 80: Connection refused [root@k8s-node01 ~]# docker run -d --name nginx -p 80:80 myapp:v1.0 9faa478eba57fde0e396cff2fc0fcce3f1df41d4ebf50c27deb1191e647904c8 [root@k8s-master01 7]# curl 10.1.214.208:6666 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
(4) endpoints 总结
Service endpoints
有标签选择器
自动创建一个同名的 endpoints 资源对象
匹配对象
当前名字空间中的 pod
标签子集运算
就绪的
没有定义标签选择器
不会创建同名的 endpoints 资源对象,需要管理员手动创建
匹配对象
管理员填写的端点信息
6.4 publishNotReadyAddresses
—— 一点点小特殊
1.默认是就绪才会添加负载,但是当遇到特殊情况,也可以未就绪也能被负载
(1)publishNotReadyAddresses
[root@k8s-master01 7]# cat readiness-httpget-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: myapp:v1.0 imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 periodSeconds: 3
4.期望:容器组:容器名、基于镜像版本、镜像拉取策略、就绪探测:httpGet 探针:端口、路径、延迟时间、间隔时间
[root@k8s-master01 7]# cat publishNotReadyAddresses.yaml apiVersion: v1 kind: Service metadata: labels: app: myapp name: myapp spec: ports: - name: 80-80 port: 80 protocol: TCP targetPort: 80 selector: app: myapp type: ClusterIP
[root@k8s-master01 7]# kubectl apply -f readiness-httpget-pod.yaml pod/readiness-httpget-pod created [root@k8s-master01 7]# kubectl apply -f publishNotReadyAddresses.yaml service/myapp created [root@k8s-master01 7]# kubectl get svc,pod -o wide NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 17d <none> service/myapp ClusterIP 10.4.155.246 <none> 80/TCP 91s app=myapp NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/readiness-httpget-pod 0/1 Running 0 5m48s 10.244.58.247 k8s-node02 <none> <none> # 访问不成功,因为 Pod 未就绪,Service 未将其添加到负载中 [root@k8s-master01 7]# curl 10.4.155.246 curl: (7) Failed to connect to 10.4.155.246 port 80: Connection refused # 添加参数,增加 publishNotReadyAddresses 参数 [root@k8s-master01 7]# kubectl edit svc myapp .......... spec: publishNotReadyAddresses: true .......... service/myapp edited # 修改后, Pod 虽然仍未就绪,但是可以通过 Service 进行访问 # 也可以使用打补丁的方式添加 publishNotReadyAddresses 参数, kubectl patch service myapp -p '{"spec":{"publishNotReadyAddresses": true}}' [root@k8s-master01 7]# kubectl get pod NAME READY STATUS RESTARTS AGE readiness-httpget-pod 0/1 Running 0 9m45s [root@k8s-master01 7]# curl 10.4.155.246 Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
———————————————————————————————————————————————————————————————————————————
无敌小马爱学习
浙公网安备 33010602011771号