19. 本地存储

本地存储

Persistent (持久存储)。本文提出了一种管理持久性、集群范围存储的模型,适用于需要长期保存数据的应用。

核心概念

  • PersistentVolume(PV)——后端存储的“实体”

    PV 是管理员提供的存储资源抽象。可以是 NFS、Ceph、云盘,也可以是节点本地目录(hostPath / Local PV)。PV 描述了容量、访问模式、回收策略等属性。

  • PersistentVolumeClaim(PVC)——应用的“存储申请”

    PVC 是用户(开发/应用)对存储的请求:要多少空间、什么访问模式、需要哪个 StorageClass。PVC 不关心底层实现,绑定到合适的 PV 后,Pod 就把 PVC 当作卷使用。

  • StorageClass——存储“类型/策略”

    管理员用 StorageClass 把存储分门别类(例如:快速 SSD、慢速 HDD、手动 Local 等),并可以配置动态供给(provisioner)或延迟绑定(volumeBindingMode)。用户在 PVC 中指定 storageClassName 来选择类型。

HostPath实践

  • 什么是 hostPath?
    PV 的一种后端实现,直接使用节点的某个目录(例如 /data/k8s/test/hostpath)。通常用于测试或单节点场景,生产环境通常不用(因节点依赖性与可靠性问题)。

  • 限制与注意

    • Pod 必须调度到含有该目录的节点(否则无法访问)。通常需要用 nodeSelector 或 nodeAffinity 固定节点。

    • 节点宕机或磁盘损坏会导致数据不可用或丢失。

    • 适合需要高 IO(例如 SSD 本地盘)的场景,但要做好备份策略。

示例:

PV 定义:

# pv-hostpath.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-hostpath
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  # accessModes(访问模式):如何挂载
  # ReadWriteOnce(RWO):单个节点可读写
  # ReadOnlyMany(ROX):多个节点只读
  # ReadWriteMany(RWX):多个节点可读写
  hostPath:
    path: "/data/k8s/test/hostpath"

对应的 PVC:

# pvc-hostpath.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-hostpath
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

Pod 使用 PVC:

# pv-hostpath-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pv-hostpath-pod
spec:
  nodeSelector:
    # 节点选择器
    # 可以通过  kubectl get nodes --show-labels 查看
    kubernetes.io/hostname: node1
  volumes:
    - name: pv-hostpath
      persistentVolumeClaim:
        claimName: pvc-hostpath
  containers:
    - name: web
      image: nginx
      volumeMounts:
        - name: pv-hostpath
          mountPath: /usr/share/nginx/html
      ports:
        - containerPort: 80

验证:

# 提前去node1节点写入目录和文件
ubuntu@ubuntu:~$ sudo mkdir -p /data/k8s/test/hostpath
ubuntu@ubuntu:~$ echo 'Hello from Kubernetes hostpath storage' | sudo tee /data/k8s/test/hostpath/index.html
Hello from Kubernetes hostpath storage

# master节点执行验证
# 创建PV
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f pv-hostpath.yaml
persistentvolume/pv-hostpath created
ubuntu@ubuntu:~/example/persistent$ kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-hostpath   10Gi       RWO            Retain           Available           manual         <unset>                          5s
ubuntu@ubuntu:~/example/persistent$ 
# 创建PVC
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f pvc-hostpath.yaml 
persistentvolumeclaim/pvc-hostpath created
ubuntu@ubuntu:~/example/persistent$ kubectl get pvc
NAME           STATUS   VOLUME        CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
pvc-hostpath   Bound    pv-hostpath   10Gi       RWO            manual         <unset>                 6s
# 注意状态变成了Bound
ubuntu@ubuntu:~/example/persistent$ kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-hostpath   10Gi       RWO            Retain           Bound    default/
# 创建并运行pod
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f ./pv-hostpath-pod.yaml 
pod/pv-hostpath-pod created
ubuntu@ubuntu:~/example/persistent$ kubectl get pods -o wide
NAME              READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
pv-hostpath-pod   1/1     Running   0          38s   10.244.2.84   node1   <none>           <none>
# 期望输出: Hello from Kubernetes hostpath storage
ubuntu@ubuntu:~/example/persistent$ curl http://10.244.2.84
Hello from Kubernetes hostpath storage
  • 状态(PV 的 lifecycle)

    • Available(可用): 表示可用状态,还未被任何 PVC 绑定
    • Bound(已绑定):表示 PV 已经被 PVC 绑定
    • Released(已释放):PVC 被删除,但是资源还未被集群重新声明
    • Failed(失败):表示该 PV 的自动回收失败
  • AccessModes(访问模式):用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

    • ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
    • ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
    • ReadWriteMany(RWX):读写权限,可以被多个节点挂载

