痛点:气隙环境部署 K8s 应用有多痛?
在金融、军工、政务、医疗等行业,生产环境往往处于完全断网的"气隙"(Air-Gapped)状态——没有外网访问,无法 docker pull,Helm chart 拉不下来,甚至 apt update 都跑不通。
传统做法是手动搬运镜像 tar 包、导出 Chart、逐一 docker load,再用 U 盘或内网传输。流程繁琐且极易出错:
- 镜像依赖层层嵌套,漏一个就部署失败
- Helm values 中硬编码的镜像地址需要逐个改写
- 多版本升级时,没有可靠的差量更新机制
- 缺乏签名验证,供应链安全无从保障
Zarf 正是为解决这类问题而生的开源工具。它由 Defense Unicorns 团队开发,现已进入 CNCF Sandbox,专门面向气隙/离线/边缘场景的 Kubernetes 声明式部署。
方案:Zarf 是什么、怎么解决问题
Zarf 的核心思路很简单:在联网环境打包所有依赖为一个不可变的 tarball(Zarf Package),搬到离线环境一键部署。
关键特性:
| 特性 | 说明 |
|---|---|
| 声明式打包 | 一个 zarf.yaml 定义所有组件:镜像、Helm chart、文件、脚本 |
| 内置镜像仓库 | 部署时自动启动内置 Registry(基于 Zot),无需预装 Harbor |
| 内置 Git Server | 可选嵌入 Gitea,支持 GitOps 流程 |
| SBOM 生成 | 自动产出 Software Bill of Materials |
| Cosign 签名 | 支持包签名与验证,保障供应链安全 |
| 差量更新 | 支持 zarf package diff 实现增量包 |
| 跨架构 | 支持 amd64/arm64 多架构镜像打包 |
工作流:
[联网环境] zarf package create → my-app.tar.zst
↓ (U盘/光盘/单向传输)
[离线环境] zarf package deploy my-app.tar.zst → 部署完成
实操步骤
Step 1:安装 Zarf CLI
在联网的构建机上安装:
# Linux amd64
curl -sL https://github.com/zarf-dev/zarf/releases/latest/download/zarf_linux_amd64 -o /usr/local/bin/zarf
chmod +x /usr/local/bin/zarf
zarf version
Step 2:编写 zarf.yaml 定义包
以部署一个 Nginx + Redis 组合为例:
kind: ZarfPackageConfig
metadata:
name: my-app-stack
version: 1.0.0
description: "Nginx + Redis for air-gapped deployment"
architecture: amd64
components:
- name: nginx-server
required: true
charts:
- name: nginx
namespace: my-app
url: https://charts.bitnami.com/bitnami
version: 18.1.11
valuesFiles:
- values/nginx-values.yaml
images:
- docker.io/bitnami/nginx:1.27.3-debian-12-r0
- name: redis-cache
required: true
charts:
- name: redis
namespace: my-app
url: https://charts.bitnami.com/bitnami
version: 20.3.0
valuesFiles:
- values/redis-values.yaml
images:
- docker.io/bitnami/redis:7.4.1-debian-12-r0
- docker.io/bitnami/redis-sentinel:7.4.1-debian-12-r0
Step 3:联网环境打包
# 在 zarf.yaml 所在目录执行
zarf package create . --confirm
# 输出: zarf-package-my-app-stack-amd64-1.0.0.tar.zst (约 200MB)
打包过程会自动拉取所有声明的镜像和 Helm chart,压缩为单一文件。可以用 --max-package-size 拆分为多个分片,方便光盘刻录。
Step 4:离线环境部署
将 tar.zst 文件搬运到离线 K8s 集群的管理节点:
# 初始化 Zarf(首次使用,会部署内置 Registry + Agent)
zarf init --confirm
# 部署应用包
zarf package deploy zarf-package-my-app-stack-amd64-1.0.0.tar.zst --confirm
# 验证
kubectl get pods -n my-app
zarf init 会在集群中部署:
- Zarf Registry(基于 Zot):存储所有推送的容器镜像
- Zarf Agent(MutatingWebhook):自动改写 Pod 中的镜像地址指向内置 Registry
这意味着 Helm chart 中写的 docker.io/bitnami/nginx:xxx 会被自动重写为内部 Registry 地址,无需手动修改任何 values 文件。
避坑指南
1. init 包也需要离线搬运
zarf init 本身需要一个 init 包(包含 Registry、Agent 等组件镜像)。第一次使用时需在联网环境执行 zarf tools download-init 下载 init 包,一并搬到离线环境:
# 联网环境
zarf tools download-init --architecture amd64
# 产出: zarf-init-amd64-vX.Y.Z.tar.zst
# 离线环境
zarf init --confirm # 自动检测同目录下的 init 包
2. 多架构镜像要显式声明
如果目标集群有 arm64 节点,需要在 zarf.yaml 中声明 architecture: multi 或分别打包:
zarf package create . --architecture arm64 --confirm
漏打架构会导致 Pod ImagePullBackOff(虽然镜像在 Registry 里,但 manifest 不匹配)。
3. 注意包大小与传输方式
生产级应用包可能达到数 GB。建议:
- 使用
--max-package-size 2048(单位 MB)拆分为 DVD 大小 - 搬运后用
zarf package inspect验证完整性 - 启用 Cosign 签名:
zarf package create . --signing-key cosign.key
对比:Zarf vs 手动搬运 vs Hauler
| 维度 | 手动搬运 | Hauler | Zarf |
|---|---|---|---|
| 学习成本 | 低 | 中 | 中 |
| 自动化程度 | 无 | 部分(仅镜像+文件收集) | 完整(镜像+Chart+部署+改写) |
| 内置 Registry | ❌ 需自建 | ❌ 需自建 | ✅ 内置 Zot |
| 镜像地址自动改写 | ❌ | ❌ | ✅ Webhook 自动处理 |
| 供应链安全 | ❌ | 部分 | ✅ SBOM + Cosign |
| GitOps 支持 | ❌ | ❌ | ✅ 内置 Gitea |
| 适用规模 | 小型 | 中型 | 中大型 |
总结
Zarf 解决了气隙环境 K8s 部署的核心痛点:依赖收集、传输打包、镜像改写、供应链验证一站式搞定。
核心建议:
- CI 集成:在 CI 流水线中加入
zarf package create,每次发版自动产出离线包 - 签名必开:生产环境务必启用 Cosign 签名,防止包被篡改
- 版本管理:利用
zarf package diff实现增量更新,减少搬运量 - 先在联网环境测试:Zarf 同样可以部署到联网集群,先验证再搬运
如果你的业务涉及政务云、金融专网、边缘计算或任何网络受限场景,Zarf 值得纳入工具链。比起手动搬镜像的"刀耕火种",声明式离线部署才是正途。