news 2026/5/12 5:09:33

Zarf:专为离线环境设计的Kubernetes应用打包与部署工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zarf:专为离线环境设计的Kubernetes应用打包与部署工具

1. 项目概述:Zarf是什么,以及它为何重要

如果你在运维一个Kubernetes集群,尤其是在一个网络受限、甚至完全离线的环境里,比如某些政府机构、金融机构的内部数据中心,或者部署在远洋船舶、偏远地区的边缘设备上,那么“如何把一套复杂的云原生应用完整地交付过去”绝对是个让人头疼的问题。传统的CI/CD流水线严重依赖互联网,从拉取容器镜像到下载Helm Chart,每一步都可能因为网络不通而卡住。Zarf的出现,就是为了彻底解决这个痛点。

简单来说,Zarf是一个专为“空气间隙”环境设计的Kubernetes应用打包和部署工具。你可以把它想象成一个功能超级强大的“离线安装包制作器”。它允许开发团队在联网的开发环境中,将应用所需的一切——包括Docker镜像、Helm Chart、配置文件、甚至Git仓库和容器镜像仓库本身——打包成一个单一的、可压缩的.tar.zst文件。然后,你只需要把这个文件拷贝到目标离线环境,运行几条Zarf命令,就能完成整个应用的部署,完全不需要外部网络。

我第一次接触Zarf是在一个军工背景的客户项目里,他们的测试环境是完全物理隔离的。以往部署一个微服务应用,运维团队需要手动导出几十个G的镜像,再写一堆复杂的脚本去导入和部署,过程繁琐且极易出错。引入Zarf后,我们将整个交付物从“一堆脚本和散落的文件”变成了一个“原子化的包”,部署过程从几个小时缩短到几分钟,而且实现了完全的可重复性。这种体验上的提升是颠覆性的。

2. Zarf的核心设计理念与优势解析

2.1 “空气间隙优先”的设计哲学

Zarf的核心设计哲学是“Airgap Native”,即原生支持离线。这与许多后来才添加离线支持的工具截然不同。它的整个架构都围绕着“假设目标环境没有任何外部连接”这一前提来构建。这意味着:

  1. 内置基础设施:Zarf包内可以包含运行应用所必需的基础设施组件,比如一个轻量级的K3s集群发行版、一个内嵌的Gitea Git服务器,以及一个Docker镜像仓库。在部署时,Zarf会优先在目标集群中拉起这些基础设施服务,后续的应用部署都将依赖这些“内置服务”,从而形成一个自包含的闭环。
  2. 依赖预拉取与重写:在打包阶段,Zarf会递归分析你的Kubernetes清单(如Helm Chart、Kustomize配置),找出所有引用的容器镜像、Git仓库地址。它会自动从互联网拉取这些资源,并将其元数据(如图像路径)重写为指向即将部署的内置仓库。这个过程彻底消除了部署时对外部镜像仓库(如Docker Hub、gcr.io)的依赖。
  3. 单一文件分发:最终产物是一个文件。这极大简化了物流链条,无论是通过物理媒介(硬盘、U盘)传递,还是在安全网络中进行文件传输,都只需要处理一个对象,降低了传输错误和版本管理的复杂度。

2.2 声明式打包与部署

Zarf采用声明式的配置方式,通过一个名为zarf.yaml的配置文件来定义整个包。这个文件描述了“最终状态应该是什么样”,而不是“如何一步步达到那个状态”。这种方式的优势在于:

  • 幂等性:无论执行多少次,只要zarf.yaml不变,部署出的环境就是一致的。这完美契合了GitOps的理念。
  • 版本控制友好zarf.yaml是一个纯文本文件,可以放入Git仓库进行版本管理。包的迭代、回滚都变得清晰可控。
  • 可复用与可组合:复杂的系统可以被拆分成多个Zarf包(组件),通过导入机制组合在一起。例如,你可以有一个“基础平台”包(包含监控日志组件),另一个“业务应用A”包。业务应用包可以声明依赖基础平台包,Zarf会确保部署顺序和依赖关系。

2.3 关键优势深度解读

