六、k8s四层负载均衡Service
ClusterIP:默认类型、仅限集群内部(pod或者Service间通信)、外部无法访问
实现机制:
- 分配一个稳定的虚拟 IP(ClusterIP),通过
kube-proxy维护的 iptables/IPVS 规则实现内部负载均衡。 - 自动关联标签匹配的 Pod,并通过 Endpoints 动态维护后端 Pod IP 列表
适用场景:
- 微服务架构中的内部通信(如前端调用后端 API)。
- 数据库、缓存等仅需集群内访问的服务。
NodePort:通过 节点 IP + 静态端口(30000-32767) 暴露服务,允许 集群外部访问
实现机制:
- 在 ClusterIP 基础上,在每个节点上绑定一个固定端口(可手动指定或自动分配)。
- 外部流量通过
<NodeIP>:<NodePort>进入,转发到 Service 的 ClusterIP 和端口
适用场景:
- 发/测试环境中的外部访问(如本地调试 Web 应用)。
- 小规模集群的临时暴露服务(非生产环境)。
ExternalName:将集群内部请求映射到外部 DNS 名称(如云数据库、第三方 API),不代理任何 Pod
实现机制:
- 使用 DNS CNAME 记录,将 Service 名称解析为外部域名(如
mysql.external.com)。 - 无 ClusterIP 或端口映射,仅提供 DNS 别名功能。
适用场景:
- 集群内访问外部服务(如公有云数据库、支付网关)。
- 隐藏外部服务细节,简化内部调用逻辑
1.service的作用
虽然k8s内部网络中的pod使用ip地址可以直接访问、但是它们的ip地址通常只是临时的、会随着pod的重启和重新调度变化。Server用于将一组 Pod 暴露为统一的访问入口,提供 服务发现 和负载均衡 功能。它通过虚拟 IP(ClusterIP)和端口对外提供服务,屏蔽 Pod 的动态变化。 在实际的应用场景中,往往会结合Ingress以实现更复杂的代理和负载 均衡需求。
主要功能
- 提供固定的IP和DNS名称。当你创建一个Service后,它会分配一个稳 定的虚拟IP地址,可以通过这个地址和Service名称访问服务,无需关心后台 Pod 的IP。
- 负载均衡。Service可以让请求分布到多个Pod上,从而实现负载均衡。 例如,当有多个后台Pod时,Service可以基于预定义的负载均衡算法将请求分 发到这些Pod中。
- 服务发现。Service通过匹配Label Selector,可以将一组后台Pod当 成一个Service进行管理,这样我们就可以方便地对这些Pod进行管理、监控及 网络访问控制等操作