Local PV

  • Local PV 是什么?

    Local PV 本质上也是本地磁盘(或挂载点),但 Kubernetes 用专门字段 local + nodeAffinity 来声明:这让调度器知道哪些 PV 在哪些节点,从而做出正确调度判断。

  • 为什么需要延迟绑定(WaitForFirstConsumer)?

    如果 PV 在节点 A,但 Pod 被调度到节点 B,会导致调度失败。WaitForFirstConsumer 延迟绑定到 Pod 调度时,由调度器综合考虑节点亲和性和 PV 所在节点来选择合适 PV,从而避免错误绑定。

Local PV 示例:

# pv-local.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-local       # PV 的名字,PVC 会通过名字或 storageClass 绑定到它
spec:
  capacity:
    storage: 5Gi       # PV 的容量,必须 >= PVC 请求的容量
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce  
  persistentVolumeReclaimPolicy: Delete
  # Delete: PVC 删除后,PV 和磁盘内容都会删除
  # Retain: PVC 删除后,PV 保留但需要手动清理
  # Recycle(废弃)
  storageClassName: local-storage   # 必须与 PVC 的 storageClass 一致
  local:
    path: /data/k8s/localpv         # 本地磁盘/目录的真实路径(在某个 Node 上)
  # nodeAffinity:必须指定这个盘在哪个节点上,否则调度器不知道 Pod 应该跑在哪
  nodeAffinity:
    required:                       # 这是必须满足的调度规则(硬规则)
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - node1             # 节点名

对应的 StorageClass(用于延迟绑定):

# local-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage          # PVC 会通过这个名字找到对应的 PV
provisioner: kubernetes.io/no-provisioner
# Local PV 是“静态”供应(Static Provisioning),不会自动创建 PV,
# 所以必须使用 no-provisioner,告诉 K8s:PV 需要人工手动创建。
volumeBindingMode: WaitForFirstConsumer
# 非常关键!
# “等待第一个使用 PVC 的 Pod 出现后,再选择具体的 PV 和节点”
# 为了确保调度器能把 Pod 调度到 PV 对应的正确节点。
# 否则 PVC 可能绑定到错误的节点,会导致本地磁盘无法访问。

PVC:

# pvc-local.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-local               # Pod 通过此名字引用 PVC -> PV -> 真实数据目录
spec:
  storageClassName: local-storage
  # 与 PV 的 storageClassName 必须一致,否则不会绑定
  accessModes:
    - ReadWriteOnce            # 本地卷只支持单节点读写(RWO)
  resources:
    requests:
      storage: 5Gi             # 请求大小必须 <= PV 的 size,否则绑定失败

对应的POD:

# local-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: local-pod       # Pod 的名字,可以通过 kubectl get pod 查看
spec:
  volumes:
    - name: example-pv-local
      persistentVolumeClaim:
        claimName: pvc-local
        # 绑定前面创建的 PVC(pvc-local)
        # 调度器会根据 PVC 对应的 PV 的 nodeAffinity,将 Pod 调度到正确的节点
        # 这里的 volume 名称(example-pv-local)可以自定义
  containers:
    - name: nginx
      image: nginx        # 使用 nginx 镜像
      volumeMounts:
        - name: example-pv-local
          mountPath: /usr/share/nginx/html
          # 将 PV 挂载到容器内的路径
          # nginx 默认网页目录是 /usr/share/nginx/html
      ports:
        - containerPort: 80
          # 容器对外暴露 80 端口
          # 方便你在 Node 上用 kubectl port-forward 或者 Service 暴露访问

