CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Kubernetes 入门/课时/存储卷
RawBlame
课时目录12 节

Kubernetes 入门

  1. 01Kubernetes 是什么
  2. 02核心概念与架构
  3. 03本地集群与 kubectl
  4. 04Pod
  5. 05Deployment 与滚动更新
  6. 06Service 与网络
  7. 07ConfigMap 与 Secret
  8. 08存储卷
  9. 09Ingress 入口
  10. 10资源配额与 HPA
  11. 11RBAC 与安全基础
  12. 12综合练习:部署 backend

存储卷

PV、PVC、StatefulSet 直觉。

30 分钟

存储卷

这一课你将能做到

  1. 说清容器可写层的临时性,并用 emptyDir 实验证明「Pod 一删数据就没」
  2. 解释 PV、PVC、StorageClass 三者的分工,写出并绑定一个 PVC
  3. 完成本站核心实验:MySQL 挂 PVC,删 Pod 重建后数据仍在;并能判断本站数据库何时该放集群外

为什么要学

Pod 重建后,容器可写层默认清空。本站的课程数据、用户内容都在 MySQL 里——这和 Docker 课里「删容器丢库」是同一个风险,只是集群里多了一层「Pod 还会被调度到别的节点」。

K8s 用声明式解决持久化:PersistentVolumeClaim(PVC) 是应用「我要一块 5Gi 盘」的申领,PersistentVolume(PV) 是真实的存储块,StorageClass 定义「用哪种存储自动供给」。理解这套模型,你才能回答面试题「PV/PVC/SC 什么关系」,也才能对「本站 MySQL 到底放哪」做出专业判断。

先建立图像

Pod 声明 volumeMount(挂到容器某路径)
  → volumes 引用 PVC
      → PVC 绑定 PV(静态创建或 StorageClass 动态供给)
          → 云盘 / 本地路径 / NFS / Ceph …

选型直觉:
  无状态 API(backend/platform):Deployment,不需要 PVC
  有状态数据(MySQL):StatefulSet + 每副本独立 PVC,或干脆用托管库
  临时缓存/共享临时文件:emptyDir(Pod 删即失)
对象角色人话
StorageClass存储供给的「模板」「要哪种货、怎么造」
PVC应用的存储申领「提货单:我要 5Gi、可读写」
PV真实存储块「仓库货位」
访问模式缩写含义
ReadWriteOnceRWO单节点读写(数据库最常用)
ReadOnlyManyROX多节点只读
ReadWriteManyRWX多节点读写(NFS 类,共享文件)

跟着做

步骤 1:先证明「默认不持久」

pod-emptydir.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: cache-demo
spec:
  containers:
    - name: app
      image: busybox:1.36
      command: ["/bin/sh", "-c", "echo v1 > /data/note.txt; sleep 3600"]
      volumeMounts:
        - name: scratch
          mountPath: /data
  volumes:
    - name: scratch
      emptyDir: {}          # 生命周期 = Pod 的临时盘
kubectl apply -f pod-emptydir.yaml
kubectl exec cache-demo -- cat /data/note.txt     # 输出 v1
kubectl delete pod cache-demo
kubectl apply -f pod-emptydir.yaml
kubectl exec cache-demo -- cat /data/note.txt     # 又是新的一次写入

emptyDir 适合:临时缓存、同 Pod 容器间共享文件。绝不能放数据库数据。

步骤 2:看集群的 StorageClass 并申请 PVC

kubectl get storageclass

minikube 自带名为 standard 的默认供给器(云集群是对应云盘的 SC)。申请一块盘:

pvc-mysql.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  # storageClassName: standard   # 不写则用默认 SC;云上需显式指定
kubectl apply -f pvc-mysql.yaml
kubectl get pvc mysql-pvc

STATUS 应从 Pending 变为 Bound。若一直 Pending:没有可用 SC 或容量/模式无人能满足(见卡点急救)。