2.k8s集群中的三类ip地址
1.Node Network(节点网络)
** **物理节点或者虚拟节点的网络,如ens33接口上的网络地址。
ip addr
2. Pod Network(pod网络)
创建的pod具有的ip地址
kubectl get pods -o wide
**3. ClusterNetwork(集群地址,也称为servicenetwork) **
这个地址是虚拟的地址(virtualip),没有配置在某个接口上,只是出现 在service的规则当中。
kubectl get svc kubernetes
3.service的配置
| 属性名称 | 取值类型 | 说明 |
|---|---|---|
| apiVersion | string | Api版本 |
| kind | string | 资源类型 |
| metadata | object | 元数据 |
| metadata.name | string | 控制器的名称 |
| metadata.namespace | string | 控制器所属的命名空间,默认值为default |
| metadata.labels[] | List | 自定义标签列表 |
| metadata.annotation[] | List | 自定义注解列表 |
| spec | object | 规范Service所需行为的规范 |
| spec.clusterIP | string | 表示分配给该Service的集群内部的IP地址。这个IP 地址可以用来访问该Service提供的服务。 clusterIP可以被配置为一个特定的IP地址,也可以让 Kubernetes自动分配一个可用的IP地址。如果配置为 一个特定的IP地址,需要保证该IP地址未被其他对象 使用,并且在同一子网(subnet)内。 例如,如果设置clusterIP为10.0.0.100,则所有访问 该Service的请求都将被路由到该IP地址。 |
| spec.ports | []object | 用于服务监听的端口号 |
| spec.ports.appProtocol | string | 用于指定服务端口上使用的应用层协议。例如HTTP或 TLS。 示例: http服务监听了80端口,targetPort为8080,protocol 为TCP,此外还指定了appProtocol为http。在使用这 种配置时,负载均衡器将根据应用层协议名http来路 由到后端上。 spec: ports: -name: http port: 80 protocol: TCP targetPort: 8080 appProtocol: http |
| spec.ports.name | string | 这个名称并不是必须的,但为了方便管理和使用,通常 会给服务的每个端口指定一个名称。 |
| spec.ports.nodePort | intrger | 用于指定NodePort模式下服务的节点端口号,在 NodePort模式下,Kubernetes会为每个节点分配一个 端口号,将访问此端口的流量转发到Service的端口上。 使用nodePort属性可以指定节点端口号。 示例: Service对象监听了80端口,NodePort模式下使用的 节点端口号为30080。当Kubernetes集群中的任何节点 上的流量通过该端口30080访问该Service时,流量将 被转发到Service的80端口上,然后service会转发 到targetPort上(也就是pod端口上)。 spec: type: NodePort ports: -name: http port: 80 targetPort: 80 nodePort: 30080 |
| spec.ports.port | integer | 用于指定服务监听的端口号。 示例: Service对象监听了80端口,protocol为TCP, targetPort为8080。所有发送到80端口的流量都将被 转发到该targetPort上。 spec: ports: -name: http port: 80 protocol: TCP targetPort: 8080 |
| spec.ports.protocol | string | 标识服务端口监听的协议类型。 Kubernetes中支持TCP、UDP、SCTP等多种协议类型。 在Service对象中,使用protocol属性指定服务端口 监听的协议类型。默认协议类型为TCP。 |
| spec.ports.targetPort | string | 用于指定服务的后端容器监听的端口号。 在Kubernetes中,Service对象通常用于代理到后端的 Pod。targetPort属性用于指定后端Pod监听的端口号。 当流量进入该端口时,Service会将其转发到相应的Pod 上。 |
| spec.selector | map[string]string | 指定当前服务关联的Pod Selector。 PodSelector用于将服务和后端Pod进行关联。当创建 服务时,可以使用selector属性指定服务需要关联哪 些Pod。Kubernetes将会自动为匹配Selector的Pods, 提供网络地址和DNS记录。 |
| spec.type | string | 指定本地或集群内服务的访问方式。 Service对象可以以三种不同的类型来暴露服务: ClusterIP、NodePort和LoadBalancer。在创建Service 对象时,需要通过指定type属性,来选择合适的访问 方式。 ● ClusterIP:默认类型。当指定该类型时, Kubernetes会为该服务创建一个虚拟的IP地址,仅能 从集群内部访问该服务。 ● NodePort:当指定该类型时,Kubernetes会为该服 务在每个节点上暴露一个端口号。通过该端口号,可以 从外部访问该服务。同时也可以从集群内部访问。 ● LoadBalancer:该类型可用于将容器服务暴露到云 平台的负载均衡器中。在使用该类型时,可以通过云平 台的负载均衡器,将服务暴露到集群外部并允许外部IP 地址的访问 |
| spec.sessionAffinity | string | 指定服务负载均衡算法。 当创建Service对象时,可以通过指定sessionAffinity 属性,来选择合适保持客户端对同一后端Pod之间会话 的策略,以实现一些业务需求。Kubernetes支持以下两 种负载均衡策略。 ● None:默认值。这意味着在多个Pod之间使用的是 基于IP的负载均衡。您可以使用此策略将请求随机分 发到匹配选择器的Pod上,且不受请求者的来源IP影 响。 ● ClientIP:这是另外一种Affinity策略,它根据 请求的源IP地址将流量转发到具有相同源IP地址的后 端Pod。 示例: Service对象负责将流量转发到与app=myapp的Pod, 服务没有IP地址,因为它被设置为一个clusterIP=None 集群IPService。服务负载均衡使用的是ClientIP的 Affinity策略。 spec: clusterIP: None port: -name: web port: 8080 targetPort: 80 selector: app: myapp sessionAffinity: ClientIP |
| spec.sessionAffinityCo nfig | object | 用于指定高级会话亲和性配置。 默认情况下,Kubernetes通过源IP地址来实现会话亲 和性。但是,在某些情况下,源IP地址可能会发生变 化,从而导致业务系统的不兼容性。为了解决这个问题, Kubernetes提供了sessionAffinityConfig属性。使用 该属性可以让用户配置其他的、更复杂的会话亲和性算 法 |
| spec.sessionAffinityCo nfig.clientIP.timeoutS econds | intrge | 设置会话超时时间。默认10800秒(三小时) |
实战:创建两个普通的pod
//编写yaml文件
vi pod_test.yaml
apiVersion: apps/v1 # 使用的 API 版本
kind: Deployment # 资源类型为 Deployment
metadata:
name: my-nginx # Deployment 名称
spec:
selector:
matchLabels:
run: my-nginx # 选择器标签,用于匹配 Pod
replicas: 2 # 副本数量
template:
metadata:
labels:
run: my-nginx # Pod 标签,需与 selector 匹配
spec:
containers:
- name: my-nginx # 容器名称
image: nginx # 使用的镜像
imagePullPolicy: IfNotPresent # 镜像拉取策略
ports:
- containerPort: 80 # 容器暴露的端口
//更新资源清单文件
kubectl apply -f pod_test.yaml
//查看pod的ip地址
kubectl get pods -o wide
//请求pod ip地址、查看结果(注意替换地址)
curl 10.244.85.197:80
curl 10.244.58.199:80
//需要注意的是,pod虽然定义了容器端口,但是不会使用调度到该节点上的
80端口,也不会使用任何特定的NAT规则去路由流量到Pod上。这意味着可以
在同一个节点上运行多个Pod,使用相同的容器端口,并且可以从集群中任何其
他的Pod或节点上使用IP的方式访问到它们。
//删除其中一个pod、查看pod标签(注意替换地址)
kubectl delete pods my-nginx-5f7668c4b-72hj9
//查看pod、发现重新生成了一个pod、ip地址发生了变化
kubectl get pods -o wide
实战一:创建type类型为ClusterIp的Service
目标:使用Deployment控制器创建2个副本,创建service类型为ClusterIP 来代理Deployment控制器所创建的副本。
//查看pod标签
kubectl get pods --show-labels
//创建service资源清单文件
vi service_ClusterIP.yaml
apiVersion: v1 # Kubernetes API 版本
kind: Service # 资源类型为 Service
metadata:
name: my-nginx # Service 名称
labels:
run: my-nginx # Service 标签(用于分类)
spec:
type: ClusterIP # Service 类型(默认集群内访问)
ports:
- name: tcp-80 # 端口名称(便于识别)
port: 80 # Service 对外暴露的端口
protocol: TCP # 使用的协议(TCP/UDP/SCTP)
targetPort: 80 # 容器内实际监听的端口
appProtocol: http # 应用层协议(供 LB 识别)
selector:
run: my-nginx # 选择器标签(匹配后端 Pod)
//创建service资源
kubectl apply -f service_ClusterIP.yaml
1.用于创建名为my-nginx的Service,该Service用于将外部流量引入到名为my-nginx
的Deployment中。
2.在配置文件中,我们定义了Service的metadata和spec部分。metadata部分定义了
Service的名称和label“run:my-nginx”。
3.在spec部分,我们定义了Service的类型为ClusterIP,表示只能从Kubernetes集群
内部访问该Service。我们还定义了端口,将Service的80端口绑定到目标容器的80端口,
同时指定appProtocol为http。
4.最后,我们定义了selector,来指定该Service映射到哪些Pod上。在这个例子中,
//查看创建的service资源、Cluster-IP 就是我们生成的service的虚拟ip
kubectl get svc my-nginx
//测试访问、在k8s任意节点访问service的IP:端口就可以把请求代理到后端pod
得出结论:clister-ip+port == pod-ip+port
curl 10.10.178.9:80
扩展1:访问10.10.178.9:80是如何将流量转发给后端pod的
//查看描述
kubectl describe svc my-nginx
//查看endpoints信息
kubectl get endpoints my-nginx
//查看ipvs80端口
ipvsadm -ln | grep 80
当我们创建一个K8s service后、service会自动创建一个虚拟IP、在serrvice的spec中、我们使用selector对象来指定哪些pod是这个service的后端、k8s就会为service自动创建一个相关的Endpoints对象、用来记录这个service管理pod的ip地址和端口号信息
当客户端发起请求时、请求先到达k8s集群节点上的kube-proxy组件、kube-porxy组件会根据service监听的端口号和协议、选择对应的后端Endpoints地址和端口、然后转发请求到这些后端pod上面、kube-proxy还会通过iptables规则或者ipvs负载均衡算法等方式来做请求的负载

