K8s Lab 把当前仓库文档整理成一个可阅读的网页站点

Repository Reading Site

工作负载与服务发现 — K8s 的核心战斗力

想象一个公司有开发、测试、生产三个环境。没有 Namespace 的话,所有资源混在一起: Namespace 提供: 1. **名称隔离** — 不同 NS 可以有同名资源 2. **权限隔离** — RBAC 可以限制用户只能操作某个 NS 3. **资源配额** — 限制每个 NS 最多用多少 CPU/内存 4. **网络隔离** — NetworkP

Markdownphase-1/01-workloads-and-services.md2026年4月9日 11:26

工作负载与服务发现 — K8s 的核心战斗力

Namespace — 虚拟集群隔离

kubectl create namespace dev
kubectl create namespace staging
kubectl create namespace prod

为什么需要 Namespace?

想象一个公司有开发、测试、生产三个环境。没有 Namespace 的话,所有资源混在一起:

  • 开发人员可能误删生产的 Pod
  • 资源名称冲突(dev 和 prod 都有叫 nginx 的 Deployment)
  • 无法按环境做资源配额

Namespace 提供:

  1. 名称隔离 — 不同 NS 可以有同名资源
  2. 权限隔离 — RBAC 可以限制用户只能操作某个 NS
  3. 资源配额 — 限制每个 NS 最多用多少 CPU/内存
  4. 网络隔离 — 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 始终可用)

面试深度题: "如何实现零停机更新?"

  1. maxUnavailable=0 — 不允许任何 Pod 下线
  2. 配置 readinessProbe — 确保新 Pod 真正就绪才接收流量
  3. 配置 preStop hook — 旧 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。

02-configmap-secret-statefulset.md