
一、Service基本概念
1. Pod的特征
Pod拥有独立的IP,属于临时性容器资源,可以灵活创建与销毁。集群扩缩容过程中,Pod实例数量会动态增减。如果Pod发生故障,ReplicaSet会自动生成新实例替换。面对Pod频繁启停、扩容缩容、故障重建的场景,如何保障业务访问持续稳定不中断。

2. Service概述
Kubernetes Service是为动态变化的Pod提供固定统一访问入口的核心资源,它通过标签匹配关联后端一组业务Pod,依靠内置负载均衡机制转发流量,屏蔽Pod重建、销毁、扩缩容带来的IP变动问题。既实现集群内外便捷的服务发现,又能保障后端实例频繁更新迭代,业务访问始终稳定不中断。
2.1 Service解决的的核心问题
Pod随时创建、删除、漂移、重建,IP地址不固定,无法直接用来访问业务
多个相同业务Pod需要负载均衡分发请求
实现集群内外统一访问,解耦客户端和后端Pod
2.2 Service的实现类型
ClusterIP:通过集群的内部IP暴露服务,选择该值时服务只能够在集群内部访问,这是默认的Service类型。
NodePort:通过每个节点上的IP和静态端口(NodePort)暴露服务。NodePort服务会路由到自动创建的ClusterIP服务。通过请求<节点IP>:<节点端口>,你可以从集群的外部访问一个NodePort服务。
LoadBalancer:使用云厂商的负载均衡器对外暴露服务,外部负载均衡可以将流量路由到自动创建的NodePort服务和ClusterIP服务上。
ExternalName:通过返回CNAME和对应值,可以将服务映射到externalName字段的内容,无需创建任何类型的代理。

3. Servic访问解耦方案
3.1 问题的根源
Pod是临时性容器:Pod会被创建、销毁、扩缩容,IP地址会频繁变化。
客户端直连:客户端需要知道所有Pod的真实IP,一旦Pod重建/扩容,客户端就得更新地址列表,无法稳定访问。
缺少负载均衡:客户端自己做负载均衡不仅麻烦,还容易出现连接不均、故障节点无法自动剔除。
3.2 解决方案:引入Service逻辑对象,解决上述问题
稳定访问入口:Service会分配一个固定的虚拟IP和DNS名称,客户端只需要访问这个固定地址,再也不用关心Pod IP的变化。
服务发现与负载均衡:Service会自动发现后端所有健康的Pod,并将客户端的请求分发到这些Pod上,实现内置的负载均衡。
解耦客户端与后端:客户端只需要和Service交互,后端Pod的扩缩容、故障重建对客户端来说完全透明,业务访问因此稳定无中断。

4. CoreDNS
CoreDNS是轻量化集群DNS服务组件,以插件化架构部署于Kubernetes集群,核心提供域名解析或服务发现能力。集群内既可以通过IP地址访问业务资源,也可以使用域名便捷访问各类服务。从Kubernetes1.13版本起,CoreDNS正式替代原有kubeDNS,成为集群默认内置的DNS解析组件。
[Tricks] 查看Kubernetes集群组件,能够看到CoreDNS相关Pod实例。
root@k8s-master:~# kubectl get pods -n kube-system
5. Headless无头服务
Headless即Kubernetes无头服务,通过配置“clusterIP: None”进行定义。该服务不会分配集群虚拟IP,不具备流量转发与负载均衡能力,kube-proxy也不会对其做路由处理。
依托集群CoreDNS实现服务发现,域名解析时直接返回匹配标签后端Pod的真实IP,客户端可以跳过代理层,直接与单个Pod建立通信。如果服务配置标签选择器,系统会自动生成对应端点记录,域名请求将直接转发至后端Pod。
无头服务无法适配依赖集群IP的会话保持类配置,适用于无需负载均衡、需要直连实例的场景,常用于MySQL、Redis等有状态集群部署,满足固定节点访问需求。相同命名空间下,客户端可以直接使用服务名进行访问。
[Step1] Headless服务的完整DNS记录名称,解析该DNS记录能够返回所有匹配该服务的Pod真实IP列表。
[Headless服务名称].[命名空间].svc.cluster.local[Step2] Deployment中Pod的DNS记录名称,解析该DNS记录只会返回单个Pod的IP。
[Pod的IP].[Headless服务名称].[命名空间].svc.cluster.local6. iptables代理模式
在iptables代理模式下,kube-proxy实时监听集群内Service与Endpoints资源的增减变动。针对每一个Service,自动配置iptables规则,拦截访问集群IP与端口的请求,并将流量转发至对应的后端Pod。通顺一点说,配置iptables规则捕获请求,然后重定向到后端Pod。
同时依据Endpoints信息完成后端节点匹配,该模式默认采用随机调度策略分发请求,依托Linux内核的netfilter机制转发流量,无需进行用户态和内核态的数据切换,系统资源开销更低,运行稳定性也更强。

