【K8s】05 - Service
文章目录
1:Service概述
Service引入主要是解决Pod的动态变化,提供统一的访问入口:
- 1、防止Pod失联,准备找到提供同一服务的Pod**(服务发现)**
- 2、定义一组Pod的访问策略**(负载均衡)**
Service通常是通过Label Selector访问一组Pod

其实 Service 只是一个概念,真正起到转发数据的是 kube-proxy 服务进程
kube-proxy 是集群中每个节点上运行的网络代理,每个节点之上都运行一个 kube-proxy 服务进程
当创建 Service 的时候,首先API Server向 etcd 写入 Service 的信息
然后kube-proxy会监听API Server,监听到 etcd 中 Service 的信息,然后根据Service的信息生成对应的访问规则

二:Endpoint
Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个Service对应的所有Pod的访问地址
它是根据Service配置文件中的label selector(标签选择器)生成的
一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来,Endpoints是实现实际服务的端点集合
换言之,Service和Pod之间的联系是通过Endpoints实现的
当我们创建Service的时候,如果Service有指定Label Selector的话,Endpoints控制器会自动创建一个名称跟Service名称一致的Endpoint对象
可简单理解为 => Endpoint是一个中间对象,用来存放Service与Pod的映射关系
在Endpoint中,可以看到,当前能正常提供服务的Pod以及不能正常提供的Pod
$ kubectl get pod -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-7f456874f4-c7224 1/1 Running 0 20m 192.168.1.3 node01 <none> <none> app=nginx,pod-template-hash=7f456874f4
nginx-7f456874f4-v8pnz 1/1 Running 0 20m 192.168.0.6 controlplane <none> <none> app=nginx,pod-template-hash=7f456874f4
$ kubectl get svc -o wide # 查看service列表
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 14d <none>
nginx ClusterIP 10.109.113.53 <none> 80/TCP 12m app=nginx
$ kubectl get ep # 查看endpoint列表,发现和service的名称一致,说明上面的两个service都指定了Label Selector
NAME ENDPOINTS AGE
kubernetes 172.30.1.2:6443 14d
nginx 192.168.0.6:80,192.168.1.3:80 12m
# 查看endpoint资源清单
$ kubectl get ep nginx -o yaml

三:Service的类型
ClusterIP
只能在集群内部访问,默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP(即VIP)
NodePort
在每个主机节点上启用一个端口来暴露服务,可以在集群外部访问,也会分配一个稳定内部集群IP地址。
访问地址:<任意Node节点的IP地址>: NodePort端口,默认NodePort端口范围:30000-32767,将外部流量路由到集群内部的服务
NodePort提供了一种简单的方式来从集群外部访问集群内部的服务,无需依赖外部负载均衡器或Ingress控制器
工作原理:
- 创建Service:当创建一个type为NodePort的Service时,Kubernetes会自动在每个节点上分配一个端口(30000-32767),并将该端口映射到Service的port和targetPort上。
- 流量路由:外部流量可以通过任何节点的IP地址和NodePort端口访问Service。kube-proxy负责将流量从NodePort端口转发到后端的Pod。
- 负载均衡:需要注意的是,NodePort本身不提供负载均衡功能。流量会直接到达接收请求的节点的首个Pod
优点:
- 简单易用:无需依赖外部负载均衡器或Ingress控制器,配置简单。
- 灵活性高:可以在任何云环境下使用,不受云平台限制。
缺点:
- 端口管理复杂:当集群中运行大量服务时,NodePort的端口管理会变得复杂且容易冲突。
- 负载均衡能力有限:NodePort本身不提供负载均衡功能,可能会导致流量分布不均
使用场景:
- 测试环境:在测试环境中,NodePort可以作为快速暴露服务的一种方式,方便开发和测试人员进行访问。
- 非生产环境:在不需要复杂负载均衡和SSL终止等高级功能的非生产环境中,NodePort可以作为一种简单的服务暴露方式。
LoadBalancer
K8s LoadBalancer 是一种 Service 类型,它允许将请求从外部负载均衡器分发到集群内部的服务上。
这通常通过云提供商的负载均衡服务来实现,为 Service 分配一个外部 IP 地址,并将流量路由到集群内的服务实例
提高系统的可用性和稳定性,通过平均分配请求到多个后端服务实例上,减轻单一服务的压力,防止单点故障
工作原理:
- 请求流程:外部请求首先到达云提供商的负载均衡器,然后负载均衡器根据配置的负载均衡算法(如轮询、加权轮询、IP Hash 等)将请求转发到集群中的某个节点上。节点上的 kube-proxy 组件会进一步将请求转发到对应的 Pod 上。
- 负载均衡算法:LoadBalancer 使用的具体负载均衡算法可能因集群环境和云提供商的不同而有所差异。常见的算法包括轮询、加权轮询和 IP Hash 等

