# 01-04-armv7 NFS 服务安装 > 本文只讲 armv7 主机侧 NFS 服务安装与导出配置,目标是把 **`/sdcard`** 作为 NFS 共享目录导出给 K3s 节点使用。 ## TL;DR - **自动化验收**:`./ansible/bin/verify.sh run 01-04` - **关键前置**:按本文「前置条件」准备环境变量/Secret/入口 IP - **成功判据**:达到本文「预期」且 playbook 断言通过 - **排障**:见本文「排障」 ## 前置条件 - 已完成 `01-03-armv7-standalone-docker.md` - armv7 与 K3s 节点网络互通 - armv7 上存在挂载点 `/sdcard`(先用 `mount | grep /sdcard` 确认) ## 操作步骤 1. 在 armv7 安装 NFS 服务(`nfs-utils` 或 `nfs-kernel-server`) 2. 将 `/sdcard` 目录配置为导出目录 3. 配置 `/etc/exports` 4. 使导出生效并启用开机自启 5. (可选)配置防火墙 ### 1) 安装 NFS 服务(按发行版二选一) ```bash # RHEL/CentOS/Fedora sudo dnf install -y nfs-utils sudo systemctl enable --now nfs-server # Debian/Ubuntu # sudo apt update # sudo apt install -y nfs-kernel-server # sudo systemctl enable --now nfs-kernel-server ``` ### 2) 确认 `/sdcard` 可用 ```bash mount | grep /sdcard ls -ld /sdcard ``` > 如果 `/sdcard` 是外置存储(SD 卡/U 盘),建议先确认它已在系统启动后自动挂载,再做 NFS 导出。 ### 3) 配置 `/etc/exports` 导出 `/sdcard` 示例(允许 `192.168.2.0/24` 网段读写): ```bash echo "/sdcard 192.168.2.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee /etc/exports sudo exportfs -rav ``` 参数说明(常用): - `rw`:允许读写 - `sync`:同步写入,数据更稳妥 - `no_subtree_check`:减少子目录检查开销 - `no_root_squash`:客户端 root 保持 root 权限(仅在可信内网使用) ### 4) 防火墙(可选,按环境) 如果 armv7 启用了 firewalld: ```bash sudo firewall-cmd --add-service=nfs --permanent sudo firewall-cmd --add-service=mountd --permanent sudo firewall-cmd --add-service=rpc-bind --permanent sudo firewall-cmd --reload ``` 如果是 Debian/Ubuntu + UFW,请按实际策略放行 NFS 相关端口/服务。 ## 验证命令 ```bash showmount -e localhost sudo exportfs -v sudo systemctl status nfs-server --no-pager || sudo systemctl status nfs-kernel-server --no-pager ``` ## 预期 - `showmount -e` 可看到导出目录 `/sdcard` - NFS 服务为运行状态 ## 客户端快速验证(在任一 K3s 节点) ```bash sudo mkdir -p /mnt/nfs-sdcard-test sudo mount -t nfs :/sdcard /mnt/nfs-sdcard-test df -h | grep nfs-sdcard-test ls -la /mnt/nfs-sdcard-test ``` > 若内网 DNS/主机名不可解析,请直接使用 armv7 的内网 IP(例如 `192.168.2.22:/sdcard`)。 验证完成后可卸载: ```bash sudo umount /mnt/nfs-sdcard-test ``` ## 本次实机验证记录(onecloud -> ylc61) - 服务端(onecloud): - `showmount -e localhost` 返回 `/sdcard 192.168.2.0/24` - `exportfs -v` 显示 `/sdcard` 已按配置导出 - 客户端(ylc61): - `mount -t nfs 192.168.2.22:/sdcard /mnt/nfs-sdcard-test` 成功 - 可写入测试文件 `.nfs_write_test` - `umount /mnt/nfs-sdcard-test` 成功 ## NFS 安全验证与加固 ### 先明确:默认 NFS 没有“用户名/密码登录” 当前这种 `/etc/exports` 用法(如 `192.168.2.0/24(...)`)主要基于: - 客户端来源 IP/网段控制 - UID/GID 映射(`root_squash`/`all_squash`) 它不是“账号密码”或“密钥登录”模型。若需要强身份认证与加密,应使用 NFSv4 + Kerberos(见下文)。 ### 基础安全加固(内网实用版) 先解释你关心的几个参数(核心差异): - `no_root_squash`:客户端 root 在服务端仍是 root(权限非常大,不推荐默认使用)。 - `root_squash`:客户端 root 会被压缩为匿名用户(更安全,推荐默认)。 - `all_squash`:不仅 root,连普通用户也统一映射为匿名用户(最“收敛”,但权限控制最粗)。 > 你说的“通常 NFS 只是数据目录,普通读写就够了”,这个判断是对的。 > 对大多数家庭实验室,优先 `root_squash` 即可,不必一上来 `no_root_squash`。 #### 推荐配置 A(默认推荐:保留普通用户语义,仅压缩 root) ```bash echo "/sdcard 192.168.2.0/24(rw,sync,no_subtree_check,root_squash)" | sudo tee /etc/exports sudo exportfs -rav ``` 适用:一般数据目录读写场景,既降低 root 风险,又不过度收紧普通用户行为。 若切到 `root_squash` 后客户端出现 `Permission denied`,通常是导出目录权限还停留在 `root:root`。可在服务端先调整目录属主与权限(按你的风险接受度选择更细粒度权限): ```bash sudo chown nobody:nogroup /sdcard sudo chmod 0777 /sdcard ``` > 说明:这是“保证先可写”的快速做法。更严格场景建议用更小权限(例如按业务 UID/GID 精细授权),不要长期依赖 `0777`。 **更小权限的实操示例(推荐)** > 多容器/多应用共享 NFS 时,不建议只改 `/sdcard` 根目录权限;更推荐“**根目录只做入口,每个应用单独子目录分权**”。 示例:应用 A 用 `UID/GID=1000`,应用 B 用 `UID/GID=1001`。 ```bash # 1) 根目录:保守权限(可遍历,不建议直接 0777) sudo chown root:root /sdcard sudo chmod 0755 /sdcard # 2) 应用A子目录 sudo mkdir -p /sdcard/app-a sudo chown 1000:1000 /sdcard/app-a sudo chmod 0770 /sdcard/app-a # 3) 应用B子目录 sudo mkdir -p /sdcard/app-b sudo chown 1001:1001 /sdcard/app-b sudo chmod 0770 /sdcard/app-b ``` 如果你选择 `all_squash`,再配合匿名映射到同一业务账号: ```bash echo "/sdcard 192.168.2.0/24(rw,sync,no_subtree_check,root_squash,all_squash,anonuid=1000,anongid=1000)" | sudo tee /etc/exports sudo exportfs -rav ``` 验证(服务端): ```bash sudo exportfs -v ls -ldn /sdcard ls -ldn /sdcard/app-a /sdcard/app-b ``` 你应能看到: - `exportfs -v` 中导出参数已是目标策略(如 `root_squash` / `all_squash,anonuid=1000`) - 导出参数符合目标策略 - 各应用子目录的属主属组与业务 UID/GID 一致(如 `app-a` 为 `1000:1000`) 在 K8s Pod 侧,建议与之对应: - 应用 A:`runAsUser/runAsGroup/fsGroup` 使用 `1000` - 应用 B:`runAsUser/runAsGroup/fsGroup` 使用 `1001` 这样比把 `/sdcard` 全盘 `0777` 更可控:权限边界在“每个业务子目录”,不同应用互不踩权限。 #### 推荐配置 B(更严格:所有用户都匿名) ```bash echo "/sdcard 192.168.2.0/24(rw,sync,no_subtree_check,root_squash,all_squash,anonuid=65534,anongid=65534)" | sudo tee /etc/exports sudo exportfs -rav ``` “所有用户都匿名”的含义与影响: - 含义:客户端不论是 root 还是普通用户,服务端都按同一个匿名身份(通常 `nobody:nogroup`)处理。 - 影响:权限简单统一,但会丢失“按用户区分权限”的能力;某些应用可能因属主/权限不匹配而报错。 - 建议:仅在你明确要“统一身份写入”时启用。 #### 不推荐长期保留(除非明确必须) ```bash echo "/sdcard 192.168.2.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee /etc/exports sudo exportfs -rav ``` `no_root_squash` 只建议临时排障或已做严格网络隔离时短期使用。 配套建议: - 防火墙只放行必要客户端 IP(不要整段网段) - NFS 服务只暴露在可信内网/VLAN - 客户端挂载可加 `nosuid,nodev,noexec`(按业务兼容性评估) ### 安全验证命令(基础版) ```bash # 服务端:确认导出参数 sudo exportfs -v # 客户端:确认挂载参数 mount | grep nfs ``` 核对点: - 采用推荐配置 A/B 时,`exportfs -v` 中不应出现 `no_root_squash` - 挂载后普通读写符合预期 - 若启用 `all_squash`,需额外确认应用对匿名 UID/GID 的权限兼容性 ### 强认证路线(进阶):NFSv4 + Kerberos 如果你需要“身份认证/完整性/加密”而不是仅靠 IP 白名单: - 使用 `sec=krb5`(认证) - 或 `sec=krb5i`(认证 + 完整性) - 或 `sec=krb5p`(认证 + 完整性 + 加密,安全最高) 这条路线需要额外建设 KDC、principal、keytab、时钟同步,复杂度明显高于内网基础版;家庭实验室通常先做“基础加固版”,再按需要升级。 ## 与 K3s 对接(入口) 在 K3s 里使用 NFS,通常不需要先把 NFS 手工挂到每台节点主机。 详细做法(Pod 直挂 / PV+PVC)请见:`03-06-k3s-使用nfs存储.md`。 ## 下一步 - `03-06-k3s-使用nfs存储.md` ## 排障 - **先看 playbook 输出**:失败时先定位是 deploy/wait/http_check 哪一步。 - **集群侧总览**:`kubectl get nodes -o wide`、`kubectl -n kube-system get pods -o wide`。 - **事件与日志**:`kubectl -n describe ...`、`kubectl -n logs ... --tail=200`。