小项目:Headless Service 与 StatefulSet(MySQL 风格行为)
Source: Dev.to
请提供您希望翻译的完整文本内容(除代码块和 URL 之外),我将按照要求将其翻译成简体中文并保持原有的 Markdown 格式。
🎯 目标
By the end you will clearly see:
- 为什么 ClusterIP 隐藏 pod 身份
- 为什么 Headless Service 暴露 pod 身份
- 如何 StatefulSet + Headless Service 提供 每个 pod 的稳定 DNS(数据库所需的魔法)
🧠 Mental model (keep this in mind)
| 设置 | DNS 结果 |
|---|---|
| Deployment + ClusterIP | 一个虚拟 IP |
| Deployment + Headless | 多个 pod IP |
| StatefulSet + Headless | 稳定的 pod DNS 名称(魔法) |
🧩 项目结构
headless-demo/
├── mysql-headless.yaml
├── mysql-statefulset.yaml
└── dns-test.yaml
1️⃣ 无头服务(NO ClusterIP)
文件: mysql-headless.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None # 👈 THIS MAKES IT HEADLESS
selector:
app: mysql
ports:
- port: 3306
重要提示:
- 不会创建虚拟 IP。
- DNS 将返回 Pod IP。
2️⃣ StatefulSet(稳定的 pod 身份)
文件: mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless # 👈 REQUIRED
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: root
ports:
- containerPort: 3306
StatefulSet 的保证
mysql-0
mysql-1
mysql-2
- 名称 永不改变
- 身份 稳定
3️⃣ DNS 测试 Pod(观察行为)
文件: dns-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: dns-test
spec:
containers:
- name: dns
image: busybox:1.28
command: ["sleep", "3600"]
4️⃣ 应用所有内容(顺序很重要)
kubectl apply -f mysql-headless.yaml
kubectl apply -f mysql-statefulset.yaml
kubectl apply -f dns-test.yaml
等待 Pod 准备就绪:
kubectl get pods
您应该看到:
mysql-0 Running
mysql-1 Running
mysql-2 Running
dns-test Running
5️⃣ 🔥 最重要的部分 — DNS 行为
进入测试 pod
kubectl exec -it dns-test -- sh
对 headless 服务进行 DNS 查询
nslookup mysql-headless
结果 – 多个 IP(每个 pod 一个)
Address: 10.244.0.12
Address: 10.244.0.13
Address: 10.244.0.14
这就是 DNS 轮询。
对 单个 pod 进行 DNS 查询(关键)
nslookup mysql-0.mysql-headless
nslookup mysql-1.mysql-headless
nslookup mysql-2.mysql-headless
每个命令都会解析为 特定的 pod IP —— 这是普通的 ClusterIP 服务永远无法做到的。
6️⃣ 为什么数据库 需要 这样
| 角色 | DNS 名称 |
|---|---|
| 主库 | mysql-0.mysql-headless |
| 副本 1 | mysql-1.mysql-headless |
| 副本 2 | mysql-2.mysql-headless |
- 写入 →
mysql-0.mysql-headless(稳定的主库) - 读取 → 副本
- 复制 → 稳定的目标
不可能 使用 Deployment + ClusterIP,因为该服务隐藏了 Pod 的身份。
7️⃣ 直观视觉(正在发生的事)
| Headless Service + StatefulSet | ClusterIP Service |
|---|---|
![]() | ![]() |
8️⃣ One‑line interview answer (remember this)
“Headless Service 移除虚拟 IP,并通过 DNS 暴露 Pod 身份。结合 StatefulSets,它提供稳定的每个 Pod 的 DNS 名称,这对于数据库和主从架构是必需的。”
🔥 同一应用,两种服务
🟦 案例 1 — ClusterIP Service(默认行为)
YAML(普通服务)
apiVersion: v1
kind: Service
metadata:
name: mysql-clusterip
spec:
selector:
app: mysql
ports:
- port: 3306
Kubernetes 的行为
- 创建 一个虚拟 IP
- 隐藏所有 pod IP
kube-proxy进行负载均衡
集群内部的 DNS 行为
nslookup mysql-clusterip
Name: mysql-clusterip
Address: 10.96.120.15 mysql-0
+--> mysql-1
+--> mysql-2
Kubernetes 决定哪个 pod 接收每个请求。
❌ 为什么这会导致数据库问题
如果写入落在任何副本(例如 mysql-2)上,主节点可能看不到,导致一致性和复制出现问题。使用带有稳定 pod DNS 的无头服务可以避免此问题。
❌ 问题:登录失败
- Login request → mysql-0 (no data)
- ❌ login fails
为什么?
写入和读取流量命中 不同的 pods。Pod 身份是隐藏的,因此无法强制流量始终路由到 mysql-0。
ClusterIP 是 无状态友好 的,但 有状态敌对 的。
🟨 案例 2 — 无头服务(无 CLUSTER IP)
我们只在 Service 定义中 更改一行。
YAML(无头服务)
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None # 👈 THIS IS EVERYTHING
selector:
app: mysql
ports:
- port: 3306
🔍 DNS 行为(关键区别)
在 pod 内部:
nslookup mysql-headless
结果
Address: 10.244.0.10 (mysql-0)
Address: 10.244.0.11 (mysql-1)
Address: 10.244.0.12 (mysql-2)
- ⚠️ 没有虚拟 IP。
- ⚠️ DNS 直接返回 pod IP —— DNS 轮询,而非 kube‑proxy 负载均衡。
🧠 单独使用仍不足(重要)
如果你就此止步,仅使用 mysql-headless,你的应用仍可能因为 DNS 响应轮转而访问到不同的 pod。
仅使用 Headless 并不是完整的解决方案。
🟩 进入 StatefulSet(缺失的拼图)
StatefulSet 保证 稳定的 pod 名称:
mysql-0
mysql-1
mysql-2
Kubernetes 会为每个 pod 自动创建 DNS 记录:
mysql-0.mysql-headless
mysql-1.mysql-headless
mysql-2.mysql-headless
🔥 恍然大悟的瞬间
写入流量
mysql-0.mysql-headless
读取流量
mysql-1.mysql-headless
mysql-2.mysql-headless
无需猜测。没有随机性。
📊 并排摘要(请记住)
| 功能 | ClusterIP | Headless |
|---|---|---|
| 拥有虚拟IP | ✅ | ❌ |
| 隐藏Pod身份 | ✅ | ❌ |
| DNS返回 | 1个IP | 多个Pod IP |
| Pod特定DNS | ❌ | ✅ |
| 适用于Web应用 | ✅ | ❌ |
| 适用于数据库 | ❌ | ✅(使用StatefulSet) |
🧪 为什么我们使用 dns-test pod
你无法在笔记本电脑上“看到 DNS”。
创建一个 pod 仅用于运行:
nslookup
这就是 SRE 调试 真实生产问题 的方式。
🎯 ONE‑LINE INTERVIEW ANSWER (IMPORTANT)
“ClusterIP services 隐藏 pod 身份并对流量进行 load‑balance,这不适用于数据库。
Headless services 通过 DNS 暴露 pod IP,结合 StatefulSets 使用时,可提供状态工作负载所需的 stable per‑pod DNS。”