使用场景:
- 生产环境:在生产环境中,当需要将 Web 应用程序等服务暴露给外部用户时,可以使用 LoadBalancer 来实现。这样,外部用户可以通过访问负载均衡器的外部 IP 地址来访问服务,而无需直接访问集群内部的节点或 Pod。
- 高可用性和扩展性:通过 LoadBalancer,可以轻松地实现服务的高可用性和扩展性。当服务需要扩容时,只需增加更多的 Pod,LoadBalancer 会自动将请求分发到新的 Pod 上。
配置和部署:
- 前提条件:要使用 LoadBalancer,首先需要确保 Kubernetes 集群支持 LoadBalancer,并且集群已经连接到云提供商的负载均衡服务。
- 安装 LoadBalancer Controller:在 Kubernetes 中,LoadBalancer 是通过 Controller 来管理和配置的。一些云提供商会提供自己的 LoadBalancer Controller,如 AWS 的 ELB Controller、GCP 的 GCE Controller 等。对于私有云或混合云环境,可能需要部署额外的组件(如 MetalLB)来提供 LoadBalancer 功能。
- 创建 Service:在 Kubernetes 中,需要创建一个类型为 LoadBalancer 的 Service 来定义负载均衡器的行为。
注意事项:
- 成本问题:使用云提供商的 LoadBalancer 服务可能会产生额外的费用,具体费用取决于云提供商的定价策略和负载均衡器的使用情况。
- 安全性:当将服务暴露给外部用户时,需要注意安全性问题。建议配置适当的安全组规则、网络策略等来控制访问权限。
- 依赖云提供商:LoadBalancer 的实现高度依赖于云提供商的服务,因此在不同云提供商之间迁移时可能会遇到兼容性问题
四:Service资源清单
yaml 格式的 Service 定义文件 :kubectl get svc nginx -o yaml
apiVersion: v1 # 版本号
kind: Service # 资源类型,固定值Service
metadata: # 元数据
creationTimestamp: "2022-12-29T08:46:28Z"
labels: # 自定义标签属性列表
app: nginx # 标签:app=nginx
name: nginx # Service名称
namespace: default # Service所在的命名空间,默认值为default
resourceVersion: "2527"
uid: 1770ab42-bd33-4455-a190-5753e8eac460
spec:
# 虚拟服务的IP地址,当spec.type=ClusterIP时,如果不指定,则系统进行自动分配,也可以手工指定。
# 当spec.type=LoadBalancer时,则需要指定
clusterIP: 10.102.82.102
clusterIPs:
- 10.102.82.102
externalTrafficPolicy: Cluster
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4 # 使用的ipv4
ipFamilyPolicy: SingleStack
ports: # Service需要暴露的端口列表
- nodePort: 30314 # 当spec.type=NodePort时,指定映射到物理机的端口号
port: 80 # 服务监听的端口号
protocol: TCP # 端口协议,支持TCP和UDP,默认值为TCP
targetPort: 80 # 需要转发到后端Pod的端口号
selector: # label selector配置,将选择具有指定label标签的pod作为管理范围
app: nginx # 选择具有app=nginx的pod进行管理
sessionAffinity: None # session亲和性,可选值为ClientIP,表示将同一个源IP地址的客户端访问请求都转发到同一个后端Pod。默认值为空【None】
type: NodePort # Service的类型,指定service的访问方式,默认值为ClusterIP。取值范围:[ClusterIP、NodePort、LoadBalancer]
status:
loadBalancer: {} # 当spec.type=LoadBalancer时,设置外部负载均衡器的地址,用于公有云环境
五:Service服务暴露
1:ClusterIP示例
1.1:定义Pod资源清单
总的来说,这段配置文件定义了一个名为nginx的Deployment,它使用官方nginx镜像创建了两个副本的Pod
每个Pod都暴露了一个TCP协议的80端口,并且这些Pod都带有app=nginx的标签,以便被Deployment管理
apiVersion: apps/v1 # 指定了使用的Kubernetes API版本为apps/v1,这是用于部署(Deployments)、有状态集(StatefulSets)等应用的API版本
kind: Deployment # 指明了Kubernetes资源的类型为Deployment。Deployment用于声明式地更新应用和服务
metadata: # 包含了该Deployment的元数据
name: nginx # 定义了Deployment的名称,这里为nginx
spec: # 包含了Deployment的规格说明
replicas: 2 # 指定了Pod的副本数量为2,即Kubernetes会尝试运行两个相同的Pod实例
selector: # 用于选择哪些Pod应该被这个Deployment管理
matchLabels: # 通过标签选择器来找到对应的Pod。
app: nginx # 这里它指定了app: nginx,意味着所有带有app=nginx标签的Pod都会被这个Deployment管理
template: # 定义了Pod的模板,即Deployment应该如何创建新的Pod
metadata: # Pod模板的元数据。
labels:
app: nginx # 定义了Pod的标签,这里同样为app: nginx,以确保这些Pod能被Deployment的selector选中
spec: # Pod的规格说明。
containers: # 定义了Pod中容器的列表
- name: nginx # 容器的名称,这里为nginx
image: nginx # 容器使用的镜像,这里使用官方提供的nginx镜像。
ports: # 定义了容器需要暴露的端口。
- containerPort: 80 # 容器内部监听的端口号为80
protocol: TCP # 指定了端口使用的协议为TCP
1.2:创建Pod并进行测试
$ kubectl apply -f clusterip-pod.yaml # 通过yaml进行应用 -f -> file
deployment.apps/nginx created
$ kubectl get pod -o wide # 查看pod列表,-o wide是展示更多的信息
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7f456874f4-c7224 1/1 Running 0 13s 192.168.1.3 node01 <none> <none>
nginx-7f456874f4-v8pnz 1/1 Running 0 13s 192.168.0.6 controlplane <none> <none>
# 任意节点发起请求
$ curl 192.168.1.3
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# 任意节点发起请求
$ curl 192.168.0.6
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
由于pod节点都是nginx默认界面都是一样的,为了方便测试,我们进入Pod修改默认界面:
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7f456874f4-c7224 1/1 Running 0 2m39s 192.168.1.3 node01 <none> <none>
nginx-7f456874f4-v8pnz 1/1 Running 0 2m39s 192.168.0.6 controlplane <none> <none>
$ kubectl exec -it nginx-7f456874f4-c7224 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# echo "hello, this request is from 192.168.1.3" > /usr/share/nginx/html/index.html
#
# cat /usr/share/nginx/html/index.html
hello, this request is from 192.168.1.3
# exit
$ kubectl exec -it nginx-7f456874f4-v8pnz /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
# echo "hello, this request is from 192.168.0.6" > /usr/share/nginx/html/index.html
# cat /usr/share/nginx/html/index.html
hello, this request is from 192.168.0.6
# exit
# 发起请求
$ curl 192.168.1.3
hello, this request is from 192.168.1.3
$ curl 192.168.0.6
hello, this request is from 192.168.0.6
1.3:定义Service资源清单
apiVersion: v1 # 声明使用的版本
kind: Service # 声明资源类型 Service
metadata:
name: nginx # 定义元数据的名称
spec: # 定义Service的规格
selector: # 定义标签选择器,选择指定的app=nginx标签的Pod
app: nginx
type: ClusterIP # 指定Service的类型为ClusterIP,VIP
# clusterIP: 10.109.113.53 # service IP地址 如果不写默认会生成一个
ports:
- port: 80 # service端口
targetPort: 80 # 目标pod端口
1.4:通过清单创建service
$ kubectl apply -f clusterip-svc.yaml # 通过清单创建service
service/nginx created
# 同时我们可以看到,分配的ClusterIP为10.109.113.53
$ kubectl get svc -o wide # svc -> Service 查看Service列表,注意nginx Service中的Selector
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 14d <none>
nginx ClusterIP 10.109.113.53 <none> 80/TCP 15s app=nginx
$ kubectl get pod -o wide # 查看Pod列表[因为这两个Pod都有app=nginx标签,使得Service可以管控这两个,类似于网关门面??]
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7f456874f4-c7224 1/1 Running 0 11m 192.168.1.3 node01 <none> <none>
nginx-7f456874f4-v8pnz 1/1 Running 0 11m 192.168.0.6 controlplane <none> <none>
# 查看svc的详细描述信息,注意Endpoints表示的就是后端真实的Pod服务节点
$ kubectl describe svc nginx
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.109.113.53
IPs: 10.109.113.53
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 192.168.0.6:80,192.168.1.3:80 # 后端真实的Pod服务节点【Pod的IP地址+虚端口】
Session Affinity: None
Events: <none>

