Skip to content

Service

概述

Service 是 Kubernetes 中用于暴露应用服务的抽象层,为一组 Pod 提供稳定的网络访问入口和负载均衡。

关键点内容
核心作用提供 Pod 的稳定访问入口和负载均衡
选择机制通过标签选择器选择后端 Pod
网络抽象提供虚拟 IP 和 DNS 名称
服务发现支持 DNS 和环境变量服务发现

Service 的本质

设计理念

  • 服务抽象:将动态变化的 Pod 集合抽象为稳定的服务端点
  • 负载均衡:在多个 Pod 实例间分发流量
  • 服务发现:提供 DNS 名称和虚拟 IP 用于服务发现
  • 解耦架构:分离服务消费者和提供者,支持微服务架构

工作原理


## 高级配置

### 会话保持(Session Affinity)

```yaml
apiVersion: v1
kind: Service
metadata:
  name: session-affinity-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800  # 3小时

多端口服务

yaml
apiVersion: v1
kind: Service
metadata:
  name: multi-port-service
spec:
  selector:
    app: my-app
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 8080
    - name: https
      protocol: TCP
      port: 443
      targetPort: 8443
    - name: metrics
      protocol: TCP
      port: 9090
      targetPort: 9090

外部 IP 配置

yaml
apiVersion: v1
kind: Service
metadata:
  name: external-ip-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  externalIPs:
    - 192.168.1.100
    - 192.168.1.101

健康检查配置

yaml
apiVersion: v1
kind: Service
metadata:
  name: health-check-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  # 配合 Endpoint 健康检查
  publishNotReadyAddresses: false  # 默认值,不发布未就绪的地址

服务发现

DNS 服务发现

完整 DNS 名称格式

<service-name>.<namespace>.svc.<cluster-domain>

示例

bash
# 同命名空间内访问
curl http://my-service:80

# 跨命名空间访问
curl http://my-service.production.svc.cluster.local:80

# 简化访问(同命名空间)
curl http://my-service

环境变量服务发现

Kubernetes 会为每个 Service 创建环境变量:

bash
# 对于名为 my-service 的服务
MY_SERVICE_SERVICE_HOST=10.0.0.1
MY_SERVICE_SERVICE_PORT=80
MY_SERVICE_PORT=tcp://10.0.0.1:80
MY_SERVICE_PORT_80_TCP=tcp://10.0.0.1:80
MY_SERVICE_PORT_80_TCP_PROTO=tcp
MY_SERVICE_PORT_80_TCP_PORT=80
MY_SERVICE_PORT_80_TCP_ADDR=10.0.0.1

Endpoint 管理

查看 Endpoint

bash
# 查看 Service 对应的 Endpoint
kubectl get endpoints my-service

# 详细信息
kubectl describe endpoints my-service

手动管理 Endpoint

yaml
apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
# 注意:没有 selector

---
apiVersion: v1
kind: Endpoints
metadata:
  name: external-service  # 必须与 Service 名称相同
subsets:
  - addresses:
      - ip: 192.168.1.100
      - ip: 192.168.1.101
    ports:
      - port: 80
        protocol: TCP

监控和调试

常用命令

bash
# 查看 Service 列表
kubectl get services

# 查看 Service 详细信息
kubectl describe service my-service

# 查看 Service 的 Endpoint
kubectl get endpoints my-service

# 查看 kube-proxy 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy

# 测试服务连通性
kubectl run test-pod --image=busybox --rm -it -- /bin/sh
# 在 Pod 内执行
wget -qO- http://my-service:80

网络调试

bash
# 查看 iptables 规则(iptables 模式)
sudo iptables -t nat -L KUBE-SERVICES

# 查看 IPVS 规则(ipvs 模式)
sudo ipvsadm -Ln

# 查看 Service 的 ClusterIP
kubectl get service my-service -o jsonpath='{.spec.clusterIP}'

# 端口转发测试
kubectl port-forward service/my-service 8080:80

故障排查

常见问题

问题可能原因解决方案
Service 无法访问标签选择器不匹配检查 Service selector 和 Pod labels
连接超时Pod 未就绪检查 Pod 状态和健康检查
负载不均衡kube-proxy 配置问题检查 kube-proxy 模式和配置
DNS 解析失败CoreDNS 问题检查 CoreDNS Pod 状态
外部访问失败防火墙或网络策略检查网络策略和防火墙规则

诊断步骤

  1. 检查 Service 配置
bash
kubectl describe service my-service
  1. 检查 Endpoint
bash
kubectl get endpoints my-service
  1. 检查 Pod 标签
bash
kubectl get pods --show-labels
  1. 测试网络连通性
bash
# 从集群内测试
kubectl run debug --image=busybox --rm -it -- /bin/sh
telnet my-service 80
  1. 检查 kube-proxy
bash
kubectl get pods -n kube-system -l k8s-app=kube-proxy
kubectl logs -n kube-system -l k8s-app=kube-proxy

性能优化

选择合适的代理模式

yaml
# kube-proxy 配置
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"  # 推荐使用 ipvs
ipvs:
  scheduler: "rr"  # 轮询调度
  strictARP: true

会话保持优化

yaml
apiVersion: v1
kind: Service
metadata:
  name: optimized-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  # 根据需要选择会话保持策略
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 3600  # 1小时,根据业务需求调整

减少网络跳转

yaml
apiVersion: v1
kind: Service
metadata:
  name: local-traffic-service
  annotations:
    service.kubernetes.io/topology-aware-hints: auto
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  # 优先路由到本地节点的 Pod
  externalTrafficPolicy: Local  # 仅对 NodePort 和 LoadBalancer 有效
  internalTrafficPolicy: Local   # Kubernetes 1.22+

最佳实践

1. 命名规范

yaml
# 推荐的命名方式
metadata:
  name: frontend-web-service      # 描述性名称
  labels:
    app: frontend
    component: web
    version: v1.0
  annotations:
    description: "Frontend web service for user interface"

2. 标签选择器设计

yaml
# 精确的标签选择
spec:
  selector:
    app: my-app
    version: v1.0
    environment: production

3. 端口配置

yaml
spec:
  ports:
    - name: http          # 为端口命名
      protocol: TCP
      port: 80           # Service 端口
      targetPort: http   # 使用容器端口名称
    - name: metrics
      protocol: TCP
      port: 9090
      targetPort: 9090

4. 安全配置

yaml
metadata:
  annotations:
    # 限制访问来源
    service.beta.kubernetes.io/load-balancer-source-ranges: "10.0.0.0/8,172.16.0.0/12"
spec:
  # 仅内部访问
  type: ClusterIP
  # 或使用网络策略进一步限制

5. 监控集成

yaml
metadata:
  labels:
    app: my-app
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "9090"
    prometheus.io/path: "/metrics"
spec:
  ports:
    - name: web
      port: 80
      targetPort: 8080
    - name: metrics
      port: 9090
      targetPort: 9090

总结

Service 是 Kubernetes 网络架构的核心组件,提供了稳定的服务发现和负载均衡能力。通过合理选择 Service 类型、配置代理模式和优化网络策略,可以构建高性能、高可用的微服务架构。

关键要点

  • 根据访问需求选择合适的 Service 类型
  • 在大规模集群中优先使用 IPVS 代理模式
  • 合理配置会话保持和流量策略
  • 建立完善的监控和故障排查机制
  • 遵循安全和性能最佳实践 客户端请求 → Service (虚拟IP) → kube-proxy → 后端Pod ↓ 标签选择器匹配 ↓ Pod1, Pod2, Pod3...

## Service 类型详解

| 类型 | 功能 | 使用场景 | 访问方式 |
| ---- | ---- | ---- | ---- |
| `ClusterIP`(默认) | 仅集群内部可访问 | 微服务间调用 | ClusterIP:Port |
| `NodePort` | 将服务暴露在每个 Node 的某个端口上 | 集群外部通过 Node IP + 端口访问 | NodeIP:NodePort |
| `LoadBalancer` | 通过云提供商分配一个公网负载均衡 IP | 公网服务,如 API 接口 | LoadBalancerIP:Port |
| `ExternalName` | 将服务映射为 DNS 名称 | 接入外部服务,如 `mysql.example.com` | DNS CNAME 记录 |
| `Headless Service` | DNS 显示所有 Pod IP,提供直连能力 | 需要感知 Pod 实例,比如 StatefulSet、数据库等 | 直接访问 Pod IP |

### 1. ClusterIP Service

**特点**:
- 默认类型,仅集群内部可访问
- 分配一个集群内部的虚拟 IP
- 通过 kube-proxy 实现负载均衡

```yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

