Files
juwan-backend/docs/kubernetes-service-explanation.md
T

22 KiB
Raw Blame History

Redis Kubernetes Service 详细解析

问题: 为什么 Redis 有 8 个 Service,但应用配置中只使用 user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379

日期: 2026年2月22日


📋 目录

  1. Service 概览
  2. Kubernetes Service 基础
  3. 8 个 Service 的详细说明
  4. 为什么使用哪个 Service
  5. Service 创建原理
  6. 网络流量路由
  7. 故障排查

📊 Service 概览

当前 Redis 的 8 个 Service

$ kubectl get svc -n juwan | grep redis

NAME                                  TYPE        CLUSTER-IP       PORTS
user-redis                            ClusterIP   10.103.91.84     6379/TCP,9121/TCP   33m
user-redis-additional                 ClusterIP   10.107.228.48    6379/TCP            33m
user-redis-headless                   ClusterIP   None             6379/TCP            33m
user-redis-master                     ClusterIP   10.97.120.76     6379/TCP            33m
user-redis-replica                    ClusterIP   10.100.213.103   6379/TCP            33m
user-redis-sentinel-sentinel          ClusterIP   10.105.28.231    26379/TCP           32m
user-redis-sentinel-sentinel-additional ClusterIP  10.97.111.42     26379/TCP           32m
user-redis-sentinel-sentinel-headless ClusterIP   None             26379/TCP           32m

按功能分类

分类 Service 名称 作用
Redis 数据层 user-redis 通用入口
user-redis-additional 备用入口
user-redis-master 主节点专用
user-redis-replica 从节点专用
user-redis-headless Pod 间通信
Sentinel 监控层 user-redis-sentinel-sentinel Sentinel 入口
user-redis-sentinel-sentinel-additional 备用入口
user-redis-sentinel-sentinel-headless Sentinel 间通信

🔷 Kubernetes Service 基础

Service 的作用

Kubernetes 中的 Service 是什么?

┌─────────────────────────────────────────────────┐
│                  Kubernetes Cluster             │
│                                                 │
│  Service (虚拟 IP + DNS)                        │
│  ↓                                              │
│  Endpoints (实际 Pod IP 列表)                    │
│  ├─ 10.244.0.10:6379  (Pod 1)                   │
│  ├─ 10.244.1.20:6379  (Pod 2)                   │
│  └─ 10.244.2.30:6379  (Pod 3)                   │
│                                                 │
│  客户端 ──→ Service IP (稳定) ──→ Pod IP (变化)   │
└─────────────────────────────────────────────────┘

Service 的三种类型

类型 CLUSTER-IP 用途 示例
ClusterIP 集群内访问 10.103.91.84
ClusterIP
(Headless)
None Pod 间直接通信 None
NodePort 集群外访问 10.103.91.84

🔍 8 个 Service 的详细说明

