【K8s 存储】Longhorn v1.12.1 离线安装全流程:外网制作离线包 + 内网部署(附踩坑实录)

【K8s 存储】Longhorn v1.12.1 离线安装全流程:外网制作离线包 + 内网部署(附踩坑实录)

写作时间:2026-10。适用于 x86_64 + Kubernetes ≥ 1.25 的内网(air-gapped)环境。

文中所有命令均为实际执行过的,踩坑部分附原因分析和解决办法。

一、背景

生产内网环境(无法访问互联网)需要部署 Longhorn 做 K8s 分布式块存储。Longhorn 官方文档对离线安装的描述比较简略,实际操作中会遇到一连串问题:

  1. Longhorn 由 14 个容器镜像 + 一堆部署清单 组成,不像普通单二进制软件那样"下载一个包就完事";
  2. 外网下载机上 Docker Hub 直连超时 ,配置的阿里云加速器对 longhornio/* 镜像直接返回 not found;
  3. raw.githubusercontent.com、hub.docker.com 等 GitHub/Docker 域名部分被墙;
  4. longhornctl 官方 CLI 的仓库从 longhorn/longhornctl 迁移到了 longhorn/cli,按旧文档操作全是 404,Release 下载还被 CDN 限速到 26KB/s。

这篇文章记录完整解决过程,最后给出一份可以直接抄的离线包目录结构和内网部署步骤。

二、环境说明

角色 系统 说明
外网下载机 Rocky Linux 9.6 (x86_64) 只用来下载文件,不装 K8s
内网集群节点 Oracle Linux 9.6 (x86_64) Kubernetes ≥ 1.25(Longhorn 1.12 硬性要求)
目标版本 Longhorn v1.12.1 发布于 2026-08,上一代线的最新补丁版

版本选择建议:发文时最新版是 v1.13.0(刚发布 3 天)。内网环境升级麻烦,建议选上一代线的最新补丁版 ,而不是最新的 .0 版本。

系统 RPM 依赖(iscsi-initiator-utils、nfs-utils)已提前备好,本文不再赘述下载过程。

三、先想清楚:离线包里到底要装什么

对照官方文档梳理,一个完整的 Longhorn 离线安装包 = 5 类文件:

  1. 容器镜像 × 14(核心,共约 1.5G):longhorn-manager / engine / instance-manager / ui / share-manager / backing-image-manager / cli + 6 个 CSI sidecar + support-bundle-kit;
  2. 部署清单 :longhorn.yaml(kubectl 直装用)、longhorn-iscsi-selinux-workaround.yaml(RHEL/CentOS/OL 系 SELinux Enforcing 必需 ,漏了这个 Pod 起不来)、longhorn-cifs-installation.yaml(仅 CIFS 备份需要);
  3. Helm Chart :longhorn-1.12.1.tgz(打算用 helm 安装时);
  4. 工具二进制:helm、longhornctl(环境预检);
  5. 校验文件 + 导入脚本 :SHA256SUMS、docker load 脚本。

最终目录结构(总共 1.7G):

复制代码
software/
├── README-离线安装说明.md        # 安装说明
├── SHA256SUMS                   # 全部文件校验和
├── load-images-offline.sh       # 一键导入镜像脚本(docker/nerdctl/ctr 自动识别)
├── images/                      # 14 个镜像 tar + 官方镜像清单 + digest 记录
├── manifests/
│   ├── longhorn.yaml
│   ├── longhorn-iscsi-selinux-workaround.yaml
│   └── longhorn-cifs-installation.yaml
├── chart/
│   └── longhorn-1.12.1.tgz
└── tools/
    ├── helm               # v4.3.0
    ├── helm3              # v3.22.0(旧集群备用)
    ├── longhornctl        # v1.12.1(集群环境检查)
    └── longhornctl-local  # v1.12.1(单机检查模式)

四、外网侧:制作离线包

4.1 确定版本、获取官方镜像清单

Longhorn 每个版本的镜像列表官方是给的,不用自己猜:

bash 复制代码
# 查最新稳定版(发文时为 v1.13.0,我选了更成熟的 v1.12.1)
curl -s https://api.github.com/repos/longhorn/longhorn/releases/latest | jq -r '.tag_name'

镜像清单在仓库的 deploy/longhorn-images.txt。踩坑 1:直接 raw.githubusercontent.com 下载报 Connection reset:

bash 复制代码
curl -fsSL -o longhorn-images.txt \
  https://raw.githubusercontent.com/longhorn/longhorn/v1.12.1/deploy/longhorn-images.txt
# curl: (35) OpenSSL SSL_connect: Connection reset by peer

解决:改走 GitHub REST API 取文件内容(base64 解码) ,api.github.com 是通的:

bash 复制代码
curl -fsSL 'https://api.github.com/repos/longhorn/longhorn/contents/deploy/longhorn-images.txt?ref=v1.12.1' \
  | jq -r '.content' | base64 -d > longhorn-images.txt

内容如下,共 14 个镜像:

复制代码
longhornio/backing-image-manager:v1.12.1
longhornio/longhorn-engine:v1.12.1
longhornio/longhorn-instance-manager:v1.12.1
longhornio/longhorn-manager:v1.12.1
longhornio/longhorn-share-manager:v1.12.1
longhornio/longhorn-ui:v1.12.1
longhornio/longhorn-cli:v1.12.1
longhornio/csi-attacher:v4.12.0
longhornio/csi-provisioner:v5.3.0
longhornio/csi-resizer:v2.2.1
longhornio/csi-snapshotter:v8.6.0
longhornio/csi-node-driver-registrar:v2.17.0
longhornio/livenessprobe:v2.19.0
longhornio/support-bundle-kit:v0.0.92

小技巧:同时下载官方 Release 附件里的 longhorn-images.txt 和自己做 diff,确认一字不差。

4.2 踩坑 2:Docker Hub 拉不动 + 加速器"半残"

先探测网络:

bash 复制代码
curl -s -o /dev/null -w '%{http_code}' https://registry-1.docker.io/v2/
# 000 ------ Docker Hub 直连超时
docker info | grep -A2 'Registry Mirrors'
# 只有阿里云个人加速器

docker pull hello-world 成功,但拉 Longhorn 镜像直接报错:

复制代码
Error response from daemon: failed to resolve reference
"docker.io/longhornio/backing-image-manager:v1.12.1": not found

原因 :阿里云个人加速器对未缓存的长尾镜像不能有效回源,longhornio/* 这类非热门仓库直接返回 not found(拉 hello-world 这种热门镜像正常,所以一开始被假象骗了)。

解决:批量探测可用的公共镜像代理,实测选一个 。探测时 /v2/ 返回 401/200 都说明服务活着(401 是 registry 标准认证应答):

bash 复制代码
for m in docker.m.daocloud.io docker.1ms.run dockerproxy.net docker.gh-proxy.com \
         hub.rat.dev dockerpull.org docker.xuanyuan.me; do
  code=$(curl -s -o /dev/null -w '%{http_code}' -m 8 "https://$m/v2/")
  echo "$m -> ${code:-timeout}"
done

再用一个小镜像(csi-node-driver-registrar 只有 20M)实测真正能拉:

bash 复制代码
docker pull docker.m.daocloud.io/longhornio/csi-node-driver-registrar:v2.17.0   # 成功
docker pull dockerproxy.net/longhornio/csi-node-driver-registrar:v2.17.0        # 成功

选定 docker.m.daocloud.io 为主通道、dockerproxy.net 备用。

注意:公共代理可用性随时间变化,使用前务必实测;公司有内网仓库(如 Harbor + 同步任务)的话优先走内网仓库。

4.3 批量拉取 + 导出脚本(含 2 个关键细节)

bash 复制代码
#!/usr/bin/env bash
# pull-images.sh:拉取全部镜像(linux/amd64)并逐个导出为 tar
set -euo pipefail
MIRROR="${MIRROR:-docker.m.daocloud.io}"
FALLBACK="dockerproxy.net"
LIST=longhorn-images.txt

while read -r img; do
  [ -z "$img" ] && continue
  name=${img//\//_}; name=${name//:/-}
  [ -s "images/${name}.tar" ] && { echo "SKIP $img"; continue; }

  echo ">>> pulling $MIRROR/$img"
  if docker pull --platform linux/amd64 "$MIRROR/$img"; then
    docker tag "$MIRROR/$img" "$img"          # 关键细节①:tag 回原始名
  else
    echo "!!! trying $FALLBACK/$img"
    docker pull --platform linux/amd64 "$FALLBACK/$img"
    docker tag "$FALLBACK/$img" "$img"
  fi
  docker save -o "images/${name}.tar" "$img"
  digest=$(docker inspect --format '{{index .RepoDigests 0}}' "$img")
  echo "sha256:${digest##*@}  ${name}.tar" >> images/image-digests.txt
done < "$LIST"
echo ALL_IMAGES_DONE

两个容易翻车的细节:

  • 细节① docker tag 回原始名 :通过代理拉下来的镜像名是 docker.m.daocloud.io/longhornio/xxx,而 longhorn.yaml 里引用的是 longhornio/xxx。不 tag 回去,内网 docker load 之后镜像名对不上,照样 ImagePullBackOff。
  • 细节② 别用管道 tee 看日志 :./pull-images.sh | tee pull.log 会把脚本真实退出码吞掉(管道返回的是 tee 的退出码),失败也显示 exit 0。正确写法是重定向:./pull-images.sh > pull.log 2>&1。

拉完后逐个验证 tar 内部的 RepoTags(这一步能同时验证 tar 没损坏、tag 是原始名):

bash 复制代码
for f in images/*.tar; do
  printf '%-55s %s\n' "$f" "$(tar -xOf "$f" manifest.json | jq -r '.[].RepoTags[]')"
done

4.4 下载部署清单和 Chart

longhorn.yaml 有 200 多 KB,直接从 Release 附件拿最省事(github.com 域名是通的,release 下载会 302 到 CDN):

bash 复制代码
curl -fsSL -o longhorn.yaml \
  https://github.com/longhorn/longhorn/releases/download/v1.12.1/longhorn.yaml

SELinux workaround 和 CIFS 清单在 deploy/prerequisite/ 目录(注意:v1.12 已经没有 旧文档里的 prerequisite.yaml 了,被 longhornctl 取代):

bash 复制代码
for f in longhorn-iscsi-selinux-workaround.yaml longhorn-cifs-installation.yaml; do
  curl -fsSL "https://api.github.com/repos/longhorn/longhorn/contents/deploy/prerequisite/$f?ref=v1.12.1" \
    | jq -r '.content' | base64 -d > "$f"
done

Helm Chart(chart 仓库域名和 github release 附件都可以):

bash 复制代码
curl -fsSL -o longhorn-1.12.1.tgz \
  https://github.com/longhorn/charts/releases/download/longhorn-1.12.1/longhorn-1.12.1.tgz
tar -tzf longhorn-1.12.1.tgz | head    # 验证包完整,确认有 templates/crds.yaml

强烈建议做一次交叉比对 :把 longhorn.yaml 里引用的所有 image: 抽出来,和 longhorn-images.txt 比,确保没有漏下载的镜像:

bash 复制代码
grep -oE 'longhornio/[a-z0-9-]+:v[0-9.]+' longhorn.yaml | sort -u > /tmp/a
sort longhorn-images.txt > /tmp/b
comm -23 /tmp/a /tmp/b   # 输出为空 = yaml 引用的镜像全部在下载清单内

helm 二进制从官方源 get.helm.sh 下载(国内可达、速度快),顺手把 v3 和 v4 都备上:

bash 复制代码
curl -fsSL -o helm.tgz https://get.helm.sh/helm-v4.3.0-linux-amd64.tar.gz
curl -fsSL -o helm3.tgz https://get.helm.sh/helm-v3.22.0-linux-amd64.tar.gz

4.5 踩坑 3:longhornctl 仓库迁移 + CDN 限速

官方 CLI 工具 longhornctl 用于部署前环境预检,按旧文档去 longhorn/longhornctl 仓库下载------404,仓库已迁移到 longhorn/cli:

bash 复制代码
curl -s https://api.github.com/repos/longhorn/longhornctl | jq -r .message
# "Not Found"

# 新地址(从官方文档确认):
curl -fsSL -o longhornctl \
  https://github.com/longhorn/cli/releases/download/v1.12.1/longhornctl-linux-amd64

但这个 45MB 的文件被 release CDN 限速到 ~26KB/s,断点续传跑了两次都要 25 分钟以上。

解决:直接从同版本的 longhorn-cli 容器镜像里抽取二进制 (我们已经把这个镜像下载下来了,里面有 usr/local/bin/longhornctl 和 longhornctl-local,版本完全一致,秒取):

bash 复制代码
# docker create 只创建不运行,再用 docker cp 拷出文件,零执行风险
docker create --name t longhornio/longhorn-cli:v1.12.1
docker cp t:/usr/local/bin/longhornctl      ./tools/longhornctl
docker cp t:/usr/local/bin/longhornctl-local ./tools/longhornctl-local
docker rm t

./tools/longhornctl version    # 输出 v1.12.1,可用

4.6 生成校验和

离线包最后一个文件:SHA256SUMS。内网拿到文件后先校验,避免拷贝过程中损坏:

bash 复制代码
find . -type f ! -name 'SHA256SUMS' -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS
# 内网侧:sha256sum -c SHA256SUMS

五、内网侧:离线部署(Oracle Linux 9)

5.1 节点准备(每个存储节点)

bash 复制代码
# RPM 离线安装(--setopt=tsflags=noscripts 是官方对 RHEL 系的推荐参数)
dnf install -y --setopt=tsflags=noscripts ./iscsi-initiator-utils-*.rpm ./nfs-utils-*.rpm

# RHEL 系必须设置 iSCSI initiator 名称(官方文档要求,漏了 iscsi 会异常)
echo "InitiatorName=$(iscsi-iname)" > /etc/iscsi/initiatorname.iscsi
systemctl enable --now iscsid

# 官方还要求这两个包,OL9 一般自带,验证一下,缺了从内网仓库补
rpm -q cryptsetup device-mapper || dnf install -y cryptsetup device-mapper

5.2 环境预检

bash 复制代码
# 先在任一节点导入 longhorn-cli 镜像(预检会在集群里跑 checker Pod)
./load-images-offline.sh

# 在能访问 kube-apiserver 的机器上执行:
./tools/longhornctl check preflight
# V2 数据引擎(SPDK)加 --enable-spdk

正常输出应该看到每个节点:

复制代码
worker1:
  info:
  - Service iscsid is running
  - NFS4 is supported
  - Package nfs-utils is installed
  - Package iscsi-initiator-utils is installed

5.3 导入镜像

一键脚本(自动识别 docker / nerdctl / ctr,containerd 集群导入 k8s.io namespace):

bash 复制代码
#!/usr/bin/env bash
# load-images-offline.sh ------ 在每个节点执行
set -euo pipefail
cd "$(dirname "$0")"

if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
  cli="docker"
elif command -v nerdctl >/dev/null 2>&1; then
  cli="nerdctl"
elif command -v ctr >/dev/null 2>&1; then
  cli="ctr"
else
  echo "未找到可用的容器运行时 (docker/nerdctl/ctr)"; exit 1
fi
echo "== 使用 $cli 导入镜像 =="

for f in images/*.tar; do
  echo ">>> $f"
  case "$cli" in
    docker)  docker load -i "$f" ;;
    nerdctl) nerdctl -n k8s.io load -i "$f" ;;
    ctr)     ctr -n k8s.io images import "$f" ;;
  esac
done

如果内网有私有仓库(Harbor 等),更优雅的方式是:load 之后统一 docker tag + push 到私有仓库,安装时指定:

helm install longhorn chart/longhorn-1.12.1.tgz -n longhorn-system --create-namespace \ --set global.cattle.systemDefaultRegistry=registry.内网域名:5000 \ --set defaultSettings.systemDefaultRegistry=registry.内网域名:5000

5.4 SELinux(OL9 Enforcing 模式必做)

bash 复制代码
getenforce    # Enforcing 就必须 apply 下面这个;Permissive/Disabled 可跳过
kubectl apply -f manifests/longhorn-iscsi-selinux-workaround.yaml

5.5 安装(二选一)

bash 复制代码
# 方式 A:kubectl(最简单)
kubectl apply -f manifests/longhorn.yaml

# 方式 B:helm(需要自定义参数时)
cp tools/helm3 /usr/local/bin/helm && chmod +x /usr/local/bin/helm
helm install longhorn chart/longhorn-1.12.1.tgz \
  --namespace longhorn-system --create-namespace

5.6 验证

bash 复制代码
kubectl -n longhorn-system get pods -o wide   # 全部 Running
kubectl -n longhorn-system get ds             # longhorn-manager / CSI 各节点就绪
# 建一个 ReadWriteOnce 的测试 PVC,能 Bound 并被 Pod 挂载即成功

六、踩坑总结(速查表)

# 现象 原因 解决
1 raw.githubusercontent.com Connection reset 域名被墙 改用 api.github.com 的 contents API + base64 解码
2 阿里云加速器拉 longhornio/* 报 not found 个人加速器对未缓存长尾镜像不回源 批量探测公共代理,实测选定 daocloud(附 fallback)
3 脚本失败但 exit 0 ` tee` 吞掉退出码
4 内网 load 后仍 ImagePullBackOff 经代理拉取的镜像名带了代理前缀 docker tag 回原始名再 docker save
5 longhorn/longhornctl 404 仓库迁移 新地址 longhorn/cli;或直接从 longhorn-cli 镜像抽二进制
6 longhornctl 下载 26KB/s release CDN 限速 docker create + docker cp 从镜像抽取(同版本)
7 OL9 上 Pod 起不来/iscsi 权限错 SELinux Enforcing apply longhorn-iscsi-selinux-workaround.yaml
8 旧文档的 prerequisite.yaml 404 v1.12 已移除 环境检查改用 longhornctl

七、几点建议

  1. 离线包做好版本固化:镜像、yaml、chart、longhornctl 全部使用同一版本号,别混搭;
  2. 别信"加速器能拉热门镜像 = 加速器可用",一定要用目标仓库的镜像实测;
  3. --platform linux/amd64 显式指定,避免多架构清单在 save 时把其他架构层也带进去;
  4. 交付前做三个校验:SHA256、tar 内 RepoTags、yaml 引用镜像与清单交叉比对------这三步能在内网开工前拦住 90% 的问题。

参考资料

  • Longhorn 官方安装要求(longhorn.io/docs → Deploy and Upgrade → Installation Requirements)
  • Longhorn Air Gap Installation 官方指引
  • longhornctl 使用文档(仓库:github.com/longhorn/cli)

如果对你有帮助,欢迎点赞收藏;评论区可以交流你们内网离线化其他 K8s 组件的姿势。

相关推荐
星恒随风43 分钟前
Linux开发工具详解(一):软件包管理、Vim、GCC/G++、Makefile与进度条实战
linux·运维·笔记·学习·vim
小小、码农1 小时前
Ubuntu / Linux 软件安装完整笔记
linux·笔记·ubuntu
yunwei371 小时前
eBPF 开发实践:使用 sockops 加速网络请求转发
linux·后端·性能优化
rest10241 小时前
做io测试
linux·服务器·网络
Timmy1 小时前
前端转全栈笔记:讲框架之前,先把 TypeScript 这关过了
前端·人工智能·node.js
一条破秋裤1 小时前
Linux 网络编程基础:网络分类、分层模型与数据封装
linux·运维·网络
FACELESS VOID1 小时前
wsl下使用npm,错误识别到了windows下的npm
linux·windows·npm
H.莓飛2 小时前
【数据结构】栈
linux·开发语言·数据结构·算法·centos
LRL_2 小时前
【云原生】Oracle Linux 9.6 离线(Air-Gapped)环境下安装 Longhorn 及其底层依赖(iSCSI/NFS)完全指南
linux·云原生·oracle