2. NodePort Service

特点

  • 在每个节点上开放一个端口(30000-32767)
  • 外部可通过 <NodeIP>:<NodePort> 访问
  • 自动创建 ClusterIP
yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nodeport-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
      nodePort: 30080
  type: NodePort

3. LoadBalancer Service

特点

  • 需要云提供商支持
  • 自动创建外部负载均衡器
  • 分配公网 IP 地址
yaml
apiVersion: v1
kind: Service
metadata:
  name: my-loadbalancer-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer

4. ExternalName Service

特点

  • 将服务映射到外部 DNS 名称
  • 不创建 ClusterIP
  • 返回 CNAME 记录
yaml
apiVersion: v1
kind: Service
metadata:
  name: my-external-service
spec:
  type: ExternalName
  externalName: database.example.com

5. Headless Service

特点

  • 设置 clusterIP: None
  • DNS 查询返回所有 Pod IP
  • 用于有状态服务
yaml
apiVersion: v1
kind: Service
metadata:
  name: my-headless-service
spec:
  clusterIP: None
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

完整配置示例

Deployment + Service 示例

yaml
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: web
        image: nginx
        ports:
        - containerPort: 80

---
# Service
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
  - port: 80        # Service 暴露的端口
    targetPort: 80  # Pod 内部容器的端口