验证:

# 创建 StorageClass, Local PV, PVC
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f local-storageclass.yaml
storageclass.storage.k8s.io/local-storage created
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f pv-local.yaml
persistentvolume/pv-local created
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f pvc-local.yaml
persistentvolumeclaim/pvc-local created
ubuntu@ubuntu:~/example/persistent$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS    VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-local   5Gi        RWO            Delete           Available           local-storage   <unset>                          12s
# 期望:如果 StorageClass volumeBindingMode=WaitForFirstConsumer,则 PVC 处于 Pending(等待 Pod)
ubuntu@ubuntu:~/example/persistent$ kubectl get pvc pvc-local
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    VOLUMEATTRIBUTESCLASS   AGE
pvc-local   Pending                                      local-storage   <unset>                 14s
# 创建POD
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f local-pod.yaml
pod/local-pod created
ubuntu@ubuntu:~/example/persistent$ kubectl get pod local-pod -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
local-pod   1/1     Running   0          21s   10.244.2.85   node1   <none>           <none>
# 测试验证
ubuntu@ubuntu:~/example/persistent$ curl http://10.244.2.85
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.29.3</center>
</body>
</html>
# 由于没写入任何文件,所以403,去node1节点写入
ubuntu@ubuntu:/data/k8s/localpv$ echo 'hello? form pvc-local' | sudo tee /data/k8s/localpv/index.html
[sudo] password for ubuntu: 
hello? form pvc-local
ubuntu@ubuntu:/data/k8s/localpv$ 

# 回到master 重新测试
ubuntu@ubuntu:~/example/persistent$ curl http://10.244.2.85
hello? form pvc-local
# 验证回收策略
# 删除POD
ubuntu@ubuntu:~$ kubectl delete pod local-pod
pod "local-pod" deleted
# node1 发现还在 
# 删除PV(pv-local 的 reclaimPolicy 为 Delete,会发现PV也跟着被删了【如果插件支持的话】)
ubuntu@ubuntu:~$ kubectl delete pvc pvc-local
persistentvolumeclaim "pvc-local" deleted
# 我这边没装插件,所以failed了,但是删除动作是发生了的,如有需要可以安装 Local Volume CSI 插件
ubuntu@ubuntu:~$ kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS    VOLUMEATTRIBUTESCLASS   REASON   AGE
pv-local   5Gi        RWO            Delete           Failed   default/pvc-local   local-storage   <unset>                          9m16s
ubuntu@ubuntu:~$ kubectl describe pv pv-local
Name:              pv-local
Labels:            <none>
Annotations:       pv.kubernetes.io/bound-by-controller: yes
Finalizers:        [kubernetes.io/pv-protection]
StorageClass:      local-storage
Status:            Failed
Claim:             default/pvc-local
Reclaim Policy:    Delete
Access Modes:      RWO
VolumeMode:        Filesystem
Capacity:          5Gi
Node Affinity:     
  Required Terms:  
    Term 0:        kubernetes.io/hostname in [node1]
Message:           error getting deleter volume plugin for volume "pv-local": no volume plugin matched
Source:
    Type:  LocalVolume (a persistent volume backed by local storage on a node)
    Path:  /data/k8s/localpv
Events:
  Type     Reason              Age   From                         Message
  ----     ------              ----  ----                         -------
  Warning  VolumeFailedDelete  2m9s  persistentvolume-controller  error getting deleter volume plugin for volume "pv-local": no volume plugin matched

我们上面手动创建 PV 的方式,即静态的 PV 管理方式,在删除 PV 时需要按如下流程执行操作:

  • 删除使用这个 PV 的 Pod

  • 从宿主机移除本地磁盘

  • 删除 PVC

  • 删除 PV

如果不按照这个流程的话,这个 PV 的删除就会失败。

NFS(共享存储)

是平时我们的应用更多的是无状态服务,可能会同时发布在不同的节点上,这个时候本地存储就不适用了,往往就需要使用到共享存储了,比如最简单常用的网络共享存储 NFS 。

安装NFS

安装 NFS 服务端(Server)

  1. 安装 NFS 服务
    在 NFS 服务端节点执行:
sudo apt update
sudo apt install -y nfs-kernel-server
  1. 创建共享目录
sudo mkdir -p /var/lib/k8s/data
sudo chmod 755 /var/lib/k8s/data
  1. 配置共享目录

编辑 /etc/exports 文件,添加以下内容:

/var/lib/k8s/data *(rw,sync,no_root_squash)

参数说明:

  • /var/lib/k8s/data:共享的目录

  • *:允许任何主机访问,也可以指定 IP 或网段

  • rw:读写权限

  • sync:写入数据立即同步

  • no_root_squash:客户端 root 用户在挂载时也拥有 root 权限(危险操作,仅测试环境使用)

  1. 重新加载 NFS 配置并启动服务
sudo exportfs -ra
sudo systemctl restart nfs-kernel-server
sudo systemctl enable nfs-kernel-server
  1. 验证 NFS 服务是否启动
ubuntu@ubuntu:~$ rpcinfo -p | grep nfs
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    3   tcp   2049  nfs_acl
ubuntu@ubuntu:~$ cat /var/lib/nfs/etab
/var/lib/k8s/data	*(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,no_root_squash,no_all_squash)

安装 NFS 客户端(Client)

  1. 安装客户端工具
# Ubuntu/Debian 系统
sudo apt install -y nfs-common
# CentOS/RHEL 系统
# sudo yum install -y nfs-utils rpcbind
  1. 查看可用共享目录
#showmount -e <NFS_SERVER_IP>
ubuntu@ubuntu:/data/k8s/localpv$ showmount -e 192.168.236.101
Export list for 192.168.236.101:
/var/lib/k8s/data *
  1. 挂载 NFS 共享目录
sudo mkdir -p /mnt/data
sudo mount -t nfs 192.168.236.101:/var/lib/k8s/data /mnt/data
# 在客户端创建测试文件:
touch /mnt/data/test.txt
# 在服务端查看是否出现文件:

Kubernetes 中使用 NFS 存储

在 Kubernetes 中,存储资源通过 PV(PersistentVolume)、PVC(PersistentVolumeClaim) 和 StorageClass 来管理。NFS 可以作为一种远程共享存储被 Kubernetes 使用。

手动创建 PV/PVC 并使用 NFS

  1. 创建 NFS 类型 PV
# nfs-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /var/lib/k8s/data/
    server: 192.168.236.101

accessModes

  • ReadWriteOnce(RWO):单节点读写

  • ReadOnlyMany(ROX):多节点只读

  • ReadWriteMany(RWX):多节点读写(NFS 支持)

persistentVolumeReclaimPolicy

  • Retain:删除 PVC 时 PV 数据保留

  • Recycle:删除 PVC 后清理数据

  • Delete:删除 PVC 后删除 PV

  1. 创建 PVC
# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

PV 和 PVC 会根据存储容量、访问模式、StorageClass 自动匹配绑定。

  1. 创建 Pod 使用 PVC
# nfs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-volumes
spec:
  volumes:
    - name: nfs
      persistentVolumeClaim:
        claimName: nfs-pvc
  containers:
    - name: web
      image: nginx
      ports:
        - containerPort: 80
      volumeMounts:
        - name: nfs
          subPath: test-volumes
          mountPath: /usr/share/nginx/html
  1. 验证
# 创建相关资源
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f nfs-volume.yaml 
persistentvolume/nfs-pv created
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f nfs-pvc.yaml 
persistentvolumeclaim/nfs-pvc created
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f nfs-pod.yaml 
pod/test-volumes created
# 查看状态
ubuntu@ubuntu:~/example/persistent$ kubectl get pods -o wide
NAME           READY   STATUS    RESTARTS   AGE    IP           NODE    NOMINATED NODE   READINESS GATES
test-volumes   1/1     Running   0          2m9s   10.244.1.3   node2   <none>           <none>
# 请求
ubuntu@ubuntu:~/example/persistent$ curl http://10.244.1.3
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.29.3</center>
</body>
</html>
# 服务端写入文件
ubuntu@ubuntu:~$ echo 'nfs pv content' | sudo tee /var/lib/k8s/data/test-volumes/index.html
[sudo] password for ubuntu: 
nfs pv content
# 再次测试
ubuntu@ubuntu:~$ curl http://10.244.1.3
nfs pv content
# 删除pod 重新访问
ubuntu@ubuntu:~/example/persistent$ kubectl delete -f ./nfs-pod.yaml 
pod "test-volumes" deleted
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f ./nfs-pod.yaml 
pod/test-volumes created
ubuntu@ubuntu:~/example/persistent$ kubectl get pods -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
test-volumes   1/1     Running   0          35s   10.244.1.4   node2   <none>           <none>
# 仍然存在
ubuntu@ubuntu:~/example/persistent$ curl http://10.244.1.4
nfs pv content

