Kubernetes‑Service
一、为什么需要Service
问题背景
- Pod是临时资源:Pod重启、扩缩容后Pod IP会发生变化,IP不稳定。
- 一组副本Pod,客户端无法维护不断变化的Pod IP列表。
- 直接用
hostPort绑定宿主机端口有缺陷:一台机器同一个端口只能被一个Pod占用,无法多副本调度。
Service核心作用
-
提供固定不变访问入口(Service IP),屏蔽后端Pod IP的动态变化。
-
实现四层负载均衡,把请求分发到后端多个Pod。
-
通过标签
selector筛选Pod,自动维护后端可用Pod列表(Endpoint)。注意:Service本身只是K8s资源对象,不处理数据包;真正转发流量由每个节点的
kube‑proxy实现。
二、基础概念
-
Selector选择器:通过标签匹配后端Pod;匹配成功的Pod会被加入
Endpoints列表。 -
Endpoints:Service后端Pod的
IP+port集合,和selector联动自动更新;Pod异常会自动剔除。 -
端口三概念(重点区分)
字段 含义 portService自身监听的端口(ClusterIP端口) targetPort后端Pod容器内部的业务端口 nodePortNodePort模式下,宿主机上开放的端口,范围默认 30000‑32767
示例:
--tcp=8080:80→ Service端口8080,转发到Pod的80端口。
简单Service yaml模板
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
selector:
app: web # 筛选标签app=web的Pod
ports:
- port: 8080
targetPort: 80
常用操作命令
# 创建clusterip服务
root@master30:~# kubectl create service clusterip web --tcp=8080:80
# 查看service
root@master30:~# kubectl get svc
# 查看详情,重点看Endpoints
# endpoints是生成的pod IP和对应的端口的组合
croot@master30:~# kubectl describe svc web
# 从deployment直接暴露service
croot@master30:~# kubectl expose deployment web --port=8080 --target-port=80
小知识点:ClusterIP ping不通属于正常现象,ClusterIP是内核虚拟标识,不是真实网卡IP,只响应端口的TCP/UDP流量,不响应ICMP ping包。
三、Service服务发现(集群内部Pod如何找到Service)
集群内部访问Service有3种方式
1. 直接使用Service Cluster‑IP访问
直接写Service的虚拟IP,缺点:IP是自动分配,写死不方便维护。
2. 环境变量访问
- Pod启动时,会注入同命名空间Service的环境变量。
- 格式示例:
MYSQL_SERVICE_HOST=10.111.69.45 - ⚠️限制:必须Service先创建,再创建Pod;如果Pod先启动,不会生成对应环境变量。
- 只能获取同一个namespace的Service环境变量。
3. DNS域名访问(生产最推荐,依赖CoreDNS)
集群内部CoreDNS组件提供服务域名解析。
域名格式:
- 同命名空间:
服务名 - 跨命名空间:
服务名.命名空间.svc.cluster.local
核心:只要集群DNS正常,不需要记IP,直接写服务名字即可互相调用。
四、Service的5种Type类型
1. ClusterIP(默认)
- 仅集群内部可以访问,外部无法访问。
- k8s从service‑cluster‑ip‑range地址池分配虚拟IP。
- 其他Service类型底层都基于ClusterIP实现。
2. NodePort
-
在所有节点上开放同一个宿主机端口,外部可以通过
任意节点IP:nodePort访问服务。 -
端口默认区间:
30000‑32767,可以随机分配,也可以yaml手动指定nodePort。 -
底层:kube‑proxy在每个节点生成iptables/ipvs规则,把nodePort流量转发给ClusterIP。
缺点:端口数量有限,对外暴露一堆端口,不适合大规模生产对外,适合测试。
3. LoadBalancer
- 在NodePort基础之上,再拿到一个独立外部公网/局域网VIP。
- 原生K8s本身不实现LB:公有云使用云厂商LB;自建机房使用
MetalLB实现。 - MetalLB(L2模式):ARP宣告VIP,流量进入集群,后续转发依旧交给kube‑proxy处理。
流量路径: 客户端 → LB外部VIP → 集群节点 → kube‑proxy规则 → Service → 后端Pod
4. ExternalName
- 不做代理转发,只做DNS CNAME别名。
- 把集群内部service名字映射到外部域名,没有ClusterIP,没有Endpoints。
spec:
type: ExternalName
externalName: www.laoma.cloud
访问svc名字,DNS直接解析跳转到外部域名,数据包不经过k8s转发。
5. Headless Service(无头服务)
设置 clusterIP: None。
- 不分配ClusterIP,kube‑proxy不会处理该Service,没有负载均衡功能。
- 带selector:DNS直接返回所有后端Pod的IP列表,客户端自己做负载均衡(用于有状态应用:mysql集群、redis集群)。
- 不带selector:自定义外部Endpoints。
使用场景:有状态应用,客户端需要直接感知每一个Pod真实IP。
五、会话保持 sessionAffinity
默认:sessionAffinity: None,流量随机分发各个Pod。
开启会话粘性:
kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'
ClientIP:同一个客户端源IP,请求始终转发到同一个后端Pod。- 默认超时时间:
10800秒(3小时),可以修改sessionAffinityConfig.clientIP.timeoutSeconds。 - 适用场景:有状态业务、WebSocket长连接、会话登录保存。
- 底层IPVS模式下使用
sh源地址哈希调度算法。
缺点:如果客户端大量来自同一个NAT出口IP,流量会全部打到同一个Pod,负载不均衡。
六、金丝雀发布(基于Service简单实现)
金丝雀(canary):少量流量给到新版本,验证新版本是否稳定,再全量切换。
实现思路
- 两套Deployment:
- stable(旧版本,多副本),标签
track: stable - canary(新版本,少量副本),标签
track: canary
- stable(旧版本,多副本),标签
- Service的selector同时匹配两套deployment的共同标签(app、tier),不区分track标签。
- 流量分配比例≈ 副本数量比例。
- 逐步减少旧副本数、增加新副本数,完成灰度升级。
示例:
- stable:8副本,canary:2副本 → 大约80%流量旧版本,20%新版本。
注意:这种方式是副本数权重,不是精确百分比权重;Ingress‑nginx canary注解可以做到精确百分比流量。
kube‑proxy
kube‑proxy 是 Kubernetes Pod网络核心组件,负责实现 Service → Endpoint(后端Pod) 的流量转发与负载均衡。
一、kube‑proxy 三种工作模式对比
| 模式 | 定位 | 性能 | 适用场景 | 核心特点 |
|---|---|---|---|---|
| iptables | K8s早期默认模式 | 中等(服务数<1000) | 小规模集群、环境稳定 | 依赖内核netfilter;服务多规则膨胀,性能下降 |
| IPVS | 生产推荐模式 | 极高(支持10w+服务) | 中大规模生产环境 | 内核哈希表O(1)查找;多种调度算法;性能远高于iptables |
| Userspace | 老旧废弃 | 很差 | 仅历史测试 | 用户态代理,性能最差;K8s 1.25+已移除 |
✅ 生产建议:使用 IPVS模式,搭配Calico网络插件,性能稳定性最佳。
二、查看 & 修改 kube‑proxy 工作模式
1. 查看当前工作模式
1)查看configmap配置(mode为空代表使用默认)
root@master30:~# kubectl get cm -n kube-system kube-proxy -o yaml|grep mode
2)查看kube‑proxy Pod日志,确认实际运行模式
# 获取kube‑proxy pod名称
root@master30:~# kubectl get pods -n kube-system -l k8s-app=kube-proxy -o name
# 查看日志
root@master30:~# kubectl logs -n kube-system <kube-proxy-pod-name> |grep Using
Using iptables proxy→ iptables模式Using ipvs Proxier→ IPVS模式
2. 切换为IPVS模式
# 1.编辑kube‑proxy配置configmap
root@master30:~# kubectl edit configmap -n kube-system kube-proxy
# 修改 mode: "ipvs"
# 2.重启daemonset使配置生效
root@master30:~# kubectl rollout restart daemonset -n kube-system kube-proxy
# 3.验证,查看日志输出 Using ipvs Proxier
root@master30:~# kubectl logs -n kube-system <new-kube-proxy-pod> |grep Using
三、IPVS模式详解
1. 原理
kube‑proxy在宿主机内核创建IPVS虚拟服务器,把后端Pod注册为Real Server; 底层使用哈希表存储转发规则,查找效率 O(1); 流量到达后,根据调度算法直接转发后端Pod,避开大量iptables规则链。
流量路径: 客户端Pod → 宿主机网卡 → 内核IPVS虚拟服务器 → 调度算法选后端Pod → 后端Pod,响应直接返回
2. IPVS支持调度算法
rr:轮询lc:最少连接(打开连接数最少)dh:目标地址哈希sh:源地址哈希sed:最短预期延迟nq:最少队列
3. 修改全局IPVS调度算法
kubectl edit configmap kube-proxy -n kube-system
ipvs:
scheduler: "wrr"
mode: "ipvs"
修改后重启daemonset:
kubectl rollout restart ds kube-proxy -n kube-system
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Adhjhfes/article/details/169269394