效果: 自动创建一个虚拟 IP(ClusterIP)

所有访问 my-service:80 的流量被转发到匹配标签 app: my-app 的 Pod 中

Service 的核心机制

服务发现

Service 在集群内注册为一个 DNS 名称

比如:my-service.default.svc.cluster.local

Pod 之间可通过 DNS 名称互相访问

负载均衡

kube-proxy 在每个节点上运行,维护 iptables 或 IPVS 规则

访问 Service IP 时,会被转发到后端某个 Pod

默认使用 轮询策略

机制

模式使用方式实现机制性能说明
userspace已淘汰kube-proxy 接收请求、转发早期方案,不再推荐
iptables默认方式(较早版本)利用内核 iptables NAT 转发规则规则多时维护开销大
ipvs推荐方式(现代部署)使用 Linux 内核 IPVS 模块性能更强、维护高效

iptables 模式详解

工作机制
  1. kube-proxy 监听 Service 和 Endpoint 的变化

  2. 为每个 Service 创建一条 iptables DNAT 规则

  3. 为每个 Endpoint 创建 随机轮询跳转规则

示例(简化)
shell
# 访问 10.0.0.1:80 会被重定向到某个 Pod 的 IP:80
-A KUBE-SERVICES -d 10.0.0.1/32 --dport 80 -j KUBE-SVC-ABCDE

# KUBE-SVC-ABCDE 链会使用随机策略跳转到真实后端 Pod
-A KUBE-SVC-ABCDE -j KUBE-SEP-1111
-A KUBE-SVC-ABCDE -j KUBE-SEP-2222

# KUBE-SEP-1111 跳转到实际 Pod IP
-A KUBE-SEP-1111 -s 172.17.0.2/32 -j DNAT --to-destination 172.17.0.2:80
特点
  • 所有规则都写死在 iptables 中

  • Pod 变动时需要重建规则 → 多 Pod 时效率下降

  • 使用 随机轮询(不支持加权)

IPVS 模式详解(推荐)

IPVS(IP Virtual Server)是 Linux 内核提供的高性能负载均衡技术。

开启,kube-proxy 启动参数包含:

shell
--proxy-mode=ipvs

节点需要安装内核模块:

shell
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
工作流程
  1. kube-proxy 将 Service/Endpoint 转换为 ipvsadm 规则

  2. 系统调用内核级别 IPVS 实现负载均衡

  3. 每个 Service 变为一个虚拟服务(Virtual Server)

  4. 每个 Pod 成为一个真实服务(Real Server)

示例(使用 ipvsadm -Ln 查看)
nginx
TCP  10.0.0.1:80 rr
  -> 172.17.0.2:80            Masq    1      0          0
  -> 172.17.0.3:80            Masq    1      0          0
  • rr:轮询(Round Robin)策略

  • Masq:使用 NAT 转发方式(Masquerade)