步骤 3:MySQL 挂上 PVC

deploy-mysql.yaml(沿用第 7 课的 db-secret):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1                   # 单实例演示;多副本 MySQL 不能这样硬凑
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-secret
                  key: DB_PASSWORD
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql     # 数据目录
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: mysql-pvc
kubectl apply -f deploy-mysql.yaml
kubectl get pods -l app=mysql -w      # 等到 Ready(首次初始化较慢)

步骤 4:核心实验——删 Pod,数据还在

写入测试数据:

kubectl exec -it deploy/mysql -- mysql -uroot -p"change-me-demo" \
  -e "CREATE DATABASE IF NOT EXISTS k8stest; USE k8stest; CREATE TABLE t(id INT); INSERT INTO t VALUES (42);"

模拟 Pod 故障(数据库容器崩溃、节点驱逐都会导致重建):

kubectl delete pod -l app=mysql
kubectl get pods -l app=mysql -w      # 等新 Pod Ready
kubectl exec deploy/mysql -- mysql -uroot -p"change-me-demo" \
  -e "SELECT * FROM k8stest.t;"

应输出 42——持久化靠 PVC 而不是容器层,这就是「删 Pod 数据还在」的验收标准。

步骤 5:看 PV 与回收策略

kubectl get pv
kubectl get pv <你的pv名> -o yaml | findstr /i "persistentVolumeReclaimPolicy"
  • Delete(动态供给默认):PVC 删除时 PV 与云盘一起删——删 PVC 前想三遍
  • Retain:PV 保留,需人工处理——重要数据建议此模式
kubectl delete pvc mysql-pvc   # 演示完可删(Retain 模式下 PV 会留为 Released)

步骤 6:StatefulSet 直觉与本站选型

记下结论(细节进阶再展开):StatefulSet 为每个副本提供稳定主机名(mysql-0/1/2)与独立 PVC,适合主从/集群拓扑;Deployment 的多副本共享模板,不适合有状态集合。

本站过渡期推荐顺序:

  1. backend / platform → Deployment(无 PVC)
  2. MySQL、Redis → 集群外 Compose 或云托管,DB_HOST/REDIS_HOST 指向可达地址
  3. API 的发布与回滚熟练后,再评估是否把库迁进集群(迁入前先落备份演练)

讲清楚要点

  1. 容器层易失,有状态目录必须外置:PVC、托管库二选一,没有第三条路。
  2. PVC 与 Pod 生命周期解耦:可以删 Pod 保数据,也可以把盘重新挂到新 Pod;这正是「数据库容器化」的立足点。
  3. RWO ≠ 单副本,而是单节点:同一节点上多个 Pod 可以共享一块 RWO 盘;跨节点多副本挂同一 RWO 盘会调度失败(Multi-Attach error)。
  4. 多副本同时写一块盘 ≠ 高可用:RWX 共享写或单盘多挂都不解决复制问题;MySQL 高可用要靠主从/MGR 等复制拓扑。
  5. StorageClass 因集群而异:同一份 PVC YAML 在 minikube 能绑、到云上要核对 SC 名与参数(性能等级、加密、备份)。
  6. 上集群前先问备份:本站核心资产在库里,「有没有验证过的恢复流程」比「有没有用上 StatefulSet」重要得多。

你可能会懵的地方

  • emptyDir、hostPath、PVC 怎么选? emptyDir:Pod 级临时盘(缓存/中转);hostPath:节点本地路径(演示方便,生产慎用——调度绑死节点、节点故障数据即失);PVC:跨 Pod 存活的正式持久化。生产数据一律 PVC 或托管。

  • Deployment 能挂 PVC 吗? 能。单副本(如本课 MySQL 演示)没问题;多副本挂同一 RWO PVC 会踩调度坑。真正的多副本有状态应用用 StatefulSet + volumeClaimTemplates。

  • PVC 为什么要和 Pod 分开? 解耦后存储独立于计算:应用发布、扩缩、迁移都不动数据;这也是「应用无状态化 + 状态外置」架构的 K8s 表达。

  • 删了 Deployment,数据还在吗? 在。Deployment/Pod 删除不影响 PVC/PV;但要小心 PVC 自身的删除策略与 PV 回收策略(步骤 5)。

  • 和 Docker named volume 比多了什么? 同属「数据外置」,但 K8s 增加了申领模型(PVC)、供给模板(SC)、跨节点调度约束与回收策略——存储第一次成为「可编排对象」。

