Files
Deploy-Laboratory/docs/03-05-k3s-local-path-pvc.md
jack be97836e0d chore: 清理调试脚本并收敛到 Ansible 流程
移除已废弃的调试/验证脚本与空目录,统一文档与脚本说明到 ansible-playbook 的部署方式,避免失效引用和误用路径。

Made-with: Cursor
2026-03-23 19:18:55 +08:00

9.6 KiB
Raw Blame History

03-05-k3s local-path PVC 本地持久化

K3s 自带的 local-path-provisioner:通过 PVC 自动创建本地 PersistentVolume适用于单副本应用、缓存、日志等无需 NFS 或 Longhorn。

与 NFS / Longhorn 的区别

方式 共享 适用场景
local-path(本页) 否,单节点 单副本应用Traefik acme.json、单机数据库等Pod 固定调度到同一节点
NFS03-06-k3s-使用nfs存储.md 是,多节点读写 多副本共享目录、需跨节点访问
Longhorn03-07-k3s-longhorn-持久化存储.md 块存储CSI 重状态系统、快照/备份、生产推荐

前置条件

  • K3s 已安装local-path-provisioner 默认启用)
  • 无额外组件,kubectl get storageclass 可见 local-path(通常为 default例如
NAME                   PROVISIONER             ...
local-path (default)   rancher.io/local-path   ...

操作步骤

1. 清单PVC + Deployment

唯一真源ansible/files/local-path-demo/local-path-pvc-demo.yaml(含 PVC local-pvc-demonginx-local-pvc-demo Deployment清单内已写 storageClassName: local-path,与 kubectl get storageclass 中名称一致即可)。

2. 应用与验证

本仓库根目录执行(或把 -f 换成清单的绝对路径):

kubectl apply -f ansible/files/local-path-demo/local-path-pvc-demo.yaml

# 等 Pod 调度、PVC 绑定后再操作local-path 多为 WaitForFirstConsumer前几秒 Pending 正常)
kubectl rollout status deploy/nginx-local-pvc-demo --timeout=180s

kubectl get pv,pvc
kubectl get pod -o wide
kubectl exec deploy/nginx-local-pvc-demo -- sh -c 'echo hello > /usr/share/nginx/html/test.txt'
kubectl delete pod -l app=nginx-local-pvc-demo
kubectl rollout status deploy/nginx-local-pvc-demo --timeout=180s
kubectl exec deploy/nginx-local-pvc-demo -- cat /usr/share/nginx/html/test.txt  # 应仍为 hello

勿在 Pod 仍为 Pending 时 exec,否则会报 does not have a host assigned。先 kubectl get pod -o wide 确认 NODE 有值且 READY 1/1

3. Pending 排查PVC / Pod 长时间不 Ready

kubectl describe pvc local-pvc-demo -n default
kubectl describe pod -l app=nginx-local-pvc-demo -n default
kubectl get events -n default --sort-by=.lastTimestamp | tail -30
kubectl get pods -n kube-system | grep -i local-path
kubectl logs -n kube-system deploy/local-path-provisioner --tail=80 2>/dev/null || \
  kubectl logs -n kube-system -l app=local-path-provisioner --tail=80

常见原因:local-path-provisioner 未就绪或报错、节点磁盘/权限、曾留下异常 PVC。可删除后重试

kubectl delete deploy/nginx-local-pvc-demo -n default --ignore-not-found
kubectl delete pvc local-pvc-demo -n default --ignore-not-found
# 等待 PV 回收后再 apply
kubectl apply -f ansible/files/local-path-demo/local-path-pvc-demo.yaml
kubectl rollout status deploy/nginx-local-pvc-demo --timeout=180s

注意事项

  • WaitForFirstConsumerPVC 在 Pod 未调度前可长期 PendingPV 在 Pod 首次成功调度到某节点后 才创建,且会带 nodeAffinityPod 重建后仍倾向同一节点
  • 单副本ReadWriteOnce,同一 PVC 只能被同一节点上的一个 Pod 挂载;多副本需 NFS 或 Longhorn
  • 数据路径:默认在 K3s --data-dir 下的 storage,如 /var/lib/rancher/k3s/storage/storage
  • 回收策略Delete,删除 PVC 时 PV 及本地目录会被清理

storageClass: local-path 与「本地路径」说明

PVC / StorageClass 里不能写宿主机目录

在清单里写 storageClassName: local-path(或 Traefik Helm persistence.storageClass: local-path)只表示:交给 K3s 自带的 local-path-provisioner 在某一工作节点上自动创建本地目录并绑定 PV

  • 不能在 PVC 或 StorageClass 里指定「数据必须落在 /mnt/mydata/xxx」这类宿主机绝对路径
  • 实际在节点磁盘上的目录,由 provisioner 的全局配置 + 内部命名规则 生成;通常位于 K3s --data-dir 下的 storage 子树(与上文「注意事项」一致)。

Traefik persistence.path: /data容器内挂载点

traefik-dashboard-acme.yaml 中:

字段 含义
persistence.path: /data Traefik 容器内的挂载目录Helm chart 把 PVC 挂到这里)
acme.storage=/data/acme.json 容器内证书文件路径,与上面挂载一致
storageClass: local-path 使用哪种动态供给方式,不等价于「宿主机路径」