结合官方介绍和我自己的使用经验,Zarf的以下几个优势在实际场景中价值巨大:

  • 零依赖的单一二进制CLI:Zarf CLI是一个静态编译的Go二进制文件,没有任何运行时依赖。你可以在任何Linux、macOS甚至Windows机器上直接运行它。这在目标环境系统版本老旧或权限受限时是个巨大优点,你不需要为了安装一个工具而去解决一堆依赖库的问题。
  • 无供应商锁定:这是很多团队关心的。Zarf本身是开源工具,它生成的包本质上是一个标准压缩包,里面包含的是原生的Kubernetes YAML、Helm Chart和容器镜像。即使有一天你决定不再使用Zarf,你仍然可以手动解压这个包,用kubectl或helm命令部署里面的内容。它没有引入任何专有的运行时或控制平面。
  • 连接开发,断开部署:开发团队可以在拥有高速互联网的环境中,使用熟悉的工具链(如Docker、Helm、CI/CD)进行开发和测试。只需在CI流水线的最后阶段引入zarf package create命令,就能生成离线包。运维团队则完全在另一个网络维度进行工作,两者互不干扰,流程顺畅。

实操心得:不要试图在离线环境“构建”包。打包(create)一定是在联网环境完成的,这是一个“收拢依赖”的过程。离线环境只做部署(deploy),这是一个“释放依赖”的过程。明确这个边界能让团队协作更清晰。

3. Zarf的核心功能与组件拆解

3.1 包结构与zarf.yaml详解

一个Zarf包(.tar.zst文件)解压后,其内部结构是精心设计的。但作为用户,我们主要与之交互的是zarf.yaml配置文件。理解它是用好Zarf的关键。

一个典型的zarf.yaml包含以下核心部分:

kind: ZarfPackageConfig metadata: name: "my-awesome-app" description: "A package for deploying our awesome app offline" version: "1.0.0" # 定义在部署时可被注入或提示用户输入的变量 variables: - name: APP_HOSTNAME default: "myapp.local" prompt: true # 部署时会提示用户输入 description: "The hostname for the application ingress" # 包由多个组件构成,组件按顺序部署 components: - name: "infrastructure" required: true # 此组件将部署一个内嵌的Gitea服务器 charts: - name: gitea namespace: zarf url: https://dl.gitea.io/charts/ version: 8.0.0 images: - "gitea/gitea:1.20-rootless" - name: "my-app" required: true dependsOn: - infrastructure # 声明依赖,确保先部署infrastructure组件 # 导入其他文件,如Kubernetes清单 manifests: - name: app-deployment files: - "./k8s/manifests/deployment.yaml" - "./k8s/manifests/service.yaml" # 使用之前定义的变量 actions: onDeploy: # 在部署时,将变量注入到Manifest中 - cmd: | kubectl patch svc my-app -n zarf -p '{"spec":{"type":"NodePort"}}'

关键字段解析

  • variables:实现了部署时的灵活配置。比如,为不同环境(开发、测试、生产)设置不同的镜像Tag或资源限制。prompt: true的变量会在zarf package deploy时交互式地询问用户,非常适合需要现场决策的配置。
  • components:组件是部署的原子单元。通过dependsOn可以构建部署依赖图。Zarf会智能地解析依赖,按正确顺序部署组件。组件也可以设置为required: false,成为可选的插件式组件。
  • actions:这是Zarf的“魔法”所在。它允许你在组件生命周期的不同阶段(onDeploy,onRemove等)执行自定义命令或脚本。例如,在部署数据库组件后,自动运行初始化SQL脚本;或者在移除组件前,优雅地备份数据。这弥补了纯声明式配置在流程控制上的不足。

3.2 内置服务与“自举”能力

Zarf最令人称道的功能之一是它的“自举”能力。它内置了几个关键服务,使得在裸机上启动一个完整的、离线的K8s应用平台成为可能。

  1. K3s:当执行zarf init(初始化一个集群)时,如果目标机器上没有Kubernetes集群,Zarf可以选择部署一个轻量级的K3s集群。这个K3s的所有镜像都已经包含在zarf-init包中,真正做到开箱即用。
  2. Zarf Registry:一个内置的Docker镜像仓库。所有在包中定义的容器镜像,在部署时都会被推送到这个内部仓库中。随后,Zarf会通过一个Mutating Webhook,自动修改所有部署的Pod的镜像拉取地址,使其指向这个内部仓库,并注入对应的拉取密钥。这个过程对应用完全透明。
  3. Zarf Gitea:一个内置的Git服务器。对于需要从Git仓库拉取配置的应用(比如使用Flux CD),Zarf可以将指定的Git仓库在打包时克隆一份,并存入这个内置的Gitea。部署时,Flux的GitRepository资源URL会被自动重写,指向这个内部Gitea实例。