错法对照

错法问题正解
数据库只写容器可写层Pod 重建即丢库PVC 或托管库
多副本 MySQL 挂同一块 RWO 盘调度失败或数据腐坏一实例一盘 + 官方复制拓扑
只做备份从不演练恢复出事才知道备份不可用定期恢复演练(核心!)
把所有服务都改 StatefulSet过度设计无状态服务一律 Deployment
生产依赖 hostPath节点故障即丢数据云盘 CSI / 网络存储

卡点急救

  1. PVC 一直 Pending:kubectl describe pvc 看事件——没有默认 StorageClass(补 storageClassName)、请求容量/模式无 PV 能满足、云集群配额不足。
  2. Pod 起不来报 Multi-Attach error:RWO 盘被另一节点占用。kubectl get pods -o wide 看新旧 Pod 节点分布;删旧 Pod 等其完全退出,或改用支持跨节点的存储。
  3. 「数据丢了」:先回忆用的是哪类卷——emptyDir/hostPath 随 Pod/节点消亡属预期;PVC 场景查 PVC 是否被误删、PV 回收策略是否为 Delete。教训:重要 PV 一律 Retain。

面试常问

  • PV、PVC、StorageClass 三者的关系? PVC 是用户侧的存储申领(容量+访问模式),PV 是集群侧的真实存储块,两者通过绑定关联;StorageClass 定义动态供给模板,PVC 指定 SC 后由供应器自动创建 PV 并绑定。类比:PVC 提货单、PV 仓库货位、SC 供货流程。运维管 PV/SC,开发只管 PVC——职责分离。

  • accessModes 的 RWO/ROX/RWX 怎么理解? 描述的是「节点级挂载方式」而非 Pod 数:RWO 单节点读写(数据库典型);ROX 多节点只读(配置、模型文件分发);RWX 多节点读写(NFS 共享文件)。注意 RWO 限制的是节点不是副本数,同一节点的多 Pod 可共享一块 RWO 盘;而多副本同时写需要的是复制机制,不是 RWX。

  • 为什么生产数据库经常不放 K8s 集群里? 三个理由:① 存储与故障域——数据库要稳定低延迟 IO 与独立故障隔离;② 运维复杂度——主从切换、备份恢复、版本升级在集群内更复杂;③ 云托管(RDS 等)自带高可用、备份、监控。合理姿势:无状态 API 上集群,数据层托管或集群外,二者用 Service DNS/ExternalName 打通——这也是中小团队的性价比最优解。

自测三问

  1. PVC 一直 Pending,你按什么顺序排查?
  2. 为什么「三个副本的 Deployment + 一块 MySQL 数据盘」是错误模型?
  3. 本站若 API 上 K8s、MySQL 仍在 Compose 卷里,这算不算合理过渡?要补什么?

小结一句话

PVC 把持久盘申领进集群,PV/SC 负责供给与回收;无状态服务走 Deployment、有状态数据走 PVC/StatefulSet/托管——下一课用 Ingress 把 HTTP 入口收拢,对标现网 Nginx 反代。

延伸

  • Persistent Volumes
  • StatefulSets
  • 下一课预告:Ingress 入口——用规则对象复刻「Nginx 反代 platform + backend」,理解 Ingress Controller 的必要性。
加载本节练习…
← 上一课ConfigMap 与 Secret下一课 →Ingress 入口