☰
13、k8s四层负载均衡Service
2026/10/2 2:23:58 网站建设 项目流程

1、为什么要有Service

在kubernetes中,Pod是有生命周期的,如果Pod重启它的IP很有可能会发生变化。如果我们的服
务都是将Pod的IP地址写死,Pod挂掉或者重启,那么和刚才重启的pod相关联的其他服务将会找不到它所关联的Pod,为了解决这个问题,在kubernetes中定义了service资源对象,Service定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,service是一组Pod的逻辑集合,这一组Pod能够被Service访问到,通常是通过Label Selector实现的。

1、pod ip经常变化,service是pod的代理,我们客户端访问,只需要访问service,就会把请求
代理到Pod
2、pod ip 在k8s集群之外无法访问,所以需要创建service,这个service可以在k8s集群外访问
的。

3、kube-proxy:iptables或者ipvs防火墙规则。

4、coredns进行域名解析,可以把service的域名解析成ip。

2、Service概述

service是一个固定接入层,客户端可以通过访问service的ip和端口访问到service关联的后端pod,这个service工作依赖于在kubernetes集群之上部署的一个附件,就是kubernetes的dns服务(不同kubernetes版本的dns默认使用的也是不一样的,1.11之前的版本使用的是kubeDNs,较新的版本使用的是coredns),service的名称解析是依赖于dns附件的,因此在部署完k8s之后需要再部署dns附件,kubernetes要想给客户端提供网络功能,需要依赖第三方的网络插件(flannel,calico等)。每个K8s节点上都有一个组件叫做kube-proxy,kube-proxy这个组件将始终监视着apiserver中有关service资源的变动信息,需要跟master之上的apiserver交互,随时连接到apiserver上获取任何一个与service资源相关的资源变动状态,这种是通过kubernetes中固有的一种请求方法watch(监视)来实现的,一旦有service资源的内容发生变动(如创建,删除),kube-proxy都会将它转化成当前节点之上的能够实现service资源调度,把我们请求调度到后端特定的pod资源之上的规则,这个规则可能是iptables,也可能是ipvs,取决于service的实现方式。

3、Service工作原理

k8s在创建Service时,会根据标签选择器selector(lable selector)来查找Pod,据此创建与Service同名的endpoint对象,当Pod地址发生变化时,endpoint也会随之发生变化,service接收前端client请求的时候,就会通过endpoint,找到转发到哪个Pod进行访问的地址。(至于转发到哪个节点的Pod,由负载均衡kube-proxy决定)

4、k8s集群中有三类IP地址

4.1 Node Network(节点网络)

物理节点或者虚拟节点的网络,如ens33接口上的网络地址

4.2 Pod Network(pod网络)

创建的pod具有的ip地址

4.3 Cluster Network(集群网络,可以称为service network)

这个地址是虚拟的地址,没有配置在某个接口上,只是出现在service的规则当中。

5、创建Service

之前我们在学习deploy滚动更新的时候就用了svc四层代理,现在我们深入展开学习。

Kubernetes 中 Service 的spec.type官方支持4 种类型:

类型作用访问方式
ClusterIP默认类型,仅在集群内部暴露服务通过集群内虚拟 IP + 端口访问
NodePort在每个 Node 上开一个端口,对外暴露服务NodeIP:NodePort,默认端口范围30000-32767
LoadBalancer在 NodePort 基础上,向云厂商/负载均衡器申请外部 LB通过外部负载均衡器 IP/域名访问
ExternalName把 Service 名称通过 DNS CNAME 映射到外部域名集群内访问该 Service 名,解析到外部地址

5.1创建type类型是ClusterIP的service

# 创建pod-test.yaml文件 vi pod-test.yaml # 填入以下内容 apiVersion: apps/v1 # 指定使用的 Kubernetes API 版本,apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment,用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据 name: my-nginx # Deployment 名称 spec: # Deployment 的期望状态 selector: # 选择器,用来匹配要管理的 Pod matchLabels: # 通过标签匹配 Pod run: my-nginx # 匹配标签 run=my-nginx 的 Pod replicas: 2 # 期望运行的 Pod 副本数量为 2 template: # Pod 模板,用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 run: my-nginx # Pod 标签 run=my-nginx,与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: my-nginx # 容器名称 image: nginx # 容器使用的镜像 imagePullPolicy: IfNotPresent # 镜像拉取策略:本地不存在时才拉取 ports: # 容器端口列表 - containerPort: 80 # Pod 中容器需要暴露的端口
# 启动pod kubectl apply -f pod-test.yaml # 查看pod启动状态 kubectl get pod -o wide

