nixidy 简介 - 使用 Nix 进行 Kubernetes GitOps

Lobsters Hottest 工具

摘要

nixidy 是一个基于 Nix 的工具,用于管理 Kubernetes GitOps 部署,它用类型化、可复现的 Nix 表达式替代了 Helm 值文件和 Kustomize 覆盖层。本教程将介绍如何使用 Argo CD 设置 nixidy 项目,并生成纯 YAML 以供审查。

<p><a href="https://lobste.rs/s/nwrobx/introduction_nixidy_kubernetes_gitops">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/06/08 17:20

# nixidy 第一部分:nixidy 入门 | codedbearder 来源:https://codedbearder.com/posts/nixidy-part-1-introduction/ ## nixidy 第一部分:nixidy 入门 发布于 2026 年 6 月 8 日 我管理过许多基于 ArgoCD 的 Kubernetes GitOps 仓库,我敢肯定不止我一个人打开过一个 600 行 YAML 的 Helm values 覆盖文件,却仍然不确定哪些值最终生效到了渲染后的清单中。我运行过 `helm template`,把它通过 `grep` 管道处理,然后放弃,最后还是提交了代码,并希望 staging 环境的 diff 能捕捉到我自己没看出来的问题。 这种“你以为你在部署的东西”和“实际落在集群里的东西”之间的差距,正是 **nixidy** (<https://github.com/arnarg/nixidy>) 想要弥合的。我编写它就是为了用每个环境的一个 Nix 表达式来取代 Helm values 文件、Kustomize overlay 和原始 YAML。每个字段都有类型,每次构建都可复现,输出是纯 YAML,你可以在它接触集群之前用 `git diff` 来检查。 学完本部分之后,我们将拥有一个可用的 nixidy 项目,它定义了一个 nginx Deployment 和 Service,自动生成 Argo CD `Application` 清单,并通过 GitOps 部署到你的集群中。 ## 你将构建什么 我们将构建一个名为 `dev` 的 nixidy 环境,其中包含一个通过 Argo CD 部署到你集群的应用。这个项目结构将是你扩展到管理整个生产集群所需的基础骨架。 ## 前置条件 - **已安装 Nix**,并启用了 flakes([下载](https://nixos.org/download.html)) - **一个 Kubernetes 集群**,并已安装 **Argo CD** - **一个 Git 仓库**,用于存放你的 Kubernetes 清单(GitHub、GitLab 等) - **基本熟悉** Kubernetes 的 Deployment、Service 和 Namespace - **基本熟悉** Argo CD 的 `Application` 资源 > 信息 > > nixidy 实现了**渲染清单模式**([Rendered Manifests Pattern](https://akuity.io/blog/the-rendered-manifests-pattern/)),你的 CI 生成纯 YAML,你在 PR 中审查它,然后 Argo CD 将其部署。如果你之前用过 Argo CD 配合原始 YAML 或 Kustomize,那么部署侧流程是一样的。不同之处完全在于 **YAML 是如何产生的**。 ## 一个构建 Kubernetes 清单的 Nix 表达式 nixidy 的核心思想是:每个 Kubernetes 资源都是一个带类型的 Nix 选项。Deployment 不是一大块 YAML,而是一个结构化的属性集,其中 `replicas` 是整数,`image` 是字符串,而 `selector` 中的拼写错误会引发构建错误,而不是运行时意外。 让我们从创建项目开始: ``` mkdir my-cluster && cd my-cluster git init ``` 现在创建 `flake.nix`,这是将 nixidy 接入 Nix flake 的入口点: ``` { description = "My Kubernetes cluster managed with nixidy"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; nixidy.url = "github:arnarg/nixidy"; }; outputs = { nixpkgs, flake-utils, nixidy, ... }: flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs {inherit system;}; in { nixidyEnvs = nixidy.lib.mkEnvs { inherit pkgs; envs.dev.modules = [ ./env/dev.nix ]; }; }); } ``` 有几件事值得注意: - `nixidy.lib.mkEnvs` 接收一组命名的环境,并返回生成 YAML 清单的 Nix 派生式。键 `dev` 成为你使用 `.#dev` 引用的属性。 - 每个环境接收一个列表,包含多个 NixOS 风格的模块,这些模块只是设置选项的普通 `.nix` 文件。这与 NixOS 本身的模块系统相同,因此你可以获得 `imports`、`lib.mkDefault`、`lib.mkForce` 以及所有你期望的组合原语。 > 信息 > > 如果你之前配置过 NixOS 系统,那么结构是一样的:一个设置选项的模块列表,由模块系统合并。不同之处在于这些选项描述的是 Kubernetes 资源,而不是系统服务。 ## 一个包含一个应用的环境模块 现在让我们创建环境目录和 dev 模块: 编写 `env/dev.nix`。请务必将仓库 URL 替换为你自己的(nixidy 将在此告诉 Argo CD 去哪里寻找渲染后的清单): ``` { nixidy.target.repository = "https://github.com/YOUR_USERNAME/my-cluster.git"; nixidy.target.branch = "main"; nixidy.target.rootPath = "./manifests/dev"; applications.nginx = { namespace = "nginx"; createNamespace = true; resources = { deployments.nginx.spec = { replicas = 2; selector.matchLabels.app = "nginx"; template = { metadata.labels.app = "nginx"; spec.containers.nginx = { image = "nginx:1.25.1"; ports.http.containerPort = 80; }; }; }; services.nginx.spec = { selector.app = "nginx"; ports.http.port = 80; }; }; }; } ``` 让我解释一下这个声明的内容: - **`nixidy.target.*`**:生成的 YAML 在 Git 仓库中的存放位置。Argo CD 的 `Application` 清单将引用此仓库、分支和路径。 - **`applications.nginx`**:一个逻辑应用。一个应用在输出中会获得自己的目录,以及自己的 Argo CD `Application` 清单。 - **`namespace = "nginx"`**:此应用的所有资源都部署到 `nginx` 命名空间中。 - **`createNamespace = true`**:nixidy 会自动生成一个 `Namespace` 清单。如果没有这个选项,你需要通过其他方式创建命名空间。 - **`resources.deployments.nginx`**:一个带类型的 Deployment。其 `spec` 属性遵循 [Kubernetes Deployment spec](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/deployment-v1/),但在 Nix 求值阶段就进行了类型检查。 - **`resources.services.nginx`**:一个带类型的 Service,同理。 为什么不直接写 YAML? 两个原因。 1. 类型错误会变成构建错误。在上面的模块中将 `replicas = "two"`,然后 `nixidy build` 会立即失败,而不会等到部署 roll out 15 分钟后才发现问题。 2. 组合能力。当你添加一个 `prod.nix`,它导入同一个模块并设置 `replicas = lib.mkForce 10` 时,你用两行代码表达了“同一应用,不同规模”,而不是复制整个 YAML 文件并修改一个数字。NixOS 模块系统(`imports`、`lib.mkDefault`、`lib.mkForce`)免费为你提供这一能力,这也是处理多环境 NixOS 配置的同一机制。 ## 构建清单 运行构建: ``` nix run github:arnarg/nixidy -- build .#dev ``` > 信息 > > 首次运行时会将 nixidy 及其依赖项下载到 Nix store 中。如果没有任何变化,后续运行会瞬间完成。 查看输出: 你应该会看到: ``` result/ ├── apps/ │ └── Application-nginx.yaml └── nginx/ ├── Deployment-nginx.yaml ├── Namespace-nginx.yaml └── Service-nginx.yaml ``` 查看生成的 Deployment: ``` cat result/nginx/Deployment-nginx.yaml ``` ``` apiVersion: apps/v1 kind: Deployment metadata: name: nginx namespace: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx:1.25.1 name: nginx ports: - containerPort: 80 name: http ``` 以及 nixidy 为你生成的 Argo CD `Application`: ``` cat result/apps/Application-nginx.yaml ``` ``` apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: nginx namespace: argocd spec: destination: namespace: nginx server: https://kubernetes.default.svc project: default source: path: ./manifests/dev/nginx repoURL: https://github.com/YOUR_USERNAME/my-cluster.git targetRevision: main ``` 每个 `applications.*` 块恰好生成一个 Argo CD `Application`,指向包含其渲染清单的目录。这就是渲染清单模式:Argo CD 同步的是纯 YAML,而不是模板,不是 Helm release,只是它可以与集群状态进行 diff 的静态文件。 ## 提交渲染后的清单 `nixidy switch` 命令会将构建好的清单复制到你的仓库中你配置的 `rootPath` 位置: ``` nix run github:arnarg/nixidy -- switch .#dev ``` 这会在 `./manifests/dev/` 下创建与 `result/` 相同的目录结构。提交并推送: ``` git add . git commit -m "Add nginx application via nixidy" git push ``` 现在渲染后的 YAML 就在你的仓库中了。Argo CD 可以看到它。 ## 部署到你的集群 ### 使用 Argo CD 引导 如果 Argo CD 已经在你的集群中运行,一条命令即可创建一个“app of apps”(一个管理你所有 nixidy 应用的父 `Application`): ``` nix run github:arnarg/nixidy -- bootstrap .#dev | kubectl apply -f - ``` 这会输出一个 Argo CD `Application` 清单,该清单指向你仓库中的 `manifests/dev/apps/`。Argo CD 会读取该目录,发现 `Application-nginx.yaml`,创建 nginx `Application`,然后它会同步 Deployment、Service 和 Namespace 到你的集群中。 ### 或者:直接应用(用于测试) 如果你想暂时跳过 Argo CD,比如在本地 `kind` 集群上: ``` nix run github:arnarg/nixidy -- apply .#dev ``` 这会使用正确的标签选择器运行 `kubectl apply --prune`,因此从 nixidy 配置中移除的资源也会在下一次 apply 时从集群中移除(如果有资源已被移除的话)。 ## 下一步 现在我们有一个环境中的一个应用。真实的集群可能包含十几个应用,分布在 dev、staging 和 production 中,我可不想把同一个 Deployment 复制粘贴到三个文件里。在[第二部分](https://codedbearder.com/posts/nixidy-part-2-multi-env-and-helm-charts/)中,我们将重构 nginx 应用,将其变成共享模块,使用 `lib.mkDefault` 和 `lib.mkForce` 按环境重写 `replicas`,并在不放弃类型安全的前提下集成一个 Helm chart。 * * * GitHub 图标 (<https://github.com/arnarg>) LinkedIn 图标 (<https://www.linkedin.com/in/arnari>) Mastodon 图标 (<https://floss.social/@arnar>) © Arnar Gauti Ingason 本网站由 [nixtml](https://github.com/arnarg/nixtml) 生成