如上,我们可以看到,分配的ClusterIP为10.109.113.53,我们可以通过ClusterIP访问:
$ curl 10.109.113.53:80
hello, this request is from 192.168.0.6
$ curl 10.109.113.53:80
hello, this request is from 192.168.1.3
可以看到,发起两次请求,请求会被负载均衡到两个不同的Pod,这就是Service提供的负载均衡功能
2:NodePort示例
$ kubectl create deployment nginx --image=nginx # Deployment声明式地更新应用和服务,搞一个nginx
# 暴露80端口,让集群外部可以访问,Service类型为NodePort
$ kubectl expose deployment nginx --port=80 --type=NodePort
service/nginx exposed
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-748c667d99-5mf49 1/1 Running 0 6m13s 192.168.1.6 node01 <none> <none>
$ kubectl get svc -o wide # 查看Service详细信息
# 可以看到,nginx这个service分配了一个ClusterIP为10.98.224.65,该Service的虚端口为80
# K8S随机分配一个nodePort端口为31853,此时要访问nginx这个服务的话,有两种方式:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 14d <none>
nginx NodePort 10.98.224.65 <none> 80:31853/TCP 6m13s app=nginx
2.1:集群内 - ClusterIP+虚端口
# ClusterIP: 10.98.224.65 虚端口: 80
$ curl 10.98.224.65:80 # clusterIp + 虚拟端口
2.2:集群内 - PodIP+虚端口
$ kubectl get pod -o wide # 查看pod列表
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-748c667d99-5mf49 1/1 Running 0 11m 192.168.1.6 node01 <none> <none>
$ kubectl get svc -o wide # 查看service列表
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 14d <none>
nginx NodePort 10.98.224.65 <none> 80:31853/TCP 11m app=nginx
$ kubectl get ep # 查看endpoint列表,类似于nacos的注册列表??
NAME ENDPOINTS AGE
kubernetes 172.30.1.2:6443 14d
nginx 192.168.1.6:80 11m
# Pod IP地址: 192.168.1.6 虚端口: 80
$ curl 192.168.1.6:80
2.3:集群外 - NodeIP+nodePort
# Node IP地址: 192.168.1.33 nodePort端口: 31853
$ curl 192.168.1.33:31853
3:ExternalName
apiVersion: v1
kind: Service
metadata:
name: externalname-service
spec:
type: ExternalName # Service类型为ExternalName
externalName: www.baidu.com
$ kubectl apply -f externalname-service.yaml
service/externalname-service created
$ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
externalname-service ExternalName <none> www.baidu.com <none> 7s <none>
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17d <none>
$ kubectl describe svc externalname-service
Name: externalname-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ExternalName
IP Families: <none>
IP:
IPs: <none>
External Name: www.baidu.com
Session Affinity: None
Events: <none>
# 查看DNS域名解析
controlplane $ dig @10.96.0.10 externalname-service.default.svc.cluster.local
; <<>> DiG 9.16.1-Ubuntu <<>> @10.96.0.10 externalname-service.default.svc.cluster.local
; (1 server found)
;; 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: 31598
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 085781a8a4291b6d (echoed)
;; QUESTION SECTION:
;externalname-service.default.svc.cluster.local. IN A
;; ANSWER SECTION:
externalname-service.default.svc.cluster.local. 7 IN CNAME www.baidu.com.
www.baidu.com. 7 IN CNAME www.a.shifen.com.
www.a.shifen.com. 7 IN CNAME www.wshifen.com.
www.wshifen.com. 7 IN A 103.235.46.40
;; Query time: 4 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Mon Jan 09 09:43:29 UTC 2023
;; MSG SIZE rcvd: 279
六:Service代理模式
1:UserSpace代理模式
在该模式下 kube-proxy 会为每一个 Service 创建一个监听端口
发送给 Cluseter IP 请求会被 ip_table 重定向给 kube-proxy 监听的端口上
其中 kube-proxy 会根据 LoadBalance 算法将请求转发到相应的pod之上