注意事项:内置服务虽然方便,但通常是为离线环境设计的测试或轻量级使用。对于大规模生产环境,你可能希望禁用某些内置服务(如在zarf.yaml中设置disable),转而连接已有的、更健壮的企业级镜像仓库和Git服务。Zarf完全支持这种模式。

3.3 软件物料清单与安全特性

在安全要求严格的领域(如国防、金融),软件供应链安全至关重要。Zarf原生集成了软件物料清单生成和签名验证功能。

  • SBOM生成:在创建包时(zarf package create --sbom),Zarf会自动为包内的所有组件生成一份软件物料清单。这份SBOM会列出所有容器镜像、它们的层哈希以及已知的漏洞信息(如果提供了漏洞扫描工具接口)。生成的SBOM文件(如sbom-viewer.html)可以随包一起分发,为安全审计提供清晰的依据。
  • Cosign签名:Zarf支持使用Sigstore项目的Cosign工具对包进行数字签名和验证。在zarf package create时添加签名密钥,可以确保包的完整性和来源可信。在离线环境部署时,使用zarf package deploy --key来验证签名,能有效防止恶意篡改。

4. 实战:从零构建并部署一个离线应用包

让我们通过一个完整的例子,将一个简单的Web应用及其依赖的Redis数据库,打包并部署到离线环境中。假设我们的应用包含一个前端(Nginx镜像)和一个后端API(自定义Go镜像),后端需要连接Redis。

4.1 环境准备与Zarf CLI安装

首先,在联网的开发机上操作。

  1. 安装Zarf CLI:访问Zarf的GitHub Release页面,下载对应你操作系统的最新版二进制文件。例如,在Linux上:

    # 下载最新版 VERSION=$(curl -s https://api.github.com/repos/zarf-dev/zarf/releases/latest | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') wget https://github.com/zarf-dev/zarf/releases/download/${VERSION}/zarf_${VERSION}_Linux_amd64 # 赋予执行权限并移动到PATH chmod +x zarf_${VERSION}_Linux_amd64 sudo mv zarf_${VERSION}_Linux_amd64 /usr/local/bin/zarf # 验证安装 zarf version
  2. 准备应用代码和清单:假设你的项目结构如下:

    my-offline-app/ ├── Dockerfile # 用于构建后端Go应用镜像 ├── frontend/ │ └── index.html # 前端静态文件 ├── k8s/ │ ├── backend.yaml # 后端Deployment & Service │ ├── frontend.yaml # 前端Deployment & Service │ └── redis.yaml # Redis StatefulSet └── zarf.yaml # Zarf包定义文件

4.2 编写zarf.yaml定义文件

这是整个打包过程的核心。我们需要定义三个组件:redis、backend、frontend。

kind: ZarfPackageConfig metadata: name: "my-offline-app" description: "A demo offline web application with Redis" version: "0.1.0" variables: - name: BACKEND_IMAGE_TAG default: "latest" description: "The tag for the backend container image" components: # 组件1: Redis数据库 - name: "redis" required: true images: - "redis:7-alpine" # Zarf会自动从Docker Hub拉取此镜像 manifests: - name: redis-statefulset files: - "./k8s/redis.yaml" # 组件2: 后端API服务 - name: "backend" required: true dependsOn: - redis # 确保先部署Redis images: # 这里引用一个需要构建的镜像,使用`###ZARF_IMAGE###`作为占位符 - "my-registry.local/my-offline-app-backend:###ZARF_IMAGE###" manifests: - name: backend-deployment files: - "./k8s/backend.yaml" actions: onDeploy: # 部署后,等待后端服务就绪 - cmd: kubectl wait --for=condition=available deployment/my-backend -n zarf --timeout=120s # 组件3: 前端Web服务 - name: "frontend" required: true dependsOn: - backend # 前端依赖后端服务 images: - "nginx:alpine" manifests: - name: frontend-deployment files: - "./k8s/frontend.yaml"

关键点说明

  • 对于需要从源码构建的镜像(如我们的后端Go应用),我们在images列表中使用了###ZARF_IMAGE###占位符。在打包时,我们需要通过--set参数或构建脚本来替换它。
  • dependsOn确保了部署顺序:Redis -> Backend -> Frontend。
  • actions.onDeploy让我们可以在部署完成后执行健康检查,确保服务可用后再部署下一个组件。

4.3 构建应用镜像并创建Zarf包