7. IPVS代理模式
在IPVS代理模式下,kube-proxy持续监听集群内Service与Endpoints资源变更,通过netlink接口自动创建并维护IPVS转发规则,同时定期完成规则同步,保障IPVS运行状态与集群服务配置始终一致。客户端访问服务时,IPVS可自动将流量转发至后端任意可用Pod。
IPVS模式同样依托netfilter机制实现流量转发,底层采用哈希表存储数据,全程在内核态完成处理。相较于iptables模式,IPVS有效降低流量转发延迟,大幅提升代理规则同步效率,具备更高的网络吞吐能力,更适配高并发业务场景。
4.1 IPVS与iptables比较
8. Endpoint Controller
端点控制器(Endpoint Controller)用于创建并维护集群内所有Endpoint资源,持续监听Service与Pod的状态变动。
监听到Service删除时,同步移除同名Endpoint资源
监听到新建Service时,匹配关联Pod清单,自动创建对应Endpoint
监听到Service配置更新时,重新匹配Pod列表,完成Endpoint信息更新
监听到Pod状态发生变更时,同步更新所属Service的Endpoint,完成Pod IP信息录入维护
9. Kubernetes服务类型总结
二、Service基础案例
1. 命令行生成NodePort类型的Service
[Step1] 本地新建YAML文件,创建一个deployment。
root@k8s-master:~# vim nginx-deployment01.yml
# 写入下列内容
apiVersion: apps/v1 # 固定配置
kind: Deployment # 资源类型
metadata:
name: nginx-deployment01
labels: # 定义标签
app: nginx-deployment01 # 自定义标签(键和值均可自定义)
spec:
replicas: 4 # 预期数量为4
selector:
matchLabels: # 标签匹配模式:精确匹配
app: nginx-deployment01 # 匹配的标签值
template: # 根据此模板来新建Pod
metadata:
labels: # 给Pod加上标签,需要和selector定义一致
app: nginx-deployment01
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80[Step2] 根据YAML文件向Kubernetes集群声明式地创建Deployment资源。
root@k8s-master:~# kubectl create -f nginx-deployment01.yml[Step3] 验证:查看当前集群中的所有Deployment资源。
root@k8s-master:~# kubectl get deployments.apps
[Step4] 通过命令行的方式创建Kubernetes Service。
root@k8s-master:~# kubectl expose deployment nginx-deployment01 --port=8080 --name=httpd-nodeport-service01 --target-port=80 --type=NodePortkubectl expose:创建Service,将一个工作负载(Deployment/Pod)暴露成可访问的服务
deployment nginx-deployment01:指定要暴露的类型的Deployment,名称为nginx-deployment
--port=8080:指定ClusterIP端口
--name=httpd-nodeport-service01:指定Service的名称
--target-port=80:后端Deployment中Pod真正监听的端口
--type=NodePort:Service类型为NodePort

