nixidy 简介 - 使用 Nix 进行 Kubernetes GitOps
摘要
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 声明式安装方式
一份关于使用 nixos-anywhere 等工具通过网络声明式安装 NixOS 的指南,重点强调在版本控制下管理配置文件。
NixOS 与密钥管理
教程介绍 NixOS 的密钥管理选项,比较 sops-nix、agenix 和 ragenix 工具,并提供使用 sops-nix 进行加密密钥管理的实际示例。
使用Nix的开发环境:四个快速示例
本教程演示了使用Nix设置开发环境的四种方法,包括交互式一次性使用、配置文件以及密封的Nix Flakes,并以GoCV和OpenCV为例。
将我的 NAS 从 CoreOS/Flatcar Linux 迁移到 NixOS
Michael Stapelberg 详细介绍了他将一台 NAS 从 CoreOS/Flatcar Linux 迁移到 NixOS 的过程,涵盖了从 Docker 容器逐步过渡到原生 NixOS 模块的步骤,并附有实际示例。
NNN Stack: NixOS, Niri, Noctalia
NNN Stack 结合了 NixOS、Niri 组合器和 Noctalia shell,创建了一个声明式、可滚动且可复现的桌面环境,并邀请用户贡献他们的 dotfiles。