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:扩展第三方功能,被第三方组件或软件识别后,可以去确认想配置的结果。

官方文档:https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/use-an-existing-slb-instance-to-expose-an-application

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>

———————————————————————————————————————————————————————————————————————————

                                                                                                                         无敌小马爱学习

posted on 2025-05-28 16:03  马俊南  阅读(196)  评论(0)    收藏  举报