由于我们的后端镜像是自定义的,我们需要先构建它,并在打包时告诉Zarf使用这个构建好的镜像。

# 1. 构建后端Docker镜像(假设使用本地Docker) docker build -t my-offline-app-backend:latest . # 2. 创建Zarf包 # 使用 `--set` 将变量和镜像引用关联起来 zarf package create . \ --set BACKEND_IMAGE_TAG=latest \ --set BACKEND_IMAGE=my-offline-app-backend:latest

执行zarf package create命令时,Zarf会执行以下魔法:

  1. 分析依赖:读取zarf.yaml,发现需要redis:7-alpinenginx:alpinemy-offline-app-backend:latest三个镜像。
  2. 拉取与重写:从Docker Hub拉取redis:7-alpinenginx:alpine。对于my-offline-app-backend:latest,它会从本地Docker Daemon中保存该镜像。同时,它会分析k8s/目录下的所有YAML文件,找出所有对镜像的引用。
  3. 打包:将所有镜像、YAML文件、SBOM(如果指定)等资源,压缩成一个名为zarf-package-my-offline-app-amd64-0.1.0.tar.zst的文件。

现在,这个.tar.zst文件就是我们的“离线安装包”。你可以把它拷贝到U盘或者内部文件服务器上。

4.4 在离线环境中部署

将包文件传输到离线环境中的一台机器上,这台机器可能是一台裸机,或者一个已有集群的跳板机。

场景A:目标环境没有Kubernetes集群

# 1. 初始化集群(会部署K3s和内置服务) # 首先需要获取zarf-init包,它通常随CLI发布或可从官网下载 zarf init --components=k3s,git-server,registry # 2. 等待初始化完成,然后部署我们的应用包 zarf package deploy zarf-package-my-offline-app-amd64-0.1.0.tar.zst

场景B:目标环境已有Kubernetes集群

# 1. 仅初始化Zarf的管理组件(如Registry, Git Server, Webhook),不安装K3s zarf init --components=git-server,registry --node-port=31830 # 2. 部署应用包 zarf package deploy zarf-package-my-offline-app-amd64-0.1.0.tar.zst

部署过程中,Zarf会:

  1. 将包内镜像推送到内置的Registry。
  2. 按顺序部署组件:先启动Redis,然后部署后端(并执行健康检查等待其就绪),最后部署前端。
  3. 自动修改所有Pod的镜像拉取策略和密钥,使其能从内置Registry拉取镜像。
  4. 如果配置了变量提示,会在此刻与用户交互。

部署完成后,你可以使用zarf connect命令建立到服务的隧道,在本地浏览器访问前端服务进行验证。

5. 高级技巧与避坑指南

5.1 处理私有依赖和自定义CA证书

在实际企业环境中,你的基础镜像可能来自私有仓库,或者内部服务使用自签名证书。

  • 私有镜像仓库:在打包时,Zarf CLI需要能访问这些仓库。你可以在执行zarf package create前,通过docker login登录私有仓库。Zarf会复用Docker的认证信息。更安全的方式是在zarf.yaml中配置imagePullSecret,但这种方式更复杂,需要预先创建secret并打包进去。
  • 自签名证书:如果内部服务(如私有Helm Chart仓库)使用自签名证书,你需要将CA证书添加到打包机的信任链中,或者使用--insecure标志(不推荐生产环境)。更好的做法是将CA证书作为一个文件放入包中,并在部署时通过actions将其添加到集群的信任存储中。

5.2 包的大小优化与分层策略

一个包含多个大型镜像的Zarf包可能会非常庞大(几十GB)。为了优化传输和存储:

  1. 分层打包:将稳定的基础组件(如数据库、消息中间件)和频繁变更的业务应用分开打包。例如,创建一个base-infra包和一个business-app包。这样,每次更新应用时,只需要传输较小的业务包。
  2. 使用轻量级基础镜像:在构建应用镜像时,优先选择Alpine、Distroless等小型基础镜像,能从源头减小包体积。
  3. 压缩与分片:Zarf默认使用zstd压缩,效率很高。对于极端情况,可以考虑在传输前对包进行分卷压缩。

5.3 调试与故障排查