[Step5] 验证:查看当前命名空间下的所有Service资源。整体转发逻辑其实是当集群外部客户端通过集群任意节点主机IP+32604端口发起访问请求,请求先抵达节点开放的NodePort端口,再经由节点上kube-proxy组件转发至nginx-service服务的ClusterIP+8080端口再通过服务的端口映射规则转发至后端四个正常运行的NginxPod内部80端口。
root@k8s-master:~# kubectl get serviceCLUSTER-IP:Service在集群内部固定的虚拟IP
PORT(S):8080为Service内部端口,32604为节点对外开放的端口
[Step6] 验证:先查看当前主机的IP地址,然后访问Deployment管理的Nginx Pod测试页面,能够正常访问。
root@k8s-master:~# ip add show ens33
root@k8s-master:~# curl 192.168.8.3:32604
[Step7] 验证:使用集群的任意节点IP地址访问Deployment管理的Nginx Pod测试页面,同样能够正常访问。
root@k8s-master:~# curl 192.168.8.4:32604
root@k8s-master:~# curl 192.168.8.5:32604
2. 声明式生成NodePort类型的Service
[Step1] 本地新建YAML文件,创建一个deployment。
root@k8s-master:~# vim nginx-deployment02.yml
# 写入下列内容
apiVersion: apps/v1 # 固定配置
kind: Deployment # 资源类型
metadata:
name: nginx-deployment02
labels: # 定义标签
app: nginx-deployment02 # 自定义标签(键和值均可自定义)
spec:
replicas: 4 # 预期数量为4
selector:
matchLabels: # 标签匹配模式:精确匹配
app: nginx-deployment02 # 匹配的标签值
template: # 根据此模板来新建Pod
metadata:
labels: # 给Pod加上标签,需要和selector定义一致
app: nginx-deployment02
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80[Step2] 根据YAML文件向Kubernetes集群声明式地创建Deployment资源。
root@k8s-master:~# kubectl create -f nginx-deployment02.yml[Step3] 验证:查看当前集群中的所有Deployment资源。
root@k8s-master:~# kubectl get deployments.apps
[Step4] 本地新建YAML文件,创建NodePort类型的Service。
root@k8s-master:~# vim httpd-nodeport-service02.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: Service # 资源类型
metadata:
name: httpd-nodeport-service02
spec:
type: NodePort # Service类型
selector: # 标签选择器,匹配后端Pod
app: nginx-deployment02 # 匹配后端Pod的标签
ports:
- protocol: TCP # 使用TCP协议
port: 8081 # Service自己暴露的端口
targetPort: 80 # 后端Pod实际监听的端口
nodePort: 31803 # 指定Node节点对外开放的端口,不指定则随机分配[Step5] 根据YAML文件向Kubernetes集群声明式地创建Service资源。
root@k8s-master:~# kubectl create -f httpd-nodeport-service02.yml[Step6] 验证:查看当前命名空间下的所有Service资源。
root@k8s-master:~# kubectl get service
[Step7] 验证:先查看当前主机的IP地址,然后访问Deployment管理的Nginx Pod测试页面,能够正常访问。
root@k8s-master:~# ip add show ens33
root@k8s-master:~# curl 192.168.8.3:31803
[Step8] 验证:使用集群的任意节点IP地址访问Deployment管理的Nginx Pod测试页面,同样能够正常访问。
root@k8s-master:~# curl 192.168.8.4:31803
root@k8s-master:~# curl 192.168.8.5:31803
3. 声明式生成ClusterIP类型的Service
[Step1] 本地新建YAML文件,创建一个deployment。
root@k8s-master:~# vim httpd-deployment01.yml
# 写入下列内容
apiVersion: apps/v1 # 固定配置
kind: Deployment # 资源类型
metadata:
name: httpd-deployment01
labels: # 定义标签
app: httpd-deployment01 # 自定义标签(键和值均可自定义)
spec:
replicas: 4 # 预期数量为4
selector:
matchLabels: # 标签匹配模式:精确匹配
app: httpd-deployment01 # 匹配的标签值
template: # 根据此模板来新建Pod
metadata:
labels: # 给Pod加上标签,需要和selector定义一致
app: httpd-deployment01
spec:
containers:
- name: httpd
image: httpd:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80[Step2] 根据YAML文件向Kubernetes集群声明式地创建Deployment资源。
root@k8s-master:~# kubectl create -f httpd-deployment01.yml[Step3] 验证:查看当前集群中的所有Deployment资源。
root@k8s-master:~# kubectl get deployments.apps
[Step4] 本地新建YAML文件,创建ClusterIP类型的Service。
root@k8s-master:~# vim httpd-clusterip-service.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: Service # 资源类型
metadata:
name: httpd-clusterip-service
spec:
type: ClusterIP # Service类型,不写的话默认为ClusterIP
selector: # 标签选择器,匹配后端Pod
app: httpd-deployment01 # 匹配后端Pod的标签
ports:
- protocol: TCP # 使用TCP协议
port: 8082 # Service自己暴露的端口
targetPort: 80 # 后端Pod实际监听的端口[Step5] 根据YAML文件向Kubernetes集群声明式地创建Service资源。
root@k8s-master:~# kubectl create -f httpd-clusterip-service.yml[Step6] 验证:查看当前命名空间下的所有Service资源。
root@k8s-master:~# kubectl get service
[Step7] 验证:查看Service关联的后端Pod IP与端口信息。
root@k8s-master:~# kubectl get endpoints
[Step8] 验证:使用ClusterIP加上端口号访问后端服务。
root@k8s-master:~# curl http://10.100.229.189:8082
4. 声明式生成Headless类型的Service
[Step1] 本地新建YAML文件,创建一个Deployment。
root@k8s-master:~# vim busybox-headless-deployment.yml
# 写入下列内容
apiVersion: apps/v1 # 固定配置
kind: Deployment # 资源类型
metadata:
name: busybox-headless-deployment
labels: # 定义标签
app: busybox-headless-deployment # 自定义标签(键和值均可自定义)
spec:
replicas: 4 # 预期数量为4
selector:
matchLabels: # 标签匹配模式:精确匹配
app: busybox-headless-deployment # 匹配的标签值
template: # 根据此模板来新建Pod
metadata:
labels: # 给Pod加上标签,需要和selector定义一致
app: busybox-headless-deployment
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ['sh','-c','echo "Hello World!" && sleep 3600'][Step2] 根据YAML文件向Kubernetes集群声明式地创建Deployment资源。
root@k8s-master:~# kubectl create -f busybox-headless-deployment.yml[Step3] 验证:查看当前集群中的所有Deployment资源。
root@k8s-master:~# kubectl get deployments.apps
[Step4] 本地新建YAML文件,创建Headless类型的Service。
root@k8s-master:~# vim busybox-headless-service.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: Service # 资源类型
metadata:
name: busybox-headless-service
spec:
clusterIP: None # 声明这是一个Headless服务
selector: # 标签选择器,匹配后端Pod
app: busybox-headless-deployment # 匹配后端Pod的标签
ports: # 必须要写,这里busybox其实用不上端口号,随便写一个
- port: 8083[Step5] 根据YAML文件向Kubernetes集群声明式地创建Service资源。警告信息表示无头服务将自动忽略“spec.sessionAffinity”配置。因为无头服务不存在“ClusterIP”,不具备负载均衡与IP代理能力,而“sessionAffinity(会话保持)”功能依托ClusterIP实现流量代理,因此识别到该项配置后,集群会自动弃用并触发提示。
root@k8s-master:~# kubectl create -f busybox-headless-service.yml
[Step6] 验证:查看当前命名空间下的所有Service资源,可以看到无头服务不存在ClusterIP。
root@k8s-master:~# kubectl get service
[Step7] 验证:显示当前命名空间下的所有Pod。
root@k8s-master:~# kubectl get pods -o wide
[Step8] 验证:登录Pod容器内部命令行终端,测试Headless服务的DNS域名解析,能够查看所有后端Pod的IP地址列表。
root@k8s-master:~# kubectl exec -it busybox-headless-deployment-65cfbf5f7-6cwns -- /bin/sh
/ # nslookup busybox-headless-service.default.svc.cluster.local