创建test-service.yaml

apiVersion: v1 # 指定 Kubernetes API 版本,v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service,用于定义一组 Pod 的访问入口 metadata: # Service 的元数据信息 name: my-nginx # Service 的名称 labels: # Service 的标签 run: my-nginx # 标签 run=my-nginx,用于标识该 Service spec: # Service 的期望状态 type: ClusterIP # Service 类型为 ClusterIP,仅在集群内部可访问 ports: # Service 端口列表 - port: 80 # Service 的端口,暴露给 k8s 集群内部服务访问 protocol: TCP # 端口使用的协议为 TCP targetPort: 80 # Pod 容器中定义的端口,流量转发到该端口 selector: # 选择器,用于匹配后端 Pod run: my-nginx # 选择拥有 run=my-nginx 标签的 Pod

启动test-service.yaml,查看service,访问service

kubectl apply -f svc_test.yaml kubectl describe svc my-nginx curl 10.107.57.148:80

注意:上面的10.107.57.148:80地址只能是在k8s集群内部可以访问,在外部无法访问,比方说我
们想要通过浏览器访问,那么是访问不通的,如果想要在k8s集群之外访问,是需要把servicetype类型改成nodePort

5.2创建type类型是NodePort的service

# 创建pod-node-export.yaml文件 vi pod-node-export.yaml # 填入以下内容 apiVersion: apps/v1 # 指定 Kubernetes API 版本,apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment,用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据信息 name: my-nginx-nodeport # Deployment 的名称 spec: # Deployment 的期望状态 selector: # 选择器,用于匹配该 Deployment 管理的 Pod matchLabels: # 通过标签选择器匹配 Pod run: my-nginx-nodeport # 匹配标签 run=my-nginx-nodeport 的 Pod replicas: 2 # 期望运行的 Pod 副本数量为 2 template: # Pod 模板,用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 run: my-nginx-nodeport # Pod 标签为 run=my-nginx-nodeport,需与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: my-nginx-nodeport-container # 容器名称 image: nginx # 容器使用的镜像为 nginx imagePullPolicy: IfNotPresent # 镜像拉取策略:本地不存在时才拉取 ports: # 容器端口列表 - containerPort: 80 # Pod 中容器需要暴露的端口

启动pod,查看pod状态

apply -f pod-node-export.yaml kubectl get pod -o wide

创建svc_node_port.yaml

# 创建svc_node_port.yaml vi svc_node_port.yaml # 填入以下内容 apiVersion: v1 # 指定 Kubernetes API 版本,v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service,用于定义一组 Pod 的访问入口 metadata: # Service 的元数据信息 name: my-nginx-nodeport # Service 的名称 labels: # Service 的标签 run: my-nginx-nodeport # 标签 run=my-nginx-nodeport,用于标识该 Service spec: # Service 的期望状态 type: NodePort # Service 类型为 NodePort,可通过集群节点 IP + nodePort 从外部访问 ports: # Service 端口列表 - port: 80 # Service 自身暴露的端口,集群内部通过该端口访问服务 protocol: TCP # 端口使用的协议为 TCP targetPort: 80 # 后端 Pod 容器中定义的端口,流量转发到该端口 nodePort: 30380 # 在每个节点上暴露的端口,外部通过 节点IP:30380 访问服务 selector: # 选择器,用于匹配后端 Pod run: my-nginx-nodeport # 选择拥有 run=my-nginx-nodeport 标签的 Pod

启动svc,查看svc,访问svc

kubectl apply -f svc_node_port.yaml kubectl describe svc my-nginx-nodeport # 内网访问 curl 10.96.202.229:80 # 宿主机访问(外网访问) curl http://192.168.138.135:30380/

服务请求走向:Client-→nodeip:30380->service ip:80-→pod ip:container port
Client->192.168.138.135:30380->110.96.202.229:80->pod ip:80

5.3创建type类型是ExternalName的service

应用场景:跨名称空间访问
需求:default名称空间下的client服务想要访问nginx-ns名称空间下的nginx-svc服务

首先创建一个client.yaml