相似文章

我喜欢的 NixOS 声明式安装方式

Michael Stapelberg

一份关于使用 nixos-anywhere 等工具通过网络声明式安装 NixOS 的指南,重点强调在版本控制下管理配置文件。

NixOS 与密钥管理

Lobsters Hottest

教程介绍 NixOS 的密钥管理选项,比较 sops-nix、agenix 和 ragenix 工具,并提供使用 sops-nix 进行加密密钥管理的实际示例。

使用Nix的开发环境:四个快速示例

Michael Stapelberg

本教程演示了使用Nix设置开发环境的四种方法,包括交互式一次性使用、配置文件以及密封的Nix Flakes,并以GoCV和OpenCV为例。

将我的 NAS 从 CoreOS/Flatcar Linux 迁移到 NixOS

Michael Stapelberg

Michael Stapelberg 详细介绍了他将一台 NAS 从 CoreOS/Flatcar Linux 迁移到 NixOS 的过程,涵盖了从 Docker 容器逐步过渡到原生 NixOS 模块的步骤,并附有实际示例。

NNN Stack: NixOS, Niri, Noctalia

Lobsters Hottest

NNN Stack 结合了 NixOS、Niri 组合器和 Noctalia shell,创建了一个声明式、可滚动且可复现的桌面环境,并邀请用户贡献他们的 dotfiles。