Files
Deploy-Laboratory/docs/03-07-k3s-longhorn-持久化存储.md
2026-03-27 16:58:41 +08:00

512 lines
25 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-07-k3s Longhorn 持久化存储4 节点实验环境)
> 本实验:**K3s 四节点集群**、**每节点 8 GiB 内存**(与下文「系统资源」建议档一致)、**磁盘基线为约 10G 系统盘 + 32G 数据盘****`/storage`** 必须挂在独立数据盘上(与 `/` 不同设备),详见 `00-02-部署环境说明.md`。**没有 NFS**,用 Longhorn 做集群内动态块存储;若后续要部署 GitLab 等重状态系统,可在此基础上接 PVC。副本数可按实验目标在「省空间」与「模拟高可用」之间取舍。
## TL;DR
- **自动化验收**`./scripts/verify.sh run 03-07`
- **关键前置**:按本文「前置条件」准备环境变量/Secret/入口 IP
- **成功判据**:达到本文「预期」且 playbook 断言通过
- **排障**:见本文「排障」
---
## 磁盘与 `/storage` 前提
Longhorn 与 K3s 的 `containerd`/镜像、local-path 都会大量占用 **`k3s_data_dir`(本仓库默认 `/storage`**。若 `/storage` 只是根分区上的普通目录,控制节点易出现 **DiskPressure / Evicted**
- **请先阅读**[`00-02-部署环境说明.md`](00-02-部署环境说明.md)(四节点统一拓扑、自检命令、推荐 playbook 顺序)。
- **自检**(每台节点):`mountpoint -q /storage && findmnt -n -o SOURCE /``findmnt -n -o SOURCE /storage` 输出须**不同**。
- **Ansible**`01-06.yml -e k3s_do_install=true``k3s_verify_storage_mount: true``group_vars/all.yml` 默认)时会在安装前校验上述条件;可选先跑 `01-06.yml -e k3s_do_prepare_storage=true -e k3s_prepare_storage=true` 准备第二块盘,见 `01-06-节点初始化-ansible-实践.md`
- Longhorn 数据目录建议为 **`/storage/longhorn`**(与 Helm `values-lab.yaml` 一致),勿与系统盘混用。
**容量与副本数**:每节点数据盘约 **32G** 时,`defaultReplicaCount`**2 或 3** 会使同一份逻辑卷在集群内占用 **多倍物理空间**(各副本落在不同节点上各占一份),且 Longhorn 元数据与系统组件仍有开销;实验环境可先用副本 **1**,要演练跨节点冗余再调高并预留磁盘。
---
## 为什么要用 Longhorn而不是 hostPath / local-path / 容器文件系统)
- **容器文件系统**Pod 重建即丢,基本不可用
- **hostPath 固定目录**:能落盘,但和调度强绑定,迁移/扩缩容/备份都更麻烦
- **local-path PVC**(见 `03-05-k3s-local-path-pvc.md`K3s 自带,单副本够用;无快照/备份,多副本需 NFS 或 Longhorn
- **LonghornCSI 块存储)**:对 K8s 来说是标准 PVC即使你只设 **副本数=1**,也能获得:
- 统一的 PVC 管理与回收策略
- 快照snapshot
- 备份backup target可推到对象存储
> 重要:**副本数=1** 时,卷只在集群里有一份数据,**节点故障仍可能丢卷**。四节点集群里若要演练节点级容灾,把卷的副本数调到 2 或 3并配合备份到外部介质。
---
## 前置条件CentOS
在**每一台**计划参与 Longhorn 的节点上安装依赖(本实验为 **4 节点**,通常四台都要装;若你明确只让部分节点承担存储,也至少要保证这些节点已装齐):
```bash
sudo yum install -y iscsi-initiator-utils nfs-utils
sudo systemctl enable --now iscsid
```
准备数据盘目录(你已有专用盘挂载到 `/storage`,建议给 Longhorn 单独目录):
```bash
sudo mkdir -p /storage/longhorn
sudo chmod 700 /storage/longhorn
```
---
## 系统资源CPU / 内存)
Longhorn **没有**在文档里给一张适用于所有场景的「每节点必须 ≥X 核、≥Y GB 内存」的固定表。安装前置、磁盘与网络等见官方 [Installation requirementsv1.7.2](https://longhorn.io/docs/archives/1.7.2/deploy/install/) 与 [Best practices - Minimum recommended hardware](https://longhorn.io/docs/archives/1.7.2/best-practices/#minimum-recommended-hardware)(其中对**磁盘** IOPS/吞吐、SSD 建议、节点间带宽等描述较多)。下面按「能规划容量」和「能对照官方默认值」两部分说明。
### CPU与官方默认机制相关
- 使用默认的 **V1 数据引擎**时,全局设置 **[Guaranteed Instance Manager CPU](https://longhorn.io/docs/archives/1.7.2/references/settings/#guaranteed-instance-manager-cpu)** 默认值为 **12**:表示为每个 **Instance Manager** Pod 预留该节点 **可分配 CPUallocatable的 12%**,用于保障引擎与副本稳定(详见 [Best practices - V1 Data Engine](https://longhorn.io/docs/archives/1.7.2/best-practices/#v1-data-engine))。
- 节点 **CPU 越小**在其它负载不变时Longhorn 与业务争抢余量的压力越大;卷多、重建/备份繁忙时更明显。
**实验环境规划(在 K3s 与系统开销之外,仍能跑少量业务)**
| 档位 | 每节点 CPU | 说明 |
| --- | --- | --- |
| 建议 | **≥ 4 vCPU** | 与常见实验/小型业务负载较匹配 |
| 最低(仅验证组件) | **2 vCPU** | 可能频繁触顶、调度排队;与 Instance Manager 预留叠加后余量偏紧 |
### 内存
-**longhorn-manager、CSI、engine-image** 等常驻组件外,**Instance Manager** 等会随卷、I/O、**副本数**、备份与重建任务变化;官方不以「每节点固定 GB」一条公式概括。
- 若启用 **V2 数据引擎**,节点还需按官方说明预留 **Huge Pages** 等(见 [V2 前置条件](https://longhorn.io/docs/archives/1.7.2/v2-data-engine/prerequisites/)),与 V1 场景不同,勿与下表混用。
**实验环境规划V1、常规用途**
| 档位 | 每节点内存(约) | 说明 |
| --- | --- | --- |
| 建议 | **≥ 8 GiB** | 留给 OS、kubelet、系统 Pod、Longhorn、业务 |
| 偏低 | **4 GiB** | 仅适合极简演示;卷与业务稍多时 **OOM 风险**高 |
**ARM64、整机只有 4 GiB 内存的设备**Longhorn **支持** ARM64见官方 [Best practices - Architecture](https://longhorn.io/docs/archives/1.7.2/best-practices/#architecture)),限制主要来自 **总内存与 CPU 余量**不是「ARM 能不能装」。在 **4 GiB 整机**上还要跑 K3s 系统组件 + Longhorn DaemonSet/CSI/Instance Manager 时,**不建议**把该节点当作 Longhorn 的**常规存储节点**(更不适合再叠加重状态业务)。更稳妥的做法是:存储用 **`03-05-k3s-local-path-pvc.md`** 的 local-path 或明确路径的 hostPath或仅在 **≥8 GiB** 的节点上跑 Longhorn**4 GiB 的 ARM 板**尽量只做**计算节点**并在 Longhorn UI 中**禁用其磁盘/不参与副本**(若仍装 Longhorn 组件,至少减轻数据面压力)。
官方仓库中的「中等规模」**性能测试参考节点**为 **8 vCPU、32 GB RAM**(用于可复现压测,**不是**最低装机要求),见 [medium node spec](https://github.com/longhorn/longhorn/blob/master/scalability/reference-setup-performance-scalability-and-sizing-guidelines/public-cloud/medium-node-spec.md)。
### 部署后自检(推荐)
已安装 **metrics-server** 时:
```bash
kubectl top node
kubectl top pod -n longhorn-system
```
未安装时,至少查看节点 **Allocatable** 与 Longhorn Pod 分布:
```bash
kubectl describe node
kubectl get pod -n longhorn-system -o wide
```
---
## SSH 部署试跑顺序4×8 GiB
当前规格 **四台、各 8 GiB**,适合按本篇做一次完整试跑:`kubectl apply` 只在**控制节点**执行一次;**四台**都要完成 iSCSI/NFS 依赖与数据目录(见「前置条件」)。
与本仓库 **Ansible 清单**对应时,主机名为 **`ylc61`**(控制 / `k3s_server`)、**`ylc62``ylc64`**(工作节点),见 `ansible/inventory.ini`。下列命令里的 `Host` 请换成你 **SSH 已通** 的名字(或 `root@192.168.2.61` 等形式)。
### SSH 配置说明(本机能否直连「各节点」)
- **`ylc61`(控制节点)**:常见做法是在本机 `~/.ssh/config` 里配置 `Host ylc61``IdentityFile` 指向**该节点专用私钥**(例如仓库内 `.ssh/id_ed25519_k3s_192.168.2.61`,与 `01-06` / 建链脚本一致)。配好后可 **`ssh ylc61`**,并在其上执行 **`kubectl`**(设好 `KUBECONFIG`**不必**强求本机安装 kubectl 或直连 API Server。
- **`ylc62``ylc64`(工作节点)**`ansible/inventory.ini` 里为**每台**配置了**不同**的 `ansible_ssh_private_key_file`(如 `~/.ssh/id_ed25519_k3s_192.168.2.62` …)。若本机 `~/.ssh/config` **没有**对应 `Host ylc62` …,则 **`ssh ylc62``Permission denied`**(用错成控制节点密钥时尤其常见)。需要本机循环 SSH 四台时,请为 **6264** 各写一段 `Host``IdentityFile` 与清单路径一致。
- **只做 Longhorn 安装与排查时**:多数步骤只需 **`ssh ylc61` + `kubectl`**;只有要到**具体工作节点**执行 **`ctr` 预拉镜像**、看 **kubelet/containerd** 时,才必须能登录该节点(直连、串口、或 Ansible `-l ylc63` 等均可)。
`~/.ssh/config` 示例(路径按你机器上实际私钥位置修改):
```sshconfig
Host ylc62
HostName 192.168.2.62
User root
IdentityFile ~/.ssh/id_ed25519_k3s_192.168.2.62
Host ylc63
HostName 192.168.2.63
User root
IdentityFile ~/.ssh/id_ed25519_k3s_192.168.2.63
Host ylc64
HostName 192.168.2.64
User root
IdentityFile ~/.ssh/id_ed25519_k3s_192.168.2.64
```
### 1. 四台节点:依赖 + 目录(从办公机循环 SSH
```bash
for h in ylc61 ylc62 ylc63 ylc64; do
echo "=== $h ==="
ssh "$h" 'sudo bash -s' <<'REMOTE'
if command -v dnf >/dev/null 2>&1; then
dnf install -y iscsi-initiator-utils nfs-utils
else
yum install -y iscsi-initiator-utils nfs-utils
fi
systemctl enable --now iscsid
mkdir -p /storage/longhorn
chmod 700 /storage/longhorn
REMOTE
done
```
### 2. 控制节点:安装 Longhorn只做一次
**首选Helm + 本仓库 `values-lab.yaml`**(与 K3s 常见实践一致,版本与实验室变量集中在 `ansible/group_vars/all.yml``longhorn_chart_version`)。
- **Ansible推荐**:在控制机执行(与 `01-06` 顺序一致):
```bash
cd ansible
ansible-playbook -i inventory.ini playbooks/verify/03-07.yml
```
该 playbook 会在各节点安装 iSCSI/NFS 依赖、在控制节点安装 Helm`dnf/yum``helm` 包则需按 [Helm 安装文档](https://helm.sh/docs/intro/install/)手工安装后重跑)、再 `helm upgrade --install`。values 真源:[`ansible/files/03-07/values-lab.yaml`](../ansible/files/03-07/values-lab.yaml)。可选:`longhorn_apply_local_path_lab: true` 时一并应用 `03-05` 中的 local-path 实验室 ConfigMap。
- **手工 Helm**(在 **`ylc61`** 或任意已配置 `KUBECONFIG` 的机器上kubeconfig 见 `01-01-k3s-控制节点含traefik.md`
```bash
ssh ylc61
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
helm repo add longhorn https://charts.longhorn.io
helm repo update
# 将仓库内 ansible/files/03-07/values-lab.yaml 拷到本机路径后:
helm upgrade --install longhorn longhorn/longhorn \
--namespace longhorn-system --create-namespace \
-f ./values-lab.yaml \
--version 1.7.2 \
--wait --timeout 15m
```
Helm 安装时 **`values-lab.yaml` 已包含** `defaultDataPath``defaultReplicaCount`、默认 StorageClass 等,**一般无需**再执行下文针对 `kubectl apply` 方式的 **`default-data-path` / StorageClass patch**。
**备选:官方清单 `kubectl apply`**(无 Helm 或需与旧文档对齐时使用):
```bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml
kubectl -n longhorn-system rollout status deploy/longhorn-ui --timeout=300s
```
然后按下文 **「安装 Longhorn」** 中 **kubectl 路径**补 **`default-data-path` 补丁**、**默认 StorageClass** 等。若经 Windows 再 SSH 导致 JSON patch 失败,用文中 **`python3` 补丁** 段落。
**Longhorn UI 访问**、**手动验证**与下文各节相同。
### 3. 试跑成功判据(最短)
- `kubectl -n longhorn-system get pod` 中关键 Pod 为 **Running**(四节点时 DaemonSet 应对齐节点数;若有 `ImagePullBackOff`,到**对应节点** `ctr` 预拉镜像,见「手动验证」)。
- 能打开 UI**port-forward** 或临时 **NodePort**Node 页可见四节点。
- 可选下文「最小读写验证」PVC + Pod 写文件通过。
---
## 安装 Longhorn
**不是**在每台机器上各执行一遍安装:无论 **Helm** 还是 **`kubectl apply`****对整个集群只做一次**(在能访问 API 的机器上执行即可Longhorn 的控制面、CSI、DaemonSet 等会由 Kubernetes 统一下发。
**每台节点**仍要做的是:前文「磁盘前提」「前置条件」里的 **OS 依赖**与 **`/storage/longhorn` 目录**Ansible `03-07.yml` 会创建)。若节点在集群内且未被 cordonLonghorn 的 DaemonSet 往往也会在**各节点**拉起组件 Pod因此各节点通常都要能 **拉取镜像**;只有「存数据」可以只在部分节点上开启(见下文「只让有大盘的节点承载数据」)。
### 首选Helm + `values-lab.yaml`
与上文 **「SSH 试跑顺序 §2」**一致:使用 **`ansible-playbook ... playbooks/verify/03-07.yml`**(或 `labs/longhorn-stack.yml`)或手工 **`helm upgrade --install ... -f values-lab.yaml`**。Chart 仓库:`https://charts.longhorn.io`values 字段以 [Longhorn Helm Chart](https://github.com/longhorn/longhorn/tree/master/chart) 当前版本为准。
### 备选:`kubectl apply` 官方清单
未使用 Helm 时:
```bash
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml
kubectl -n longhorn-system rollout status deploy/longhorn-ui
```
将 Longhorn 默认数据路径改到 `/storage/longhorn`
```bash
kubectl -n longhorn-system patch settings.longhorn.io default-data-path \
--type=merge -p '{"value":"/storage/longhorn"}'
```
若出现 `invalid character ':' in string escape code`(多经一层 SSH/脚本时 JSON 被错误转义),在**控制节点**用下面方式补丁(不依赖引号嵌套):
```bash
python3 - <<'PY'
import subprocess, json
patch = json.dumps({"value": "/storage/longhorn"})
subprocess.check_call([
"kubectl", "-n", "longhorn-system", "patch", "settings.longhorn.io", "default-data-path",
"--type=merge", "-p", patch,
])
subprocess.run([
"kubectl", "-n", "longhorn-system", "get", "settings.longhorn.io", "default-data-path",
"-o", "jsonpath={.status.value}{'\n'}",
])
PY
```
`longhorn` 设为默认 StorageClass推荐
```bash
kubectl get storageclass
kubectl patch storageclass longhorn -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
```
`patch storageclass` 同样因转义失败,可改用:
```bash
python3 - <<'PY'
import subprocess, json
p = json.dumps({"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}})
subprocess.check_call(["kubectl", "patch", "storageclass", "longhorn", "-p", p])
PY
```
---
## Longhorn UI部署与访问
### 是否需要单独部署
**不需要。** 官方 `longhorn.yaml` 里已包含 **Deployment `longhorn-ui`****Service `longhorn-frontend`**(命名空间 `longhorn-system`)。执行上文 `kubectl apply -f .../longhorn.yaml`UI 会与其它组件一起创建;安装阶段里的 `kubectl ... rollout status deploy/longhorn-ui` 就是在等 UI 就绪。
若 UI 长期不 Ready优先按节点查 **镜像拉取****Pod 事件**(见下文「手动验证」)。
### 部署与网络对象核验
```bash
kubectl -n longhorn-system get deploy longhorn-ui
kubectl -n longhorn-system get svc longhorn-frontend
kubectl -n longhorn-system get pod -l app=longhorn-ui -o wide
kubectl -n longhorn-system rollout status deploy/longhorn-ui --timeout=300s
```
`longhorn-frontend` 默认多为 **ClusterIP**,集群外浏览器**不能直接**访问 Service VIP需用 **port-forward**、**NodePort** 或 **Ingress** 之一。
### 访问方式一:`kubectl port-forward`(实验环境推荐)
在**已配置 kubeconfig、能访问 API** 的机器上执行(可以是办公机,也可以是某台 SSH 上去的控制节点):
```bash
kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80
```
浏览器打开:**http://127.0.0.1:8080**
**常见场景**
- 只在控制节点上有 `kubectl`:先 SSH 到控制节点执行上述命令,再用浏览器访问——若浏览器在本地电脑,需 **SSH 本地转发**,例如在本机执行
`ssh -L 8080:127.0.0.1:8080 user@控制节点`
然后在控制节点上 `port-forward` 绑定 `127.0.0.1:8080`,本地浏览器仍访问 `http://127.0.0.1:8080`
- 需要把转发绑到非本机接口时(慎用,内网限定):
`kubectl -n longhorn-system port-forward --address 0.0.0.0 svc/longhorn-frontend 8080:80`
**无图形界面时的快速验证**`port-forward` 占用当前终端时,另开一个终端):
```bash
curl -sI http://127.0.0.1:8080 | head -n 5
```
能返回 `HTTP/1.1 200``302` 等即说明 UI 服务已响应(具体状态码随版本可能略有不同)。
### 访问方式二:临时改为 NodePort仅实验内网
便于用「任意节点 IP + 端口」访问,**不要对公网暴露**。
```bash
kubectl -n longhorn-system patch svc longhorn-frontend -p '{"spec":{"type":"NodePort"}}'
kubectl -n longhorn-system get svc longhorn-frontend
```
在输出里查看 `PORT(S)` 一列的 `80:3xxxx/TCP`,用浏览器访问:**`http://` + 任意节点内网 IP + `:` + NodePort 端口**。
实验结束后若要改回 **ClusterIP**(与默认清单一致,便于继续只用 port-forward
```bash
kubectl -n longhorn-system patch svc longhorn-frontend -p '{"spec":{"type":"ClusterIP"}}'
```
一般由 apiserver 重新分配 Cluster IP若与预期不符从当前版本的 `longhorn.yaml` 中仅重新 `apply` **Service `longhorn-frontend`** 那一段即可。
### 访问方式三Ingress + Traefik可选生产需认证与 TLS
K3s 默认带 Traefik 时,可为 `longhorn-frontend`**Ingress**,用域名访问。**生产或跨网段**务必配 **HTTPS****身份认证**Longhorn 支持多种认证方式,以[官方文档](https://longhorn.io/docs/)当前版本为准),实验环境若仅用内网域名也至少限制来源网段。
### 界面内验证要点
打开 UI 后确认:
- **Node** 页能看到集群节点,状态与磁盘信息合理(与 `kubectl get nodes` 对照)。
- **Volume** 在创建测试 PVC 后出现对应卷(可与下文「最小读写验证」联动)。
- 需要改**默认副本数**、**节点磁盘是否可调度**时,在 **Setting** / **Node** 中操作(与上文「实验环境建议配置」一致)。
若页面无法加载或接口报错,查看 UI 与后端:
```bash
kubectl -n longhorn-system logs deploy/longhorn-ui --tail=80
kubectl -n longhorn-system describe pod -l app=longhorn-ui
```
---
## 实验环境建议配置4 节点)
### DaemonSet 与镜像
- `longhorn-manager``engine-image` 等会以 DaemonSet 形式跑在**多个节点**上;四节点时**每个节点**都应对应有 Pod 最终就绪(若某台 `ImagePullBackOff`,先在**该节点**用 `ctr` 预拉镜像,见下文「手动验证」)。
- 数据路径与 `default-data-path` 是**按节点**生效的:四台都要能访问你设定的目录(例如每台都有 `/storage/longhorn`,或只在有盘的节点上建目录并在 UI 里禁用无盘节点)。
### 副本数
- **默认副本数=1**:省磁盘、适合先跑通功能;四节点集群里卷仍可能只落在某一个节点上。在 **每节点约 32G 数据盘** 的实验室基线下,优先用 **1** 避免多副本占满盘。
- **默认副本数=2 或 3**:利用多节点做副本,更接近生产里的冗余;**物理占用约为逻辑卷大小 × 副本数**再加引擎与文件系统开销32G 盘上调高前务必在 UI 或 `kubectl` 中确认各节点剩余空间。
- 迁移卷或临时演练容灾时,可对单个卷调高副本数,待同步完成再调回。
### 只让“有大盘”的节点承载数据
若 4 节点里只有部分机器有 `/storage` 或大盘:
- 在 Longhorn UI 里把无盘或不想参与存储的节点的 disk 设为**不可调度**。
- 或给存储节点打标签,配合工作负载的 nodeSelector/affinity让应用尽量靠近数据
> 注意:副本=1 时,卷不会“随使用自动从小盘迁到大盘”,需要你手动迁移或从源头限制调度。
---
## GitLab 这类重状态系统如何落地
原则:**所有关键组件都用 PVC**Longhorn
- **必须 PVC**PostgreSQL、Redis、Gitalyrepo、uploads/artifacts/packages、registry如启用
- **备份**
- 应用层GitLab 自带 backup+ 存储层Longhorn snapshot/backup双保险
---
## Traefik `acme.json` 如何持久化/备份(可选)
Traefik 的 ACME 状态很小,但也建议持久化以避免重建后触发频繁签发。
- **推荐**:给 Traefik 的 `/data` 使用 PVCLonghorn`acme.json` 走标准持久化
- **兜底**:定期导出 `acme.json` 备份(例如 `kubectl cp pod/<traefik-pod>:/data/acme.json ...`
---
## 验证
```bash
kubectl -n longhorn-system get pod
kubectl get pvc -A
kubectl get pv
```
### 手动验证(按顺序,便于排障)
在 **K3s 节点**上(与 kubelet 使用同一套 containerd可先手动拉镜像区分「网络/仓库问题」与「Longhorn 配置问题」:
**镜像与节点**K3s 每台节点自带 containerd**镜像按节点本地缓存**不会在节点间自动同步。Pod 第一次调度到某节点时,该节点会自己去仓库拉取(联网正常则不必事先每台手动 `ctr pull`。Longhorn 的 DaemonSet 在 **4 节点**上各跑一份时,**每台**都可能要拉同一批镜像;某台若 `ImagePullBackOff`,到**该台**上执行下面的 `ctr pull` 做预热或排障。
```bash
# 使用 k3s 的 containerd 命名空间
CTR="sudo ctr --address /run/k3s/containerd/containerd.sock -n k8s.io"
$CTR images pull docker.io/longhornio/longhorn-manager:v1.7.2
$CTR images pull docker.io/longhornio/longhorn-ui:v1.7.2
$CTR images pull docker.io/longhornio/longhorn-share-manager:v1.7.2
$CTR images pull docker.io/longhornio/longhorn-engine:v1.7.2
$CTR images pull docker.io/longhornio/longhorn-instance-manager:v1.7.2
$CTR images pull docker.io/longhornio/backing-image-manager:v1.7.2
# 其余 longhornio/* 镜像以你安装的版本清单为准(避免 tag 与文档漂移):
# curl -sSL https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml | grep -E 'image:.*longhornio' | sort -u
# 对照:非 Longhorn 镜像(判断是否为 Docker Hub 整体不通)
$CTR images pull docker.io/library/nginx:alpine
```
确认控制面与 DaemonSet`longhorn-manager` 每节点一份;**4 节点**时应看到与节点数相关的 Pod 分布,`engine-image` 等会陆续就绪):
```bash
kubectl -n longhorn-system get pod,deploy,ds -o wide
kubectl get nodes -o wide
kubectl -n longhorn-system rollout status deploy/longhorn-ui --timeout=300s
kubectl -n longhorn-system rollout status deploy/longhorn-driver-deployer --timeout=300s
```
确认默认数据路径与 StorageClass
```bash
kubectl -n longhorn-system get settings.longhorn.io default-data-path -o yaml
kubectl get storageclass
```
`longhorn``local-path` 同时带有 `storageclass.kubernetes.io/is-default-class: "true"`,未写 `storageClassName` 的 PVC 行为可能不符合预期;建议只保留一个默认类,或业务 PVC 显式写 `storageClassName: longhorn`
**最小读写验证**(动态卷 + 临时 Pod
```bash
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: longhorn-pvc-smoke
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:
name: longhorn-smoke
namespace: default
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "echo ok-longhorn > /data/test.txt && sleep 3600"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: longhorn-pvc-smoke
EOF
kubectl wait --for=condition=Ready pod/longhorn-smoke -n default --timeout=180s
kubectl exec -n default longhorn-smoke -- cat /data/test.txt
```
清理冒烟资源:
```bash
kubectl delete pod longhorn-smoke -n default --ignore-not-found
kubectl delete pvc longhorn-pvc-smoke -n default --ignore-not-found
```
Longhorn UI 的部署核对、port-forward、NodePort 与界面内验证要点见上文 **「Longhorn UI部署与访问」**。
---
## 下一步
- `03-05-k3s-local-path-pvc.md`:单副本、无快照需求时,用 K3s 自带 local-path 即可
- 返回后续 GitOps / 业务部署(如 GitLab章节
## 排障
- **先看 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`