自动创建 PV(动态 Provision)

参考git链接 https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

下载项目并修改 deploy/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 192.168.236.101 # # nfs server 地址
            - name: NFS_PATH
              value: /var/lib/k8s/data # NFS_SERVER_SHARE
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.236.101 # nfs server 地址
            path: /var/lib/k8s/data

安装

ubuntu@ubuntu:~/nfs-subdir-external-provisioner-master$ kubectl apply -k ~/nfs-subdir-external-provisioner-master/deploy/
storageclass.storage.k8s.io/nfs-client created
serviceaccount/nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
deployment.apps/nfs-client-provisioner created
# 安装后会创建一个名为 nfs-client 的 StorageClass
ubuntu@ubuntu:~/example/persistent$ kubectl get sc
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  18m
# 自动创建的 PV 会在 NFS 上生成目录:
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f ./nfs-dynamic-pvc.yaml 
persistentvolumeclaim/nfs-dynamic-pvc created
ubuntu@ubuntu:~/example/persistent$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-689c1c6e-42db-48ac-ba51-e4b92251166d   1Gi        RWO            Delete           Bound    default/nfs-dynamic-pvc   nfs-client     <unset>                          115s
# 自动创建的 PV 会在 NFS 上生成目录:
# /var/lib/k8s/data/<namespace>-<pvcName>-<pvName>

验证自动创建与删除:

# nfs-dynamic-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-dynamic-pvc
spec:
  storageClassName: nfs-client
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
kubectl get pv
kubectl describe pvc nfs-dynamic-pvc
# 自动创建的 PV 会在 NFS 上生成目录:
# /var/lib/k8s/data/<namespace>-<pvcName>-<pvName>

Pod 使用

# nfs-test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nfs-test-pod
spec:
  containers:
  - name: web
    image: nginx
    ports:
      - containerPort: 80
    volumeMounts:
      - name: nfs-storage
        mountPath: /usr/share/nginx/html
  volumes:
    - name: nfs-storage
      persistentVolumeClaim:
        claimName: nfs-dynamic-pvc

验证:

# 创建
ubuntu@ubuntu:~/example/persistent$ kubectl apply -f ./nfs-test-pod.yaml 
pod/nfs-test-pod created
ubuntu@ubuntu:~/example/persistent$ kubectl get pods -o wide
NAME                                     READY   STATUS    RESTARTS   AGE     IP           NODE    NOMINATED NODE   READINESS GATES
nfs-client-provisioner-87cd7bd6b-ckmgj   1/1     Running   0          6m38s   10.244.1.6   node2   <none>           <none>
nfs-test-pod                             1/1     Running   0          14s     10.244.1.7   node2   <none>           <none>
# 宿主机上多了一个目录
# /var/lib/k8s/data/default-nfs-dynamic-pvc-pvc-689c1c6e-42db-48ac-ba51-e4b92251166d
# 写入数据
ubuntu@ubuntu:~/example/persistent$ echo 'nfs provisioner content' | sudo tee /var/lib/k8s/data/default-nfs-dynamic-pvc-pvc-689c1c6e-42db-48ac-ba51-e4b92251166d/index.html
nfs provisioner content
# 测试访问
ubuntu@ubuntu:~/example/persistent$ curl http://10.244.1.7
nfs provisioner content
posted @ 2025-11-24 19:47  beamsoflight  阅读(14)  评论(0)    收藏  举报