饮墨

子安饮墨馀三斗,留与卿儿作赋来

Zarf:离线/气隙环境下 Kubernetes 部署的终极方案

痛点:气隙环境部署 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 部署的核心痛点:依赖收集、传输打包、镜像改写、供应链验证一站式搞定。

核心建议:

  1. CI 集成:在 CI 流水线中加入 zarf package create,每次发版自动产出离线包
  2. 签名必开:生产环境务必启用 Cosign 签名,防止包被篡改
  3. 版本管理:利用 zarf package diff 实现增量更新,减少搬运量
  4. 先在联网环境测试:Zarf 同样可以部署到联网集群,先验证再搬运

如果你的业务涉及政务云、金融专网、边缘计算或任何网络受限场景,Zarf 值得纳入工具链。比起手动搬镜像的"刀耕火种",声明式离线部署才是正途。

您还没有登录,请登录后发表评论。