Files
Deploy-Laboratory/docs/03-06-k3s-使用nfs存储.md
2026-03-27 16:58:41 +08:00

228 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 03-06-k3s 使用 NFS 存储
> 本文只讲 K3s 集群侧如何使用已安装好的 NFS。
## TL;DR
- **自动化验收**`./scripts/verify.sh run 03-06`
- **关键前置**:按本文「前置条件」准备环境变量/Secret/入口 IP
- **成功判据**:达到本文「预期」且 playbook 断言通过
- **排障**:见本文「排障」
## 前置条件
- 已完成 `01-05-armv7-nfs服务安装.md`
- 可从 K3s 节点访问 NFS 服务器与导出目录
## 方式对比(从简单到复杂)
| 项 | 方式 1Pod 直接挂 NFS | 方式 2静态 NFSPV + PVC | 方式 3动态 NFS选装 provisioner |
|---|---|---|---|
| 复杂度 | 低 | 中 | 高 |
| 最少 YAML 段数 | 1 段Deployment/Pod | 2 段PV+PVC | 通常 1 段 PVCPV/目录动态生成) |
| 目录创建 | 需手工提前创建 | 需手工提前创建 | 通常由 provisioner 自动创建子目录 |
| 与应用耦合 | 高(写死 server/path | 低(应用只引用 PVC | 低(应用只引用 PVC |
| 适用场景 | 临时验证、概念验证(先跑通) | 稳定运行、团队协作 | 大规模/多团队、追求自动化 |
## 操作步骤
1. 按复杂度选择一种方式
2. 应用清单
3. 验证读写
> 结论K3s 使用 NFS **不需要**先把 NFS 手工挂到每台节点主机Pod/PVC 可直接挂远端 NFS。
### 方式 1Pod 直接挂 NFS最简单快速验证
> 说明:`nfs.path` 指向的目录(或子目录)需要在 NFS 服务端**提前创建并设置好权限**K3s 不会自动在 NFS 服务端创建该目录。
>
> 例如在 onecloud 上预创建子目录:
>
> ```bash
> sudo mkdir -p /sdcard/app-a
> sudo chown 1000:1000 /sdcard/app-a
> sudo chmod 0770 /sdcard/app-a
> ```
```yaml
apiVersion: apps/v1 # Deployment 使用的 API 版本
kind: Deployment # 资源类型Deployment
metadata: # 资源元信息
name: nfs-direct-demo # Deployment 名称
namespace: default # 命名空间
spec: # Deployment 规格
replicas: 1 # 副本数
selector: # Pod 选择器
matchLabels: # 标签匹配条件
app: nfs-direct-demo # 选择带 app=nfs-direct-demo 的 Pod
template: # Pod 模板
metadata: # Pod 元信息
labels: # Pod 标签
app: nfs-direct-demo # Pod 标签值
spec: # Pod 规格
containers: # 容器列表
- name: app # 容器名称
image: nginx:alpine # 容器镜像
volumeMounts: # 容器内挂载点
- name: nfs-data # 引用下方 volumes 的卷名
mountPath: /usr/share/nginx/html # 挂载到容器内目录
volumes: # Pod 卷定义
- name: nfs-data # 卷名
nfs: # 直接使用 NFS 卷
server: <NFS_SERVER_IP> # NFS 服务器地址(应用前替换)
path: <NFS_EXPORT_PATH_OR_SUBDIR> # NFS 导出目录或子目录(应用前替换)
```
可执行真源:[`ansible/files/03-06/nfs-direct-demo.yaml`](../ansible/files/03-06/nfs-direct-demo.yaml)。
### 方式 2静态 NFSPV + PVC推荐
**唯一真源**[`ansible/files/03-06/nfs-pv-pvc-demo.yaml`](../ansible/files/03-06/nfs-pv-pvc-demo.yaml)。
> 为减少硬编码,示例清单已改为占位符:`<NFS_SERVER_IP>`、`<NFS_EXPORT_PATH>`。
> 应用前必须先替换(例如 `192.168.2.22`、`/sdcard`)。
> 静态 NFS 同样需要在服务端提前创建目录并设置权限;不会自动创建目录。
### 方式 3动态 NFS选装 provisioner
这是选装增强,不是 K3s 内置默认能力。常见组件是 `nfs-subdir-external-provisioner`
### 3.1 安装 provisionerHelm
> 前提NFS 服务端已可用(例如 `192.168.2.22:/sdcard`),且 K3s 节点网络可达。
```bash
# 1) 添加 chart 仓库
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update
# 2) 安装(建议放到 kube-system
helm upgrade --install nfs-subdir-external-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
-n kube-system --create-namespace \
--set nfs.server=192.168.2.22 \
--set nfs.path=/sdcard \
--set storageClass.name=nfs-client \
--set storageClass.defaultClass=false \
--set storageClass.reclaimPolicy=Delete \
--set storageClass.archiveOnDelete=true
```
参数说明(最常改):
- `nfs.server`NFS 服务器地址
- `nfs.path`NFS 导出根目录provisioner 会在其下创建子目录)
- `storageClass.name`:动态供给使用的 StorageClass 名称
- `archiveOnDelete`:删除 PVC 时是否归档目录(`true` 更稳妥,`false` 更干净)
### 3.2 验证 provisioner 与 StorageClass
```bash
kubectl -n kube-system get pod -l app.kubernetes.io/name=nfs-subdir-external-provisioner -o wide
kubectl get storageclass
```
### 3.3 用动态 PVC 验证自动建卷
创建一个最小 PVC示例
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-dynamic-pvc-demo
namespace: default
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-client
resources:
requests:
storage: 5Gi
```
可执行真源:[`ansible/files/03-06/nfs-dynamic-pvc-demo.yaml`](../ansible/files/03-06/nfs-dynamic-pvc-demo.yaml)。
应用并验证:
```bash
kubectl apply -f ansible/files/03-06/nfs-dynamic-pvc-demo.yaml
kubectl get pvc nfs-dynamic-pvc-demo -n default
kubectl get pv | grep nfs-dynamic-pvc-demo
```
当 PVC `Bound` 后,通常可在 NFS 服务器的 `/sdcard` 下看到自动创建的子目录(命名规则由 provisioner 管理)。
### 3.5 本次实机验证记录ylc61 + onecloud
- `nfs-subdir-external-provisioner` 安装成功并 `Running`
- `StorageClass nfs-client` 创建成功
- 动态 PVC `nfs-dynamic-pvc-demo` 成功 `Bound`
- 自动创建 PV 成功,并在 NFS 服务端目录下生成子目录:
- `/sdcard/default-nfs-dynamic-pvc-demo-pvc-<uid>`
- 删除临时 PVC 后PV 按 `Delete` 回收完成
> 备注:验证中曾出现过镜像拉取 `EOF`(偶发网络抖动),重试后官方镜像 `registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2` 已可正常拉取并启动。
### 3.4 何时选动态 NFS
- 目录数量多、变更频繁
- 希望减少手工维护 PV/PVC 对应关系
- 团队里希望应用只声明 PVC平台统一管理 StorageClass
## 验证命令(若 YAML 在 manifests 目录,按实际路径选择其一复制执行)
```bash
# 仓库根直接应用
# 先替换 ansible/files/03-06/nfs-pv-pvc-demo.yaml 里的占位符
# <NFS_SERVER_IP> -> 例如 192.168.2.22
# <NFS_EXPORT_PATH> -> 例如 /sdcard
kubectl apply -f ansible/files/03-06/nfs-pv-pvc-demo.yaml
```
```bash
# 或默认路径(已拷贝到 manifests 时)
kubectl apply -f /var/lib/rancher/k3s/server/manifests/nfs-pv-pvc.yaml
kubectl get pv,pvc -A
kubectl describe pv nfs-pv-demo
```
```bash
# 自定义 data-dir如 /storage
kubectl apply -f /storage/server/manifests/nfs-pv-pvc.yaml
kubectl get pv,pvc -A
kubectl describe pv nfs-pv-demo
```
```bash
# 对方式 1Pod 直挂)可这样验证
kubectl apply -f ansible/files/03-06/nfs-direct-demo.yaml
kubectl rollout status deploy/nfs-direct-demo --timeout=180s
kubectl exec deploy/nfs-direct-demo -- sh -c 'echo nfs-direct-ok > /usr/share/nginx/html/nfs.txt && cat /usr/share/nginx/html/nfs.txt'
```
## 预期
- PV/PVC 状态为 `Bound`
- 业务 Pod 可读写挂载目录
## 失败排查
- 检查 NFS 服务与导出目录权限
- 检查节点到 NFS 服务器网络
- 检查 `path``server` 配置是否正确
- 若报 `Permission denied`,回到 `01-05``root_squash` 权限章节,确认导出目录与业务 UID/GID 对齐
## 下一步
- `03-05-k3s-local-path-pvc.md`:单副本应用用 K3s 自带 local-path 即可,无需 NFS
- `05-06-openlist挂载网盘与自动备份.md`
## 排障
- **先看 playbook 输出**:失败时先定位是 deploy/wait/http_check 哪一步。
- **集群侧总览**`kubectl get nodes -o wide``kubectl -n kube-system get pods -o wide`
- **事件与日志**`kubectl -n <ns> describe ...``kubectl -n <ns> logs ... --tail=200`