Repository Reading Site
工作负载与服务发现 — K8s 的核心战斗力
想象一个公司有开发、测试、生产三个环境。没有 Namespace 的话,所有资源混在一起: Namespace 提供: 1. **名称隔离** — 不同 NS 可以有同名资源 2. **权限隔离** — RBAC 可以限制用户只能操作某个 NS 3. **资源配额** — 限制每个 NS 最多用多少 CPU/内存 4. **网络隔离** — NetworkP
工作负载与服务发现 — K8s 的核心战斗力
Namespace — 虚拟集群隔离
kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace prod
为什么需要 Namespace?
想象一个公司有开发、测试、生产三个环境。没有 Namespace 的话,所有资源混在一起:
- 开发人员可能误删生产的 Pod
- 资源名称冲突(dev 和 prod 都有叫
nginx的 Deployment) - 无法按环境做资源配额
Namespace 提供:
- 名称隔离 — 不同 NS 可以有同名资源
- 权限隔离 — RBAC 可以限制用户只能操作某个 NS
- 资源配额 — 限制每个 NS 最多用多少 CPU/内存
- 网络隔离 — NetworkPolicy 可以禁止跨 NS 通信
K8s 默认的 Namespace
| Namespace | 用途 |
|---|---|
default |
不指定 NS 时资源放这里(别用,不好管理) |
kube-system |
K8s 系统组件(API Server、CoreDNS、kube-proxy 等) |
kube-public |
集群公开信息(cluster-info) |
kube-node-lease |
节点心跳租约(kubelet 用来报告存活状态) |
最佳实践: 永远不要往 default 放东西。创建专用 Namespace。
Deployment — 最常用的工作负载
创建
kubectl -n dev create deployment nginx --image=nginx:1.25 --replicas=3
这一条命令背后创建了三层对象:
Deployment (nginx)
└── ReplicaSet (nginx-7b97df8d44)
├── Pod (nginx-7b97df8d44-bsqqk) → 调度到 cp-3
├── Pod (nginx-7b97df8d44-xrqcd) → 调度到 us590068728056
└── Pod (nginx-7b97df8d44-ctm9h) → 调度到 wk-1
为什么是三层?
| 层 | 职责 | 面试常问 |
|---|---|---|
| Deployment | 管理版本更新策略(滚动更新/回滚) | "Deployment 和 ReplicaSet 的区别?" |
| ReplicaSet | 确保指定数量的 Pod 在运行 | "为什么不直接用 ReplicaSet?" |
| Pod | 运行实际的容器 | "Pod 和容器的区别?" |
答案:Deployment 在 ReplicaSet 之上增加了版本管理。每次更新镜像,Deployment 创建新的 ReplicaSet,逐步将 Pod 从旧 RS 迁移到新 RS。旧 RS 保留(replicas=0),用于回滚。
滚动更新(Rolling Update)
# 更新镜像版本
kubectl -n dev set image deployment/nginx nginx=nginx:1.27
更新过程(默认策略 maxSurge=25%, maxUnavailable=25%):
时间线:
T0: 旧Pod: ●●● (3个 nginx:1.25) 新Pod:
T1: 旧Pod: ●● (缩1个) 新Pod: ○ (启1个 nginx:1.27)
T2: 旧Pod: ● (缩1个) 新Pod: ○○ (启1个)
T3: 旧Pod: (缩1个) 新Pod: ○○○ (启1个)
关键参数:
- maxSurge=25% — 更新期间最多比期望多 25% 的 Pod(3*1.25=3.75 → 最多 4 个 Pod 同时存在)
- maxUnavailable=25% — 更新期间最多有 25% 的 Pod 不可用(3*0.75=2.25 → 至少 2 个 Pod 始终可用)
面试深度题: "如何实现零停机更新?"
maxUnavailable=0— 不允许任何 Pod 下线- 配置
readinessProbe— 确保新 Pod 真正就绪才接收流量 - 配置
preStophook — 旧 Pod 优雅关闭,处理完当前请求
我们的实际操作结果
更新前:3 个 Pod 运行 nginx:1.25
执行: kubectl set image deployment/nginx nginx=nginx:1.27
过程: 新 ReplicaSet nginx-86d7c4cfc4 创建,旧 RS 逐步缩容到 0
结果: 3 个 Pod 运行 nginx:1.27
ReplicaSet 状态:
nginx-7b97df8d44 DESIRED:0 (旧版本,保留用于回滚)
nginx-86d7c4cfc4 DESIRED:3 (新版本,当前运行)
Rollout History:
REVISION 1: nginx:1.25
REVISION 2: nginx:1.27
回滚
# 回滚到上一个版本
kubectl -n dev rollout undo deployment/nginx
# 回滚到指定版本
kubectl -n dev rollout undo deployment/nginx --to-revision=1
原理: 不是"重新部署旧镜像",而是把旧 ReplicaSet 的 replicas 从 0 调回来,新 RS 缩到 0。所以回滚是秒级的——旧版本的 RS 一直在那里。
Service — 服务发现与负载均衡
问题:Pod IP 不稳定
Pod 每次重建都会获得新 IP。你不能硬编码 Pod IP 来访问服务。
Service 的三种类型
ClusterIP(默认)— 集群内部访问
kubectl -n dev expose deployment nginx --port=80 --name=nginx-svc
创建后:
NAME TYPE CLUSTER-IP PORT(S)
nginx-svc ClusterIP 10.110.86.136 80/TCP
10.110.86.136是虚拟 IP,不绑定在任何网卡上- kube-proxy 在每个节点上写 iptables 规则:发往
10.110.86.136:80的流量 → DNAT 到后端 Pod IP - 自带负载均衡(随机或轮询到后端 Pod)
集群内访问方式:
http://nginx-svc # 同 namespace 内
http://nginx-svc.dev # 跨 namespace 简写
http://nginx-svc.dev.svc.cluster.local # 完整 FQDN
NodePort — 外部可访问
kubectl -n dev expose deployment nginx --port=80 --type=NodePort --name=nginx-nodeport
NAME TYPE CLUSTER-IP PORT(S)
nginx-nodeport NodePort 10.111.37.160 80:31281/TCP
在每个节点的 31281 端口开放,外部可通过 http://<任意节点IP>:31281 访问。
端口范围: 30000-32767(默认)。我们的 VPN 用 443 和 40000,不冲突。
LoadBalancer — 云环境的标准做法
在云平台(AWS/GCP/阿里云)上会自动创建一个外部负载均衡器。裸金属环境下会一直 Pending(除非装了 MetalLB)。
Endpoints — Service 背后的真相
$ kubectl -n dev get endpoints nginx-svc
NAME ENDPOINTS
nginx-svc 10.244.119.195:80,10.244.147.68:80,10.244.242.3:80
Service 通过 Label Selector 找到匹配的 Pod,把它们的 IP 注册为 Endpoints。当 Pod 增减时,Endpoints 自动更新,kube-proxy 同步刷新 iptables 规则。
面试关键链路:
用户请求 → ClusterIP (10.110.86.136:80)
→ iptables DNAT → 随机选一个 Endpoint
→ Pod IP (10.244.119.195:80)
→ 容器内 nginx 进程
我们的实际验证
# 从集群外部通过 NodePort 访问(成功)
$ curl http://107.148.176.193:31281
<!DOCTYPE html>
<html>... ← nginx 欢迎页
# Endpoints 正确指向 3 个 Pod
$ kubectl -n dev get endpoints nginx-svc
10.244.119.195:80, 10.244.147.68:80, 10.244.242.3:80
镜像拉取问题与解决(实战经验)
遇到的问题
Worker-4 (wk-1, HK) 无法访问 Docker Hub:
Failed to pull image "docker.io/library/nginx:1.25":
dial tcp 210.56.51.193:443: i/o timeout
根因
Docker Hub 在某些地区网络不稳定。HK 这台机器的出口 IP 到 registry-1.docker.io 超时。
解决方案:containerd 镜像加速器
# 创建目录
mkdir -p /etc/containerd/certs.d/docker.io
# 配置镜像加速
cat > /etc/containerd/certs.d/docker.io/hosts.toml << 'EOF'
server = "https://registry-1.docker.io"
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
[host."https://mirror.gcr.io"]
capabilities = ["pull", "resolve"]
EOF
# 更新 containerd 配置指向 certs.d 目录
# 在 config.toml 中设置:
# config_path = "/etc/containerd/certs.d"
systemctl restart containerd
原理: containerd 先尝试镜像加速器(DaoCloud Mirror、Google Mirror),如果都失败再回退到 Docker Hub 官方。
面试考点: 生产环境中通常部署私有 Harbor 镜像仓库,所有镜像从 Harbor 拉取。后续 Phase 2 我们会搭建 Harbor。
接下来
下一步:ConfigMap/Secret、StatefulSet、DaemonSet、Job/CronJob、RBAC。