在Serokell,我们使用了大量的Nix。虽然它在很多方面对我们有帮助,但我们觉得Nix+NixOS部署的选择实际上是相当缺乏的,没有任何现有的工具符合我们基础设施的要求。
我们尝试了morph、NixOps、一些按项目定制的部署脚本,甚至是普通的nixos-rebuild ,以及一些非Nix的解决方案,但没有一个能解决所有问题。
因此,我们决定研究创建我们自己的解决方案。 deploy-rs.
我们发现,它必须是:
- 远程:我们不希望(总是)在目标服务器上执行构建工作。
- 无状态:在我们每个开发人员和自动部署之间同步状态数据是不值得任何好处的。
sudo-兼容的:我们不希望在部署时需要root登录,即使是一个完整的NixOS系统关闭。- 安全:我们不想浪费Nix在激活失败时回滚的惊人能力。
- 可重复使用:该程序必须适合我们的每一个Nix部署。
有很多NixOS部署工具已经符合这些需求,尽管我们仍然必须给我们的CI/CD机器以root权限,或者使用非Nix解决方案来部署所有的应用程序,这两种情况都是不可取的。
我们想出的解决方案是根本不制作或使用NixOS部署工具,而是创建一个Nix部署工具,支持NixOS和任何其他类型的Nix配置文件,系统或其他。
结果就是这个,一个奇妙的简单的bash脚本。它不仅可以部署一个NixOS系统,还可以部署任何你想要的配置文件(如本例中所述)。
它很好地利用了Nix的新flakes功能,并以对待任何其他配置文件的部署方式来对待NixOS的部署,使我们能够在NixOS配置文件旁边部署任何应用程序的无根配置文件。
这是一个了不起的第一个原型,表明Nix部署仍然可以改进,尽管它仍然有一些问题。它是在Bash中进行的(这很好,尽管考虑到它是关键的基础设施,继续开发是有风险的),如果某些属性发生变化,有理论上的回滚问题,并且有一些从以前的实验中被放弃的想法(如bootstrap )。
deploy-rs 这是对这个初始工具背后的想法的全面重新实现。我们已经有了一个很好的想法,只是需要对它进行打磨。
这个工具遵循相同的模式,但在此基础上进行了扩展,并且完全用Rust编写,所以我们可以享受更多的安全性、表现力和速度。我们保留了相同的设计、片状结构和多配置文件的实现,但改进了界面并增加了更多功能。
特点
我们已经实现了很多替代NixOS部署工具中的基本功能,尽管我们自己的工具有一些独特的功能,解决了NixOS和非NixOS部署配置文件中的问题。
对于一个更完整的列表,你应该阅读项目的官方README。
多配置文件
一个标准的NixOS部署工具会让你把一个NixOS配置部署到机器上。然而,deploy-rs 是一个Nix部署工具,完全没有对NixOS的明确依赖性。
对于每个服务器(称为节点),你可以有任何数量的配置文件,它们被独立部署,你可以让一个NixOS配置文件以root身份安装,另一个是其他类型的配置文件,以你想要的任何用户身份部署:
{
deploy.nodes.example = {
hostname = "localhost";
profiles = {
system = {
user = "root";
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.example;
};
hello = {
user = "hello";
path = deploy-rs.lib.x86_64-linux.activate.custom self.defaultPackage.x86_64-linux "./bin/activate";
};
};
};
}
神奇的回滚
如前所述,使Nix/NixOS伟大的事情之一是回滚的能力。这是许多其他工具所支持的,但只是在激活失败的时候。我们决定将这一功能提升到新的水平。 deploy-rs (如果启用magic-rollback )将在配置文件激活后创建一个 "金丝雀 "文件,该文件将被部署端删除,否则配置文件将回滚并在30秒后重新激活(尽管超时是可配置的)。
这意味着我们在对基础设施进行现代化改造以使用我们的新工具时,不必担心会造成灾难。如果我们删除了自己的密钥,弄乱了网络,或者以其他方式阻止自己访问服务器,这个错误最多只会持续30秒。
静态激活路径
如果你通读了上面deploy 的代码,你可能已经注意到这个注释:
# Assuming that activation command didn't change
eval "$SUDO $activate"
这其实很重要,因为它在做一个假设:重新激活上一代的激活命令与激活这一代的激活命令是一样的。这意味着,如果你改变了你的激活命令并导致失败,回滚也会失败。
在deploy-rs ,我们通过让激活路径是静态的和标准化的来解决这个问题:deploy-rs 将总是运行${yourProfile}/deploy-rs-activate 中的文件。为了在我们的bash祖先中带回一些activate 领域的便利,我们在flake中包含了一个叫做lib.activate 的工具。要用自定义命令激活,你可以使用deploy-rs.lib.x86_64-linux.activate.custom pkgs.hello "./bin/hello" ,要激活NixOS系统,你可以使用deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.some-random-system ,如果你只是想写配置文件而不激活任何东西,你可以使用deploy-rs.lib.x86_64-linux.activate.noop 。
互动模式
如果你提供了-i 标志,deploy-rs 将打印所有将在toml中激活的东西,并在继续之前提示你:
[examplecomputer.system]
user = "root"
ssh_user = "exampleuser"
path = "/nix/store/xxrgxdg8x9zy8p0ky3d2hff4wf5igjpk-activatable-nixos-system-examplecomputer-21.03.20201119.a322b32"
hostname = "localhost"
ssh_opts = []
[examplecomputer.exampleuser-home-manager]
user = "exampleuser"
ssh_user = "exampleuser"
path = "/nix/store/k32k88vbyx9yqk7fk80bk0vcybzbkhra-activatable-home-manager-generation"
hostname = "localhost"
ssh_opts = []
INFO deploy > Are you sure you want to deploy these profiles?
>
非flake支持
虽然这个工具的实现和单纯的概念源于新的只适用于不稳定的Nix flakes命令,但我们已经确保这个工具也能在任何稳定版本的Nix中工作。
一旦你用较新的Nix版本创建了你的flake和flake.lock,你可以使用flake-compat ,使你的flake可以在较旧的Nix版本上通过default.nix 。deploy-rs ,将自动检测是否缺乏flakes支持,从default.nix ,并执行某些变通方法(例如在没有nix flakes check ,手动构建.checks 属性)。
自动检查
deploy-rs'的flake带有一些实用的检查,可以放在你的flake检查中,并在部署前自动检查所有的检查(除非指定--skip-checks )。这可以帮助你在每次部署前确保你的基础设施没有问题。
你可以使用我们包含的检查,只需将此添加到你的flake.nix 。
{
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
}
传递Nix参数
给予deploy-rs 的任何尾部参数将被传递给Nix本身,因此你可以做一些事情,如deploy . -- --override-input nixpkgs ./nixpkgs 。
我们如何使用它
在GitHub仓库中已经有了一些例子,不过如果你想看一些真实的使用情况,可以看看我们的网络应用集群定义,在那里我们专门利用deploy-rs 来部署NixOS,还有我们在上面运行的一个应用,它利用deploy-rs 来部署无root的服务。
值得注意的是,尽管在这些例子中,我们在NixOS的部署部分使用了systemd服务,而在应用端只使用了简单的systemctl restart ,但你也可以很容易地使用systemd用户服务来完成同样的事情,而不需要sudo规则。我们只是选择不这样做。
你甚至可以用它来部署一个没有root权限的家庭管理员配置。
未来
虽然我们的工作远未完成,但它已经达到了功能完整阶段,并通过了我们自己团队的审查。我们想把deploy-rs 发展成最终的部署工具,为我们所有的用例提供精心设计的工具。
我们的下一个近期目标(除了错误修复和代码清理)是支持systemd的可移植服务,以避免上一节中我们为用户应用使用系统级服务的问题。
我们也在考虑建立一个模块系统的想法,以增加一些功能,比如用于服务器的自动kexec lustration的模块,允许你在部署期间将系统转换为NixOS,以及与Vault集成的模块等等。
总结
我们希望这个工具对其他人也像对我们一样有用,允许你用Nix进行部署,而不需要root和完整的系统配置来部署一个完整的NixOS配置文件。