因此:容器里永远是 /data/...;宿主机上对应哪一块目录,要看该 PVC 绑定的 PV

如何查看数据实际落在节点的哪个目录

PVC 绑定后,用 PV 反查Traefik 示例在 kube-system

# 1) 找到 Traefik 使用的 PVC 名称chart 创建的 claim 名因版本可能略有差异)
kubectl -n kube-system get pvc

# 2) 从 PVC 的 Volume / Bound 信息得到 PV 名,再查看 PV路径在 spec 或 describe 输出中)
kubectl -n kube-system describe pvc <你的-pvc-名>
kubectl describe pv <上一步看到的-pv-名>
kubectl get pv <pv-名> -o yaml   # 在 spec 中查 path、hostPath、local、csi.volumeAttributes 等

不同 K3s / provisioner 版本字段名可能略有差异,以 describe / yaml 实际输出为准。

需要指定「整盘根目录」时:改 local-path-provisioner 配置

若希望某一类节点上通过 local-path 创建的数据统一落在指定根路径下(仍由 provisioner 在根下自动分子目录),可编辑 kube-system 中的 ConfigMap local-path-config(键名多为 config.json),使用 nodePathMap 等为节点配置路径。

修改前建议 kubectl -n kube-system get configmap local-path-config -o yaml 备份;改错会导致新 PVC 无法创建。

示意(仅为结构说明,请与集群内现有 JSON 合并修改,勿直接整段覆盖

{
  "nodePathMap": [
    {
      "node": "DEFAULT_PATH_FOR_NON_LISTED_NODES",
      "paths": ["/var/lib/rancher/k3s/storage"]
    },
    {
      "node": "你的节点主机名",
      "paths": ["/data/k3s-local-path"]
    }
  ]
}

保存 ConfigMap 后,通常需 重启 local-path-provisioner 相关负载使配置生效(以你集群实际 Deployment/DaemonSet 名为准):

kubectl -n kube-system rollout restart deploy/local-path-provisioner 2>/dev/null || true

具体字段与默认值以当前 K3s 版本自带的 rancher local-path-provisioner 文档为准。

与 hostPath 的区别

方式 说明
storageClass: local-path 动态 PV路径由 provisioner 管理;适合一般工作负载与 Traefik ACME。
hostPath / 手写 PV 在清单里直接绑定节点上某一目录需自行保证节点一致性与权限与「local-path StorageClass」不是同一条配置路径。

若 Traefik Helm chart 支持你也可使用其 persistence.hostPath 类选项(若版本提供),则属于 显式 hostPath,与仅写 local-path 的用法不同。

Traefik ACME证书固定到 local-path推荐

ACME 存储路径在配置里已是 /data/acme.json(见 03-0203-03。K3s 自带 Traefik Helm chart 支持 persistence:开启后由 chart 自动创建 PVCstorageClass: local-path),挂载到 /data,与 acme.storage 一致,Pod 重建 / 滚动后证书仍在

前提nodeSelector 必须把 Traefik 固定在同一节点(与 local-path ReadWriteOnce 一致);若换节点,需迁卷或重新签发。

场景 唯一真源
Dashboard + ACME + local-path推荐 仅此一份ansible/files/traefik-dashboard-acme/traefik-dashboard-acme.yamlHelmChart persistence + ACME + Dashboard + IngressRoute

清单内已含:persistence.enabled: truestorageClass: local-pathsize: 512Mipath: /data,与 acme.storage=/data/acme.json 一致。部署前替换 <YOUR_REAL_EMAIL>nodeSelector 中的 主机名;并确保 cloudflare-api-token Secret 已存在(同 03-02 / 03-03)。不需要 Dashboard 时按该 YAML 文件头注释删减。

只能有一份 HelmChartConfigmetadata.name: traefik)。若曾用旧版无 persistence 的清单,请 合并为 上述 traefik-dashboard-acme.yaml(或 traefik-acme.yaml 并自行补全 persistence避免多文件重复定义。

应用与核对(路径按你的 manifests 目录调整):

kubectl apply -f ansible/files/traefik-dashboard-acme/traefik-dashboard-acme.yaml

kubectl -n kube-system rollout status deploy/traefik --timeout=300s
kubectl -n kube-system get pvc | grep -i traefik
kubectl -n kube-system exec deploy/traefik -- ls -la /data/acme.json
kubectl -n kube-system logs deploy/traefik --tail=80 | grep -i acme || true

emptyDir / 无持久卷 迁到 PVC 时,若旧 Pod 里已有有效 acme.json,可先 kubectl cp 备份再切换;否则切换后会按新账户重新向 Lets Encrypt 申请。

更多 ACME 排障见 03-02-k3s-traefik-acme.md03-03-k3s-traefik-dashboard-acme.md

下一步

  • 03-06-k3s-使用nfs存储.md:需多节点共享时
  • 03-07-k3s-longhorn-持久化存储.md:重状态、快照、备份