核心特点
  1. 内核实现,高性能、低延迟

  2. 支持更多调度策略(见下方)

  3. 即时响应 Pod 变更,效率高

IPVS 支持的调度算法(调度策略)

策略名称含义
rr (Round Robin)轮询,默认策略
wrr (Weighted RR)加权轮询,支持不同权重
lc (Least Connection)最少连接数
wlc (Weighted LC)加权最少连接数
sh (Source Hashing)基于源IP做一致性哈希,用于 session 粘性
dh (Destination Hashing)基于目标IP做一致性哈希

性能与对比分析

项目iptablesipvs
实现方式用户空间维护规则,内核转发全部内核态实现
规则数量大时效率随着 Pod 增多性能下降规则查找稳定高效
调度策略仅支持轮询多种高效调度算法
响应变化速度规则重建延迟大快速生效
推荐程度中等(兼容性好)高(大规模集群首选)

选择建议

场景推荐模式
小规模开发环境iptables(易部署)
中大型生产环境ipvs(高性能)
对连接追踪依赖强iptables
希望高并发、快速切换后端 Podipvs

常见问题排查

问题排查方法
Service IP 不通kubectl get endpoints 看是否为空
kube-proxy 不工作查看 kube-proxy Pod 日志
ipvs 模式不生效检查内核模块是否加载成功
转发不均衡检查是否启用 sessionAffinity
规则过多导致变慢考虑切换为 IPVS 模式

Session Affinity(会话保持)

Kubernetes 通过 Service 实现负载均衡。默认情况下,请求被随机分配到后端 Pod。但启用 SessionAffinity 后,会根据 客户端 IP 地址 绑定目标 Pod。

开启配置

yaml
spec:
  sessionAffinity: ClientIP  # 同一个客户端访问保持连接到同一个 Pod

使用场景

场景是否推荐启用会话保持
登录状态保存在 Pod✅ 是
视频会议系统✅ 是
无状态 Web 接口(REST API)❌ 否
依赖 Cookie 的轻会话(JWT)❌ 否(推荐使用 Cookie 识别)

注意事项

项目说明
粒度基于 客户端 IP 地址,不支持 Cookie 或 Header
节点间共享各 Node 的 kube-proxy 独立维护映射,跨 Node 效果可能不一致(iptables 模式)
超时不可忽略过期后会重新负载均衡,可能“粘性失效”
IPVS 优势IPVS 模式下更高效,天然支持会话表维护
配置范围SessionAffinity 是 Service 层的配置,对 Pod 本身无感知

对比

机制粘性依据可配置性说明
SessionAffinity: ClientIP客户端 IP支持 timeout 设置最常见
Ingress Cookie-based Sticky SessionCookie灵活(支持多个路由规则)适用于 HTTP
Web 应用自行实现粘性Token / Header高度可控服务逻辑实现,适用于复杂路由需求

Headless Service

yaml
apiVersion: v1
kind: Service
metadata:
  name: my-db
spec:
  clusterIP: None
  selector:
    app: my-db
  ports:
    - port: 5432

说明:

  • 不分配 ClusterIP

  • DNS 解析返回所有 Pod 的 IP 地址

  • 用于客户端需要直接访问某个 Pod 的场景,如:

    • StatefulSet(有序部署、主从数据库)

    • Kafka、Zookeeper 等需要节点感知的系统

Service 与 Ingress 的关系

  • Service 是基础网络单元

  • Ingress 是用于 HTTP/HTTPS 七层反向代理的入口控制器

  • Ingress 通常转发请求到一个或多个 Service,进行统一的 URL 路由、TLS 终结等处理

常用命令

shell
# 查看所有服务
kubectl get svc

# 查看服务详情
kubectl describe svc my-service

# 测试服务连接
kubectl run test --rm -it --image=busybox -- /bin/sh
> wget my-service:80

# 查看kube-proxy模式
kubectl get pod -n kube-system -l k8s-app=kube-proxy -o yaml | grep mode

典型问题与注意事项

问题原因解决方案
无法访问 Service标签选择器未匹配到 Pod检查 Deployment 与 Service 的 labels/selector 是否一致
Service 无响应Pod 没有监听端口或没就绪查看 Pod 状态,确认端口和 readiness probe
NodePort 无法外部访问节点防火墙或安全组限制检查防火墙规则、云平台安全组