vi client.yaml # 填入以下内容 apiVersion: apps/v1 # 指定 Kubernetes API 版本,apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment,用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据信息 name: client # Deployment 的名称 spec: # Deployment 的期望状态 replicas: 1 # 期望运行的 Pod 副本数量为 1 selector: # 选择器,用于匹配该 Deployment 管理的 Pod matchLabels: # 通过标签选择器匹配 Pod app: busybox # 匹配标签 app=busybox 的 Pod template: # Pod 模板,用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 app: busybox # Pod 标签为 app=busybox,需与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: busybox # 容器名称 image: busybox # 容器使用的镜像为 busybox command: ["/bin/sh", "-c", "sleep 36000"] # 覆盖容器默认命令,启动后休眠 36000 秒

启动client,查看client

kubectl apply -f client.yaml kubectl get pod -o wide

创建svc_client.yaml

apiVersion: v1 # 指定 Kubernetes API 版本,v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service,用于定义一组 Pod 的访问入口或外部服务别名 metadata: # Service 的元数据信息 name: client-svc # Service 的名称 spec: # Service 的期望状态 type: ExternalName # Service 类型为 ExternalName,将服务映射到外部 DNS 名称 externalName: nginx-svc.nginx-ns.svc.cluster.local # 外部服务的 DNS 名称,访问该 Service 时会解析到此地址 ports: # 端口列表(ExternalName 类型下端口通常不是必需的,targetPort 可能被忽略) - name: http # 端口名称,标识该端口为 http port: 80 # Service 暴露的端口 targetPort: 80 # 目标端口,在 ExternalName 类型中通常不生效,可省略

启动svc并查看svc

kubectl apply -f svc_client.yaml kubectl describe svc client-svc

接着创建一个创建一个命名空间

kubectl create ns nginx-ns kubectl get ns

在这个命名空间下创建一个pod

vi nginx-pod.yaml #填入以下内容 apiVersion: apps/v1 # 指定 Kubernetes API 版本,apps/v1 用于 Deployment kind: Deployment # 资源类型为 Deployment,用于管理无状态应用的 Pod 副本 metadata: # Deployment 的元数据信息 name: nginx # Deployment 的名称 namespace: nginx-ns # 指定该 Deployment 所在的命名空间为 nginx-ns spec: # Deployment 的期望状态 replicas: 1 # 期望运行的 Pod 副本数量为 1 selector: # 选择器,用于匹配该 Deployment 管理的 Pod matchLabels: # 通过标签选择器匹配 Pod app: nginx # 匹配标签 app=nginx 的 Pod template: # Pod 模板,用于创建 Pod metadata: # Pod 模板的元数据 labels: # 给创建的 Pod 打标签 app: nginx # Pod 标签为 app=nginx,需与 selector 匹配 spec: # Pod 模板的期望状态 containers: # 容器列表 - name: nginx # 容器名称 image: nginx # 容器使用的镜像为 nginx imagePullPolicy: IfNotPresent # 镜像拉取策略:本地不存在时才拉取

启动pod,并查看pod状态

kubectl apply -f nginx-pod.yaml # 查看nginx-ns命名空间下的pod,如果是kubectl get pods -o wide是无法查看的 # 因为这个是查看default的命名空间,所以如下命令中带上了 -n nginx-ns,表示要查看nginx-ns命名空间下的pod kubectl get pods -n nginx-ns -o wide

最后给这个nginx-pod做一个service代理

# 创建nginx_svc.yaml vi nginx_svc.yaml # 填入以下内容 apiVersion: v1 # 指定 Kubernetes API 版本,v1 用于 Service 等核心资源 kind: Service # 资源类型为 Service,用于定义一组 Pod 的访问入口 metadata: # Service 的元数据信息 name: nginx-svc # Service 的名称 namespace: nginx-ns # 指定该 Service 所在的命名空间为 nginx-ns spec: # Service 的期望状态 selector: # 选择器,用于匹配后端 Pod app: nginx # 选择拥有 app=nginx 标签的 Pod ports: # Service 端口列表 - name: http # 端口名称,标识该端口为 http protocol: TCP # 端口使用的协议为 TCP port: 80 # Service 自身暴露的端口,集群内部通过该端口访问服务 targetPort: 80 # 后端 Pod 容器中定义的端口,流量转发到该端口

启动这个service,并查看这个service

kubectl apply -f nginx_svc.yaml kubectl describe svc nginx-svc -n nginx-ns

登录到client pode

# 登录client kubectl exec -it client-54bd759bfc-kqtpf -- /bin/sh # 分别执行如下两个命令 wget -q -O - client-svc.default.svc.cluster.local wget -q -O - nginx-svc.nginx-ns.svc.cluster.local # 两个命令结果一致

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询