如何在docker和k8s中使用nfs文件系统

在多个 Docker 容器使用同一个 NFS 后端时,强烈建议给每个 Docker(或每个业务/应用)分配单独的 NFS 挂载目录(子目录),而不是让所有容器共用一个根目录。

是的,您的理解非常准确。在标准的 NFS 挂载流程中,确实需要人工(或通过自动化脚本)先在 NFS 服务端创建好子目录,然后再将其挂载到 Docker 宿主机上

具体分为以下两个核心步骤:

1. 在 NFS 服务端创建子目录并授权

NFS 协议本身不会自动为客户端动态创建目录。您需要提前在 NFS 服务端的根目录下规划并创建好各个子目录,并设置好正确的权限(如 chownchmod),以确保容器内的用户有权限读写。

2. 在 Docker 宿主机上挂载

在每台运行 Docker 的宿主机上,您需要将 NFS 服务端的对应子目录挂载到本地的一个路径(例如 /mnt/nfs/app1_data)。


💡 进阶:如何让 Docker 自动完成挂载?(推荐)

虽然"先挂载到宿主机,再绑定给容器"是最稳妥的做法,但如果您不想手动执行 mount 命令,可以利用 Docker 的 local driver 让 Docker 自动接管 NFS 的挂载工作。

方式一:通过命令行直接创建 NFS 卷

您只需告诉 Docker NFS 服务端的 IP 和子目录路径,Docker 会在容器启动时自动去挂载它:

bash 复制代码
docker volume create --driver local \
  --opt type=nfs \
  --opt o=addr=192.168.1.100,rw,nfsvers=4.1 \
  --opt device=:/nfs_root/app1_data \
  app1-vol

方式二:在 Docker Compose 中声明式挂载

如果您使用 Docker Compose,可以直接在 docker-compose.yml 中定义,Docker 会自动处理挂载逻辑:

yaml 复制代码
version: '3.8'
services:
  app1:
    image: nginx
    volumes:
      - app1-vol:/usr/share/nginx/html
volumes:
  app1-vol:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.100,rw,vers=4.1
      device: ":/nfs_root/app1_data"

⚠️ 关键注意事项:

  1. 前提条件 :即使使用上述自动化方式,NFS 服务端的子目录也必须提前创建好,否则挂载会失败。
  2. 权限问题 :NFS 默认会将客户端的 root 权限降级为 nobody(即 root_squash)。如果您的容器需要以 root 身份写入数据,必须在 NFS 服务端的 /etc/exports 配置中加上 no_root_squash 参数,或者配置 anonuid/anongid 对齐容器内的用户 UID。
  3. 适用场景 :NFS 非常适合存放图片、配置文件、日志等静态数据,但强烈不建议将数据库(如 MySQL)的数据目录放在 NFS 上,因为网络延迟和文件锁机制极易导致数据库损坏或启动卡死。

在 Kubernetes (K8s) 中为容器挂载 NFS 目录,主要有三种常见方式。根据您的需求(是否需要为每个容器分配独立子目录、是否需要自动创建),您可以选择最适合的方案:

方案一:在 Pod 中直接声明式挂载(最简单,适合测试)

如果您只需要快速将某个 NFS 目录挂载到 Pod 中,可以直接在 YAML 文件的 volumes 中指定 NFS 服务器和路径。

示例 YAML:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: nfs-test
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: nfs-storage
          mountPath: /data  # 容器内的挂载路径
  volumes:
    - name: nfs-storage
      nfs:
        server: 192.168.1.100      # NFS 服务器 IP
        path: /nfs_root/app1_data  # NFS 服务端的子目录路径

注:这种方式需要您提前在 NFS 服务端创建好 /nfs_root/app1_data 目录。

方案二:使用 PV + PVC 静态绑定(生产环境推荐)

将存储资源(PV)与业务请求(PVC)解耦,是 K8s 的最佳实践。

1. 创建持久卷 (PV)

yaml 复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany  # 允许多个节点同时读写
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    server: 192.168.1.100
    path: /nfs_root/app1_data

2. 创建持久卷声明 (PVC)

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: nfs
  resources:
    requests:
      storage: 10Gi

3. 在 Pod 中引用 PVC

yaml 复制代码
volumes:
  - name: nfs-storage
    persistentVolumeClaim:
      claimName: nfs-pvc

方案三:使用动态供应(Dynamic Provisioning,终极推荐)

如果您希望 K8s 能够自动在 NFS 服务端创建子目录 ,而不需要每次手动去 NFS 服务器上 mkdir,您需要部署 NFS Subdir External Provisioner 组件。

  • 工作原理 :您只需在 NFS 服务端配置一个统一的根目录(如 /nfs_root)。当您在 K8s 中提交 PVC 申请时,该 Provisioner 会自动在 /nfs_root 下生成一个独立的子目录(如 /nfs_root/default-nfs-pvc-xxx),并自动绑定给 Pod。

  • 部署方式 :官方推荐使用 Helm 进行一键安装:

    bash 复制代码
    helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
    helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
      --set nfs.server=192.168.1.100 \
      --set nfs.path=/nfs_root \
      --set storageClass.name=nfs-client
  • 使用方式 :安装后,您只需在 PVC 中指定 storageClassName: nfs-client,无需再手动创建 PV,K8s 会自动完成子目录的创建和挂载。

⚠️ K8s 挂载 NFS 的前置要求

无论使用哪种方案,必须在 K8s 集群的所有 Node(节点)上安装 NFS 客户端工具 ,否则 Pod 会因无法识别 NFS 协议而卡在 ContainerCreating 状态:

  • CentOS/RHEL 系统yum install nfs-utils -y
  • Ubuntu/Debian 系统apt install nfs-common -y

总结建议

  • 如果是临时测试 ,使用方案一
  • 如果是固定业务 ,使用方案二
  • 如果是多租户/微服务架构 ,强烈建议使用方案三(动态供应),它能完美契合您之前"为每个容器分配独立子目录"的需求,且极大降低了运维成本。
相关推荐
Plastic garden1 小时前
k8s(3)rocky9.7 k8s和Rancher
运维·docker·容器
IT策士1 小时前
第 43 篇 k8s之集群网络策略:NetworkPolicy 入门
网络·容器·kubernetes
杨某不才1 小时前
Linux服务器离线安装docker
linux·服务器·docker
MyFreeIT2 小时前
Docker & MySQL Manual
mysql·docker·容器
牛奶咖啡132 小时前
k8s容器编排技术实践——k8s应用中机密信息的配置与存储
云原生·kubernetes·k8s中secret资源的创建·k8s的pod使用secret·k8s中configmap创建·k8s中使用configmap·k8s中重要数据的配置与存储
做个文艺程序员10 小时前
第1篇:K8s 核心概念精讲:Pod、Deployment、Service 与 Namespace——Java 开发者快速上手指南
java·云原生·容器·kubernetes·容器编排
一勺菠萝丶11 小时前
Docker Desktop 启动后容器自动启动怎么办?如何关闭容器自启动
运维·docker·容器
做个文艺程序员14 小时前
第08篇:K8s 部署 AI 大模型推理服务:GPU 调度 × vLLM × Java 客户端集成——从 0 到生产的完整方案
人工智能·kubernetes·vllm
Plastic garden15 小时前
K8s(2)安装,集群
云原生·容器·kubernetes