该模式下,kube-proxy充当了一个四层负载均衡器的角色。
由于kube-proxy运行在userspace中,在进行转发处理的时候会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率非常低下
2:iptables代理模式
iptables模式下 kube-proxy 为每一个pod创建相对应的 iptables 规则,发送给 ClusterIP 的请求会被直接发送给后端pod之上。
在该模式下 kube-proxy 不承担负载均衡器的角色,其只会负责创建相应的转发策略
该模式的优点在于较userspace模式效率更高,但是不能提供灵活的LB策略,当后端Pod不可用的时候无法进行重试。

3:IPVS代理模式
IPVS模式与iptable模式类型,kube-proxy 会根据pod的变化创建相应的IPVS转发规则
与iptalbes模式相比,IPVS模式工作在内核态,在同步代理规则时具有更好的性能
同时IPVS提高网络吞吐量为大型集群提供了更好的可扩展性,同时提供了大量的负责均衡算法

当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。
如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行
下面演示如何修改代理模式为IPVS代理模式:
3.1:加载ipvs相关内核模块
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
3.2:编辑配置文件
实际上是修改kube-proxy对应的ConfingMap:
$ kubectl get cm -n kube-system | grep kube-proxy
NAME DATA AGE
kube-proxy 2 14d
$ kubectl edit cm kube-proxy -n kube-system
configmap/kube-proxy edited
修改mode的值,将其修改为ipvs
3.3:删除原有的kube-proxy代理
$ kubectl get pod -A | grep kube-proxy
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system kube-proxy-xnz4r 1/1 Running 0 14d
kube-system kube-proxy-zbxrb 1/1 Running 0 14d
$ kubectl delete pod kube-proxy-xnz4r -n kube-system
pod "kube-proxy-xnz4r" deleted
$ kubectl delete pod kube-proxy-zbxrb -n kube-system
pod "kube-proxy-zbxrb" deleted
删除完成后,k8s会自动重启kube-proxy的Pod:
$ kubectl get pod -A | grep kube-proxy
kube-system kube-proxy-hvnmt 1/1 Running 0 6m35s
kube-system kube-proxy-zp6z5 1/1 Running 0 6m20s
3.4:查看IPVS
$ ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 172.30.1.2:6443 Masq 1 1 0
TCP 10.96.0.10:53 rr
-> 192.168.0.5:53 Masq 1 0 0
-> 192.168.1.2:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 192.168.0.5:9153 Masq 1 0 0
-> 192.168.1.2:9153 Masq 1 0 0
TCP 10.99.58.167:80 rr
-> 192.168.0.6:80 Masq 1 0 0
-> 192.168.1.3:80 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 192.168.0.5:53 Masq 1 0 0
-> 192.168.1.2:53 Masq 1 0 0
4:再谈iptables和ipvs
4.1:Netfilter内核模块
ptables和ipvs其实都是依赖的一个共同的Linux内核模块:Netfilter。
Netfilter是Linux 2.4.x引入的一个子系统,它作为一个通用的、抽象的框架,提供一整套的hook函数的管理机制
使得诸如数据包过滤、网络地址转换(NAT)和基于协议类型的连接跟踪成为了可能。
Netfilter的架构就是在整个网络流程的若干位置放置了一些检测点(HOOK),而在每个检测点上登记了一些处理函数进行处理。