当service的后端pod数量发生变化时、Endpoints对象也会自动更新
扩展2:集群的FQDN(非常重要)
service只要创建完成,我们就可以直接解析它的服务名,每一个服务创建完成后都会 在集群dns中动态添加一个资源记录,添加完成后我们就可以解析了,资源记录格式是:
SVC_NAME.NS_NAME.DOMAIN.LTD.
SVC名称.命名空间名称.域名后缀,集群默认的域名后缀是svc.cluster.local。
就像我们上面创建的my-nginx这个服务,它的完整名称解析就是: my-nginx.default.svc.cluster.local
//查询
kubectl exec -it my-nginx-5f7668c4b-cnf2b --bash root@my-nginx-5f7668c4b-cnf2b :/# curl my-nginx.default.svc.cluster.local
实战二:创建type类型为NodePort的Service
目标:使用Deployment控制器创建2个副本,创建service类型为NodePort 来代理Deployment控制器所创建的副本
先创建pod、再创建service文件、创建pod的过程为实战里的代码过程、在上面、这里不再给出、仅提供创建svc的部分
/查看pod标签
kubectl get pods --show-labels
//创建service资源清单文件
vi service_NodePort.yaml
apiVersion: v1 # Kubernetes API 版本
kind: Service # 资源类型为 Service
metadata:
name: my-nginx # Service 名称
labels:
run: my-nginx # Service 标签(用于资源分类)
spec:
type: NodePort # Service 类型(通过节点端口暴露服务)
ports:
- port: 80 # Service 虚拟端口(集群内访问使用)
protocol: TCP # 网络协议类型(TCP/UDP/SCTP)
targetPort: 80 # 容器实际监听的端口
nodePort: 30380 # 节点暴露端口(范围30000-32767)
selector:
run: my-nginx # 选择器标签(匹配具有相同标签的Pod)
//创建service资源
kubectl apply -f service_NodePort.yaml
//查看创建的service资源、Cluster-IP 就是我们生成的service的虚拟ip
kubectl get svc my-nginx
//测试访问、在集群内访问
curl 10.10.228.115
//在集群外访问
在集群外部访问node节点IP+service代理的端口,即可代理到Pod
浏览器访问192.168.128.11:30380
扩展1:访问192.168.128.11:30380是如何将流量转发给后端pod的
NodePort类型的Service除了会创建一个ClusterIP地址外,还会分配一个静态端口 号,供集群外部访问Service。集群外部的请求将会先访问Kubernetes集群节点的该端口, 然后被重定向到Service相应的Pod上。 具体来说,当Kubernetes集群中的某个节点的kube-proxy组件监听到NodePort端口 的请求,它会转发请求到Service代理的ClusterIP地址,并根据Service中的selector 获得要转发给的Pod的IP地址和端口号。之后,kube-proxy会使用网络地址转换(NAT) 技术将节点的IP地址和NodePort转换成Pod的IP地址和容器内应用的服务端口号,最后 将请求转发到Pod上。如下图
需要注意的是,如果有多个节点,流量到达每个节点上的NodePort端口时,都会转发到相同的Pod上。当Pod的IP地址发生变化时,节点上的kube-proxy组件会自动刷新其 iptables规则,确保新的PodIP地址可以正常被转发
实战三:创建type类型为 ExternalName 的Service
先创建pod、再创建service文件、创建pod的过程为实战里的代码过程、在上面、这里不再给出、仅提供创建svc的部分
//创建svc文件
vi baidu-svc.yaml
apiVersion: v1 # Kubernetes API 版本
kind: Service # 资源类型为 Service
metadata:
name: baidu # Service 名称(集群内DNS使用该名称)
spec:
type: ExternalName # Service 类型(DNS别名映射)
externalName: www.baidu.com # 外部服务域名(将作为CNAME记录)
//应用yaml文件
kubectl apply-f baidu-svc.yaml
//查看svc、发现并没有虚拟ip
kubectl get svc baidu
//创建pod、进行测试、访问的时候被拒绝了、因为百度服务器不允许我们做代理
kubectl run busybox --image busybox:latest --restart=Never --rm -it busybox --sh
/# pingbaidu.default.svc.cluster.local
实战四:无标签选择器的Service
创建一个service,不使用标签选择器,通过创建endpoints指定IP和PORT, 然后和SVC进行绑定。 实战:k8s集群引用外部的mysql数据库
实战:k8s集群引用外部的mysql数据库
//在k8s-node-01上安装mysql数据库
yum install mariadb-server -y
systemctl restart mariadb
netstat -tlun | grep 3306
mysql
//在master节点创建yaml文件
vi mysql_service.yaml
apiVersion: v1 # Kubernetes API 版本
kind: Service # 资源类型为 Service
metadata:
name: mysql # Service 名称(用于集群内服务发现)
spec:
type: ClusterIP # 服务类型(默认集群内访问)
ports:
- port: 3306 # Service 暴露的端口
//更新资源清单文件
kubectl apply -f mysql_service.yaml
//查看创建的mysql的SVC
kubectl get svc | grep mysql
//查看描述
kubectl describe svc mysql
//创建Endpoints的yaml文件注意endpoints的名称必须和service的名称对应起来
vi mysql_endpoint.yaml
apiVersion: v1 # Kubernetes API 版本
kind:Endpoints # 资源类型为 Service
metadata:
name: mysql # Service 名称(用于集群内服务发现)
spec:
type: ClusterIP # 服务类型(默认集群内访问)
ports:
- port: 3306
//对yaml文件的说明
创建一个名为mysql的Endpoints对象的示例,它将一个或多个IP地址和端口映射到了一个命名的mysql服务上。
这个mysql服务可以在集群内部被其它Pod的容器使用,进而访问这些IP地址上的服务。
该清单表明了这个Endpoints对象的名称是mysql,它只有一个子集(subset),包含了一个IP地址192.168.
128.11和一个端口3306。
其中,metadata字段包含了Endpoints对象的元数据信息,例如名称、标签、注释等等;subsets字段是Endpo
ints对象的核心,它包含了Endpoints对象映射的IP地址和端口信息,可以有多个子集,每个子集可以映射多个IP地址和端口。
//更新资源清单文件
kubectl apply -f mysql_endpoint.yaml
//查看创建的mysql SVC
kubectl describe svc mysql
//在集群节点进行测试
mysql -h 10.102.14.71