第一组:Redis 数据层 Service(端口 6379

1️⃣ user-redisClusterIP

基本信息:

名称: user-redis
类型: ClusterIP (有负载均衡)
Cluster IP: 10.103.91.84
端口: 6379/TCP, 9121/TCP
DNS: user-redis.juwan.svc.cluster.local

Endpoints 信息:

$ kubectl get endpoints user-redis -n juwan

NAME         ENDPOINTS
user-redis   10.244.0.10:6379,10.244.1.20:6379,10.244.2.30:6379

负载均衡机制:

客户端请求 ──→ Service IP (10.103.91.84)
                     ↓
              kube-proxy (iptables/ipvs)
                     ↓
            随机选择一个 Pod
            ├─ 10.244.0.10 (redis-0)
            ├─ 10.244.1.20 (redis-1)  ← 可能
            └─ 10.244.2.30 (redis-2)

特点:

  • 对所有 Pod 轮询负载均衡
  • 包含 Redis 数据服务(6379)和 Exporter9121
  • ⚠️ 可能把写请求轮询到从节点导致失败

适用场景:

  • 监控抓取(Prometheus 从 9121 端口抓指标)
  • 不关心读写分离的简单查询

为什么有 2 个端口?

6379: Redis 数据服务
9121: Prometheus Exporter 监控端口
      └─ 暴露 Redis 性能指标给 Prometheus
         (redis_up, redis_memory_used, etc.)

不用这个的原因:

❌ 如果直接使用 user-redis 进行读写:
   ├─ 写请求可能被路由到从节点 (error)
   ├─ 无法进行故障自动转移
   └─ 依赖于手动更新配置

2️⃣ user-redis-additionalClusterIP

基本信息:

名称: user-redis-additional
类型: ClusterIP (有负载均衡)
Cluster IP: 10.107.228.48
端口: 6379/TCP
Endpoints: 同 user-redis

作用:

  • 功能完全同 user-redis
  • 提供额外的访问入口
  • 用于多租户/网络隔离场景

为什么有这个?

场景:某些网络策略可能只允许访问特定 Service
└─ 额外的 Service 提供备用入口

不常用的原因:

  • 大多数场景用 user-redis 就足够
  • user-redis-additional 是备用

3️⃣ user-redis-headlessClusterIP: None

基本信息:

名称: user-redis-headless
类型: ClusterIP (Headless Service)
Cluster IP: None  ← 关键:无虚拟 IP
端口: 6379/TCP
DNS: user-redis-headless.juwan.svc.cluster.local

特殊之处:无虚拟 IP

# 正常 Service 查询返回虚拟 IP
$ nslookup user-redis.juwan.svc.cluster.local
Name: user-redis.juwan.svc.cluster.local
Address: 10.103.91.84  ← 虚拟 IP

# Headless Service 查询返回所有 Pod IP
$ nslookup user-redis-headless.juwan.svc.cluster.local
Name: user-redis-headless.juwan.svc.cluster.local
Address: 10.244.0.10   ← Pod 1 实际 IP
Address: 10.244.1.20   ← Pod 2 实际 IP
Address: 10.244.2.30   ← Pod 3 实际 IP

使用场景:

┌─────────────────────────────────────────────────┐
│  StatefulSet (Redis Cluster/Replication)       │
│                                                 │
│  redis-0 (主)   redis-1 (从)   redis-2 (从)    │
│     ↓               ↓               ↓           │
│  10.244.0.10   10.244.1.20    10.244.2.30      │
│                    ↑                            │
│  需要直接连接到特定 Pod:                        │
│  redis-0.user-redis-headless  (连接主节点)      │
│  redis-1.user-redis-headless  (连接从节点)      │
└─────────────────────────────────────────────────┘

谁在使用?

  • Redis 主从复制:从节点需要连接到已知的主节点
  • Sentinel 监控:需要直接访问特定 Redis 实例
  • Redis Operator 内部使用

为什么应用不用这个?

❌ Pod DNS 只能在 Pod 内使用
   └─ 外部应用不知道 Pod 的具体 DNS 名称

✅ 用虚拟 Service IP 的优势
   └─ 无需关心底层 Pod 变化

4️⃣ user-redis-masterClusterIP

基本信息:

名称: user-redis-master
类型: ClusterIP
Cluster IP: 10.97.120.76
端口: 6379/TCP
Endpoints: 10.244.0.10:6379  (只有 1 个 Pod)
DNS: user-redis-master.juwan.svc.cluster.local

特点:只指向主节点

$ kubectl get endpoints user-redis-master -n juwan

NAME                ENDPOINTS
user-redis-master   10.244.0.10:6379  ← 仅主节点

对比所有 Endpoints

user-redis-master:  10.244.0.10        (主)
user-redis-replica: 10.244.1.20, 10.244.2.30  (从)
user-redis:         所有 Pod

为什么分开?

┌─────────────────────────────────────────┐
│        Redis 主从架构                    │
│                                         │
│  Redis Master (10.244.0.10)             │
│    ├─ 处理所有写操作                     │
│    └─ 赋值数据给 Slave                   │
│                                         │
│  Redis Slave 1 (10.244.1.20)            │
│    └─ 处理只读操作                       │
│                                         │
│  Redis Slave 2 (10.244.2.30)            │
│    └─ 处理只读操作                       │
└─────────────────────────────────────────┘

请求分类:
┌───────────────────────┐
│ SET key value         │ ──→ user-redis-master (10.97.120.76)
│ HSET user:1 name john │
└───────────────────────┘

┌───────────────────────┐
│ GET key               │ ──→ user-redis-replica (10.100.213.103)
│ HGET user:1 name      │
└───────────────────────┘

适用场景:

  • 读写分离架构
  • 优化读性能(从节点处理读)
  • 减轻主节点负担

为什么应用通常不直接用?

❌ 需要在应用层面区分读写操作
   ├─ 写操作 → user-redis-master
   ├─ 只读操作 → user-redis-replica
   └─ 代码复杂度高

✅ Sentinel 模式自动处理
   └─ 应用无需关心主从区别

5️⃣ user-redis-replicaClusterIP

基本信息:

名称: user-redis-replica
类型: ClusterIP
Cluster IP: 10.100.213.103
端口: 6379/TCP
Endpoints: 10.244.1.20:6379, 10.244.2.30:6379  (两个从节点)
DNS: user-redis-replica.juwan.svc.cluster.local

特点:只指向从节点,支持负载均衡

$ kubectl get endpoints user-redis-replica -n juwan

NAME                 ENDPOINTS
user-redis-replica   10.244.1.20:6379, 10.244.2.30:6379

读流量分散:

应用发送 GET 请求
          ↓
   user-redis-replica (10.100.213.103)
          ↓
   随机选择一个从节点
   ├─ 10.244.1.20 (redis-1) ← 可能
   └─ 10.244.2.30 (redis-2) ← 可能

适用场景:

  • 除了 Sentinel 模式外的读优化
  • 需要手动管理读写分离

第二组:Sentinel 监控层 Service(端口 26379

6️⃣ user-redis-sentinel-sentinelClusterIP

基本信息:

名称: user-redis-sentinel-sentinel
类型: ClusterIP
Cluster IP: 10.105.28.231
端口: 26379/TCP
Endpoints: 10.244.0.50:26379, 10.244.1.70:26379, 10.244.2.90:26379
           (3 个 Sentinel 实例)
DNS: user-redis-sentinel-sentinel.juwan.svc.cluster.local

为什么应用使用这个?

应用程序配置:
┌──────────────────────────────────────────────┐
│ Redis:                                       │
│   Host: user-redis-sentinel-sentinel         │
│   Port: 26379                                │
│   Type: sentinel                             │
│   MasterName: mymaster                       │
└──────────────────────────────────────────────┘

连接流程:
┌─────────────────────────────────────────────┐
│                 应用程序                     │
└────────────────────┬────────────────────────┘
                     │
                     ↓
┌─────────────────────────────────────────────┐
│  user-redis-sentinel-sentinel (26379)        │
│  ├─ Sentinel 1: 10.244.0.50:26379           │
│  ├─ Sentinel 2: 10.244.1.70:26379           │
│  └─ Sentinel 3: 10.244.2.90:26379           │
└────────────────────┬────────────────────────┘
                     │
         应用询问: "mymaster 在哪?"
                     ↓
         Sentinel 回答: "在 10.244.0.10:6379"
                     ↓
┌─────────────────────────────────────────────┐
│  Redis Master: 10.244.0.10:6379              │
│  (应用直接连接进行读写)                      │
└─────────────────────────────────────────────┘

故障转移过程:
Master 故障 → Sentinel 检测 → 提升新主节点
           → 应用下次查询时 → 获得新主节点 IP
           → 自动连接新主节点

为什么这是最佳选择?

  1. 自动故障转移

    主节点宕机 (✗) → Sentinel 自动选举新主 → 应用自动连接
    
  2. 高可用

    Sentinel 集群(3 个) → 任意 1-2 个故障仍可用
    
  3. 应用无感知

    应用只需配置 MasterName: mymaster
    无需关心主从地址变化
    
  4. 标准做法

    ✅ 业界公认的 Redis 高可用方案
    ✅ 最小化应用改动
    ✅ 自动化程度最高
    

为什么不用其他 Service

❌ user-redis-master/user-redis-replica
   └─ 需要应用层区分读写,主从切换需要重启应用

❌ user-redis/user-redis-additional
   └─ 没有故障转移能力,故障时应用会报错

✅ user-redis-sentinel-sentinel
   └─ 自动发现新主节点,无需重启应用

7️⃣ user-redis-sentinel-sentinel-additionalClusterIP

说明: 功能同 user-redis-sentinel-sentinel,备用入口


8️⃣ user-redis-sentinel-sentinel-headlessClusterIP: None

说明: 供 Sentinel 内部通信和选举使用


🎯 为什么使用哪个 Service

应用配置选择

Sentinel 模式(生产推荐)

# 应用配置
Redis:
  Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
  Type: sentinel
  MasterName: mymaster
  Pass: ${REDIS_PASSWORD}

优势:

  • 自动故障转移(RTO < 30 秒)
  • 应用无需重启
  • 自动发现新主节点
  • 生产标准做法

主从分离模式(可选)

# 应用配置(需要两个 host
Redis:
  Master:
    Host: user-redis-master.juwan.svc.cluster.local:6379
  Slave:
    Host: user-redis-replica.juwan.svc.cluster.local:6379

适用场景:

  • 读写分离显著
  • 对读性能有极高要求

缺点:

  • 主从故障需手动切换
  • 应用层复杂度高

不推荐的做法

# ❌ 直接连接单个节点
Redis:
  Host: user-redis-0.user-redis-headless.juwan.svc.cluster.local:6379
  # 问题:Pod 重启 IP 变化,需要更新配置

# ❌ 连接通用 Service(无故障转移)
Redis:
  Host: user-redis.juwan.svc.cluster.local:6379
  # 问题:无法自动转移,故障时应用报错

# ❌ 硬编码 Pod IP
Redis:
  Host: 10.244.0.10:6379
  # 问题:Pod 重启 IP 变化,应用立即不可用

🔌 Service 创建原理

为什么会自动创建这么多 Service?

由 Redis Operator 自动创建:

// Redis Operator 逻辑(伪代码)
func CreateServicesForRedis(redis *RedisReplication) {
    // 数据层 Service
    CreateService("user-redis", AllRedisNodes)
    CreateService("user-redis-additional", AllRedisNodes)
    CreateService("user-redis-master", [MasterNode])
    CreateService("user-redis-replica", [SlaveNodes])
    CreateHeadlessService("user-redis-headless", AllRedisNodes)
    
    // 监控层 Service
    CreateService("user-redis-sentinel-sentinel", AllSentinelNodes)
    CreateService("user-redis-sentinel-sentinel-additional", AllSentinelNodes)
    CreateHeadlessService("user-redis-sentinel-sentinel-headless", AllSentinelNodes)
}

为什么这样设计?

Service 原因
多个 ClusterIP 不同场景需要不同的 Endpoints 配置
包含 additional 网络隔离/多租户支持
包含 headless StatefulSet 需要 Pod 间直接通信

类比:

Redis Operator 就像一个完整的产品
└─ 提供多种方式使用 Redis
   ├─ 简单: user-redis
   ├─ 高级: user-redis-master/replica
   ├─ HA: user-redis-sentinel-sentinel
   └─ 内部: headless services

🌐 网络流量路由

查询 Service 背后的 Pod

查看 Service Endpoints

# 查看 user-redis 关联的 Pod
$ kubectl get endpoints user-redis -n juwan
NAME         ENDPOINTS
user-redis   10.244.0.10:6379,10.244.1.20:6379,10.244.2.30:6379

# 查看 user-redis-master 关联的 Pod
$ kubectl get endpoints user-redis-master -n juwan
NAME                ENDPOINTS
user-redis-master   10.244.0.10:6379

# 查看 user-redis-replica 关联的 Pod
$ kubectl get endpoints user-redis-replica -n juwan
NAME                 ENDPOINTS
user-redis-replica   10.244.1.20:6379,10.244.2.30:6379

Pod 和 Service 的映射关系:

Pods (实际运行的实例)          Services (虚拟 IP)
└─ redis-0 (主)              └─ user-redis (所有)
   ├─ 10.244.0.10              ├─ 10.103.91.84
   └─ :6379
                              └─ user-redis-master (仅主)
└─ redis-1 (从)                 ├─ 10.97.120.76
   ├─ 10.244.1.20
   └─ :6379
                              └─ user-redis-replica (仅从)
└─ redis-2 (从)                 ├─ 10.100.213.103
   ├─ 10.244.2.30
   └─ :6379

DNS 解析过程:

应用 DNS 查询
  └─ user-redis-master.juwan.svc.cluster.local
       ↓
CoreDNS (Kubernetes DNS)
  └─ 查询并返回 Service IP:
       ├─ 10.97.120.76 (user-redis-master)
       ├─ 或 10.100.213.103 (user-redis-replica)
       ├─ 或 10.103.91.84 (user-redis)
       └─ 或 Sentinel 的 IP

Sentinel 模式的特殊之处:

应用查询 Sentinel
  └─ user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
       ↓
Sentinel Service (负载均衡到 3 个 Sentinel 节点)
       ↓
Sentinel 节点 (任选一个)
       ↓
应用询问: "mymaster 主节点 IP 是什么?"
       ↓
Sentinel 回答: "10.244.0.10:6379"
       ↓
应用直接连接 Redis Master: 10.244.0.10:6379

🔧 故障排查

问题 1:为什么应用连接失败?

检查步骤:

# 1. 验证 Service 存在
kubectl get svc user-redis-sentinel-sentinel -n juwan

# 2. 验证 Endpoints 不为空
kubectl get endpoints user-redis-sentinel-sentinel -n juwan

# 3. 测试 DNS 解析
kubectl run -it --rm nettest --image=busybox --restart=Never -n juwan -- \
  nslookup user-redis-sentinel-sentinel.juwan.svc.cluster.local

# 4. 测试连接性
kubectl run -it --rm nettest --image=busybox --restart=Never -n juwan -- \
  nc -zv user-redis-sentinel-sentinel.juwan.svc.cluster.local 26379

# 5. 查看应用日志
kubectl logs -f user-rpc-xxx -n juwan

问题 2:为什么看不到某个 Service?

# 确保在正确的命名空间
kubectl get svc -n juwan | grep redis

# 如果 Redis Operator 有问题,Service 可能不会创建
# 查看 Operator 日志
kubectl logs -n default deployment/redis-operator

问题 3Service IP 经常变化?

# Service IP 是稳定的(除非被删除和重建)
# 如果频繁变化,说明 Service 被频繁重建

# 检查 Service 创建事件
kubectl describe svc user-redis-sentinel-sentinel -n juwan

# 检查 Operator 是否有异常
kubectl describe redissentinel user-redis-sentinel -n juwan

📚 总结

快速理解

Service 用途 应用是否使用
user-redis-sentinel-sentinel Sentinel 高可用 生产推荐
user-redis-master 直连主节点 ⚠️ 需要读写分离
user-redis-replica 直连从节点 ⚠️ 需要读写分离
user-redis 通用入口 不推荐(无 HA
headless services 内部通信 应用不用

为什么有这么多 Service

答案: 为了提供灵活的使用方式

Redis Operator 的设计理念:
┌─────────────────────────────────────────┐
│  提供完整的 Redis 高可用解决方案         │
│                                         │
│  ├─ 简单使用场景                       │
│  │  └─ user-redis (所有节点)           │
│  │                                     │
│  ├─ 高级使用场景                       │
│  │  ├─ user-redis-master (写)          │
│  │  └─ user-redis-replica (读)         │
│  │                                     │
│  ├─ 生产场景 (推荐)                    │
│  │  └─ user-redis-sentinel-sentinel    │
│  │                                     │
│  └─ 内部通信                           │
│     └─ headless services               │
└─────────────────────────────────────────┘

应用该用哪个?

一句话:使用 user-redis-sentinel-sentinel:26379 + Sentinel 模式

# 这是最佳实践
Redis:
  Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
  Type: sentinel
  MasterName: mymaster

为什么?

  • 自动故障转移
  • 应用无需重启
  • 无需手工干预
  • 行业标准

文档版本: 1.0
创建日期: 2026年2月22日
维护者: DevOps Team