在离线环境,调试工具匮乏。Zarf提供了一些内置命令来帮助排查问题。

  • zarf tools monitor:在部署后,可以快速连接到内置的K9s终端仪表盘,查看Pod状态、日志和事件。这是离线环境下最强大的实时诊断工具。
  • zarf connect:用于端口转发,可以将集群内服务的端口映射到本地,方便直接访问Web界面或API。
  • 查看Zarf日志:Zarf组件的Pod运行在zarf命名空间下。使用kubectl logs -n zarf -l app=zarf-controller可以查看控制器的日志,里面通常包含了部署动作的详细记录和错误信息。

常见问题速查表

问题现象可能原因排查步骤
zarf package create拉取镜像失败1. 网络问题
2. 私有镜像未认证
3. 镜像不存在或标签错误
1. 检查网络和代理设置
2. 运行docker login
3. 手动docker pull测试镜像
zarf package deploy时Pod处于ImagePullBackOff1. 内置Registry未成功启动
2. Mutating Webhook未生效
3. 节点无法访问Registry Service
1.kubectl get pods -n zarf检查zarf-docker-registry
2.kubectl get mutatingwebhookconfiguration检查Zarf webhook
3.zarf connect registry测试本地能否访问
部署顺序不符合预期dependsOn配置有循环依赖或错误检查zarf.yaml中各组件的dependsOn关系,确保其为有向无环图
变量未正确替换变量名拼写错误,或Manifest中变量语法错误1. 确认变量在variables部分已定义
2. 确认Manifest中使用的是{{ .VARIABLE_NAME }}语法(Helm风格)

5.4 与现有CI/CD流水线集成

Zarf可以无缝集成到你的CI/CD流程中,作为“发布最后一步”的工件生成器。

例如,在GitLab CI中:

stages: - build - test - package package: stage: package image: docker:latest services: - docker:dind variables: ZARF_VERSION: "v0.32.0" before_script: - wget -qO- https://github.com/zarf-dev/zarf/releases/download/${ZARF_VERSION}/zarf_${ZARF_VERSION}_Linux_amd64 -O zarf - chmod +x zarf - ./zarf version script: # 登录到私有镜像仓库 - echo $DOCKER_PASSWORD | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin # 构建应用镜像 - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG # 使用Zarf打包,引用刚推送的镜像 - ./zarf package create . --confirm --set APP_IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG artifacts: paths: - zarf-package-*.tar.zst expire_in: 1 week

这样,每次代码合并并打上Tag后,流水线就会自动生成一个对应版本的、完整的离线部署包。

Zarf解决的是一个非常具体但极其痛苦的痛点——云原生应用的离线交付。它将复杂的、手动的、易出错的过程,变成了一个声明式的、自动化的、可靠的单文件操作。从我实际使用的经验来看,它的价值在那些对网络安全、供应链安全有极高要求的场景中会被无限放大。虽然它增加了一层抽象和打包的步骤,但相比于在离线环境里挣扎于各种网络代理和手动同步,这点前期投入是绝对值得的。如果你正在或即将面临类似挑战,花点时间研究一下Zarf,很可能为你和你的团队省下无数个加班的夜晚。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 5:08:06

AI Commit 2:基于AI的智能Git提交信息生成工具实战指南

1. 项目概述:AI Commit 2,一个智能化的版本控制助手如果你和我一样,每天在终端里敲git commit -m "fix bug"或者git commit -m "update"的次数比喝水还多,那你肯定也经历过那种“词穷”的尴尬时刻。明明代码改…

作者头像 李华
网站建设 2026/5/12 5:08:03

信息检索简单介绍

一.概念二.流程与方法三.常用的消息检索技术 1.基本运算符2.布尔逻辑检索3.截词检索4.位置检索5.限制检索 四.利用平台检索 1.中国知网 2.国家知识产权局专利检索及分析平台

作者头像 李华
网站建设 2026/5/12 5:06:34

claude-recall:为AI编程助手赋予记忆,自动化你的重复工作流

1. 项目概述:当AI助手学会“记忆”,你的工作流将如何进化?在AI工具井喷的今天,我们每天都在与各种智能助手打交道,从代码补全到文档生成,它们极大地提升了我们的效率。但不知你是否和我有同样的感受&#x…

作者头像 李华
网站建设 2026/5/12 5:02:39

C++——智能指针 weak_ptr

weak_ptr这个指针天生一副小弟的模样,也是在C11的时候引入的标准库,它的出现完全是为了弥补它老大shared_ptr天生有缺陷的问题。只能配合shared_ptr一起使用。 shared_ptr 循环引用造成的后果:存在资源泄露 一、shared_ptr 的循环引用 什么…

作者头像 李华