kubernetes service && proxy

Kubernetes‑Service

一、为什么需要Service

问题背景

  1. Pod是临时资源:Pod重启、扩缩容后Pod IP会发生变化,IP不稳定。
  2. 一组副本Pod,客户端无法维护不断变化的Pod IP列表。
  3. 直接用hostPort绑定宿主机端口有缺陷:一台机器同一个端口只能被一个Pod占用,无法多副本调度。

Service核心作用

  1. 提供固定不变访问入口(Service IP),屏蔽后端Pod IP的动态变化。

  2. 实现四层负载均衡,把请求分发到后端多个Pod。

  3. 通过标签selector筛选Pod,自动维护后端可用Pod列表(Endpoint)。

    注意:Service本身只是K8s资源对象,不处理数据包 ;真正转发流量由每个节点的kube‑proxy实现。


二、基础概念

  1. Selector选择器 :通过标签匹配后端Pod;匹配成功的Pod会被加入Endpoints列表。

  2. Endpoints :Service后端Pod的IP+port集合,和selector联动自动更新;Pod异常会自动剔除。

  3. 端口三概念(重点区分)

    字段 含义
    port Service自身监听的端口(ClusterIP端口)
    targetPort 后端Pod容器内部的业务端口
    nodePort NodePort模式下,宿主机上开放的端口,范围默认30000‑32767

示例:--tcp=8080:80 → Service端口8080,转发到Pod的80端口。

简单Service yaml模板

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP
  selector:
    app: web       # 筛选标签app=web的Pod
  ports:
  - port: 8080
    targetPort: 80

常用操作命令

bash 复制代码
# 创建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。
yaml 复制代码
spec:
  type: ExternalName
  externalName: www.laoma.cloud

访问svc名字,DNS直接解析跳转到外部域名,数据包不经过k8s转发。

5. Headless Service(无头服务)

设置 clusterIP: None。

  1. 不分配ClusterIP,kube‑proxy不会处理该Service,没有负载均衡功能。
  2. 带selector:DNS直接返回所有后端Pod的IP列表,客户端自己做负载均衡(用于有状态应用:mysql集群、redis集群)。
  3. 不带selector:自定义外部Endpoints。

使用场景:有状态应用,客户端需要直接感知每一个Pod真实IP。


五、会话保持 sessionAffinity

默认:sessionAffinity: None,流量随机分发各个Pod。

开启会话粘性:

bash 复制代码
kubectl patch svc web -p '{"spec":{"sessionAffinity":"ClientIP"}}'
  • ClientIP:同一个客户端源IP,请求始终转发到同一个后端Pod。
  • 默认超时时间:10800秒(3小时),可以修改sessionAffinityConfig.clientIP.timeoutSeconds。
  • 适用场景:有状态业务、WebSocket长连接、会话登录保存。
  • 底层IPVS模式下使用sh源地址哈希调度算法。

缺点:如果客户端大量来自同一个NAT出口IP,流量会全部打到同一个Pod,负载不均衡。


六、金丝雀发布(基于Service简单实现)

金丝雀(canary):少量流量给到新版本,验证新版本是否稳定,再全量切换。

实现思路

  1. 两套Deployment:
    • stable(旧版本,多副本),标签track: stable
    • canary(新版本,少量副本),标签track: canary
  2. Service的selector同时匹配两套deployment的共同标签(app、tier),不区分track标签。
  3. 流量分配比例≈ 副本数量比例。
  4. 逐步减少旧副本数、增加新副本数,完成灰度升级。

示例:

  • 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为空代表使用默认)

bash 复制代码
root@master30:~# kubectl get cm -n kube-system kube-proxy -o yaml|grep mode

2)查看kube‑proxy Pod日志,确认实际运行模式

bash 复制代码
# 获取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模式

bash 复制代码
# 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调度算法

ini 复制代码
kubectl edit configmap kube-proxy -n kube-system
ipvs:
  scheduler: "wrr"
mode: "ipvs"

修改后重启daemonset:

ini 复制代码
kubectl rollout restart ds kube-proxy -n kube-system
相关推荐
艾伦_耶格宇2 小时前
【kubernetes - 1.28版本】-1 kubernetes基础
云原生·容器·kubernetes
时间售卖铺2 小时前
MySQL存储过程流程控制全解析
运维·数据库·mysql·云原生
Initialize-le2 小时前
PVC 一直 Pending?五步排查存储绑定
云原生·容器·kubernetes
9624562 小时前
一次 Kubernetes 临时存储压力引发的小程序授权雪崩:从 Pod 驱逐到定时任务漏执行
容器·小程序·kubernetes
SatanII2 小时前
Kubernetes 网络
网络·容器·kubernetes
知已难寻12 小时前
第 2 篇 · 云的地基:服务器、存储、网络三大基础设施
运维·服务器·网络·云原生·云计算·负载均衡·1024程序员节
阿里云云原生16 小时前
车企数据隐私保护必修课:如何用 SLS mask 守住日志中的敏感信息
云原生
阿里云云原生17 小时前
切换模型会损失缓存,智能路由还省钱吗?
云原生
闲云野鹤在人间17 小时前
Kubernetes Service 与 kube-proxy 详解
云原生·容器·kubernetes