HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 概览

    • K8s 实战学习实验室
    • 服务访问清单
    • K8s-Lab 学习总纲、仓库评估与专家路线图
  • 课程正文

    • 环境验证与第一课:认识你的真实集群
    • 第二课:kubectl apply 之后,到底发生了什么
    • 第三课:调度器如何选节点,为什么 Pod 会 Pending
    • 第四课:Kubernetes 网络、协议分层、VXLAN/IPIP/WireGuard 原理与排障
    • 第五课:NetworkPolicy、零信任网络与流量边界
    • 第六课:身份、认证、授权、准入与 ServiceAccount / RBAC 原理
    • 第七课:ConfigMap 与 Secret 注入模型、更新机制与安全边界
    • 第八课:存储持久化、PV / PVC / StorageClass 与 NFS 原理
    • 第九课:StatefulSet、Headless Service、稳定身份与存储原理
    • 第十课:探针、滚动更新、优雅终止与 PDB 原理
    • 第十一课:requests / limits、QoS、OOM 与驱逐原理
    • 第十二课:HPA、自动扩缩容、指标链路与副本伸缩原理
    • 第十三课:Service、EndpointSlice、kube-proxy、CoreDNS 与服务发现原理
    • 第十四课:Ingress-nginx、反向代理、Host / Path、NodePort 与北南向流量原理
    • 第十五课:HTTPS、TLS、SNI、证书信任与 Ingress 终止原理
    • 第十六课:cert-manager、Ingress 自动签发、证书生命周期与 ACME 工作流原理
    • 第十七课:ACME、Let's Encrypt、HTTP-01 / DNS-01、Orders / Challenges 与生产限制原理
    • 第十八课:大模型全生态,从数据到训练到部署到治理原理
    • 第十九课:大模型数据集、清洗、标注、切分、版本管理与质量治理原理
    • 第二十课:大模型训练、SFT、LoRA、Checkpoint、Adapter 与模型产物原理
    • 第二十一课:大模型推理、量化、KV Cache、vLLM、吞吐/延迟与部署发布链路原理
  • 实验操作记录

    • 本次仓库审查操作记录与命令原理
    • 本轮操作记录:环境验证、集群基线盘点与故障样本采集
    • 本轮操作记录:kubectl apply 主链路实验
    • 本轮操作记录:调度实验与 Pending 排查
    • 本轮操作记录:Kubernetes 网络原理、协议对比与调试实验
    • 本轮操作记录:NetworkPolicy 与零信任网络实验
    • 本轮操作记录:身份、认证、授权、准入实验
    • 本轮操作记录:ConfigMap 与 Secret 注入、更新与安全边界实验
    • 本轮操作记录:存储持久化、PV / PVC / StorageClass 与 NFS 实验
    • 本轮操作记录:StatefulSet、Headless Service 与稳定身份实验
    • 本轮操作记录:探针、滚动更新、优雅终止与 PDB 实验
    • 本轮操作记录:资源模型、QoS、OOM 与 CPU 节流实验
    • 本轮操作记录:HPA 自动扩缩容实验
    • 本轮操作记录:Service、EndpointSlice、CoreDNS 与服务发现排障实验
    • 本轮操作记录:Ingress-nginx、NodePort 与北南向流量实验
    • 本轮操作记录:HTTPS、TLS、自签证书与 Ingress 实验
    • 本轮操作记录:cert-manager 安装、CA 签发与 Ingress 自动证书实验
    • 本轮操作记录:ACME staging、HTTP-01 失败样本与排障实验
    • 本轮操作记录:大模型全生态与基础原理科普文撰写
    • 本轮操作记录:大模型数据集样本与治理文档编写
    • 本轮操作记录:大模型训练与模型产物概念文撰写
    • 本轮操作记录:大模型推理与服务发布概念文撰写

工作负载与服务发现 — 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-systemK8s 系统组件(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