在一个网络包进入Linux网卡后,有可能经过这上面几个Hook点
我们可以自己写Hook函数,注册到任意一个点上,而iptables和ipvs都是在这个基础上实现的。
4.2:iptables代理模式底层
iptables是把一些特定规则以“链”的形式挂载到每个Hook点,这些链的规则是固定的,而是是比较通用的
可以通过iptables命令在用户层动态的增删,这些链必须串行的执行。
执行到某条规则,如果不匹配,则继续执行下一条,如果匹配,根据规则,可能继续向下执行,也可能跳到某条规则上,也可能下面的规则都跳过。

4.3:二者比较
- iptables更通用,主要是应用在防火墙上,也能应用于路由转发等功能,ipvs更聚焦,它只能做负载均衡,不能实现其它的
- iptables在处理规则时,是按“链”逐条匹配,如果规则过多,性能会变差,它匹配规则的复杂度是O(n),而ipvs处理规则时,在专门的模块内处理,查找规则的复杂度是O(1)
- iptables虽然可以实现负载均衡,但是它的策略比较简单,只能以概率转发,而ipvs可以实现多种策略
七:HeadLiness services
在某些场景中,开发人员可能不想使用Service提供的负载均衡功能,而希望自己来控制负载均衡策略
针对这种情况,kubernetes提供了HeadLiness Service,这类Service不会分配Cluster IP
如果想要访问Service,只能通过Service的域名进行查询
7.1:创建Pod
apiVersion: apps/v1 # 指定了使用的Kubernetes API版本为apps/v1,这是用于部署(Deployments)、有状态集(StatefulSets)等应用的API版本
kind: Deployment # 指明了Kubernetes资源的类型为Deployment。Deployment用于声明式地更新应用和服务
metadata: # 包含了该Deployment的元数据
name: nginx # 定义了Deployment的名称,这里为nginx
spec: # 包含了Deployment的规格说明
replicas: 2 # 指定了Pod的副本数量为2,即Kubernetes会尝试运行两个相同的Pod实例
selector: # 用于选择哪些Pod应该被这个Deployment管理
matchLabels: # 通过标签选择器来找到对应的Pod。
app: nginx # 这里它指定了app: nginx,意味着所有带有app=nginx标签的Pod都会被这个Deployment管理
template: # 定义了Pod的模板,即Deployment应该如何创建新的Pod
metadata: # Pod模板的元数据。
labels:
app: nginx # 定义了Pod的标签,这里同样为app: nginx,以确保这些Pod能被Deployment的selector选中
spec: # Pod的规格说明。
containers: # 定义了Pod中容器的列表
- name: nginx # 容器的名称,这里为nginx
image: nginx # 容器使用的镜像,这里使用官方提供的nginx镜像。
ports: # 定义了容器需要暴露的端口。
- containerPort: 80 # 容器内部监听的端口号为80
protocol: TCP # 指定了端口使用的协议为TCP
$ vim headliness-pod.yaml
$ kubectl apply -f headliness-pod.yaml
deployment.apps/nginx created
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7f456874f4-225j6 1/1 Running 0 16s 192.168.1.3 node01 <none> <none>
nginx-7f456874f4-r7csn 1/1 Running 0 16s 192.168.0.6 controlplane <none> <none>
7.2:创建Service
apiVersion: v1
kind: Service
metadata:
name: headliness-service
spec:
selector:
app: nginx # Label选择器,指定选择app=nginx为标签的Pod
clusterIP: None # 将clusterIP设置为None,即可创建headliness Service
type: ClusterIP
ports:
- port: 80 # Service的端口
targetPort: 80 # Pod的端口
$ vim headliness-service.yaml
# 编写上面的内容
$ kubectl get pod -o wide --show-labels # 检查现有的pod
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-7f456874f4-225j6 1/1 Running 0 103s 192.168.1.3 node01 <none> <none> app=nginx,pod-template-hash=7f456874f4
nginx-7f456874f4-r7csn 1/1 Running 0 103s 192.168.0.6 controlplane <none> <none> app=nginx,pod-template-hash=7f456874f4
controlplane $ kubectl apply -f headliness-service.yaml # kubectl apply 应用服务
service/headliness-service created
controlplane $ kubectl get svc -o wide --show-labels # 查看service列表
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR LABELS
headliness-service ClusterIP None <none> 80/TCP 10s app=nginx <none>
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17d <none> component=apiserver,provider=kubernetes
# 查看详情
$ kubectl describe service headliness-service
Name: headliness-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 192.168.0.6:80,192.168.1.3:80 # 能提供服务的Pod
Session Affinity: None
Events: <none>
7.3:进入容器,查看服务域名
# 查看Pod
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7f456874f4-225j6 1/1 Running 0 4m37s 192.168.1.3 node01 <none> <none>
nginx-7f456874f4-r7csn 1/1 Running 0 4m37s 192.168.0.6 controlplane <none> <none>
# 进入Pod
$ kubectl exec nginx-7f456874f4-r7csn -it -- bin/bash
# 查看域名
root@nginx-7f456874f4-r7csn:/# cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5
# 通过Service的域名进行查询:默认访问规则service名称.名称空间.svc.cluster.local
# 在Pod内通过curl可以访问
root@nginx-7f456874f4-r7csn:/# curl headliness-service.default.svc.cluster.local
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
root@nginx-7f456874f4-r7csn:/# exit
exit
# 查看DNS
$ apt install bind9-utils
$ dig @10.96.0.10 headliness-service.default.svc.cluster.local
; <<>> DiG 9.16.1-Ubuntu <<>> @10.96.0.10 headliness-service.default.svc.cluster.local
; (1 server found)
;; 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: 59994
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: b633b51a4ca3a653 (echoed)
;; QUESTION SECTION:
;headliness-service.default.svc.cluster.local. IN A
# ----------------> 注意下面这三行 <-----------------
;; ANSWER SECTION:
headliness-service.default.svc.cluster.local. 30 IN A 192.168.1.3
headliness-service.default.svc.cluster.local. 30 IN A 192.168.0.6
;; Query time: 0 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Mon Jan 09 09:
1107

被折叠的 条评论
为什么被折叠?



