Files
blog-public/content/blog/cluster-filesystem.md
2025-01-15 13:09:54 +08:00

97 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 集群的文件系统应该怎么做?
date: 2025-01-14T12:14:06+08:00
summary: 让我捋一捋
---
NixOS 的文件系统本来就比较复杂(加上 impermanence 之后)。
集群又需要共享家目录。
又考虑到集群里机器的 CPU 不一样home-manager 等工具生成的配置文件指向的二进制在不同机器上不一定能用,因为编译时 `-march` 不同),
搞得就很麻烦。
前几天把一直分开运行的两个机器合并到一起了,但在合并前并没有非常仔细地思考文件系统怎么设计,
于是成功地自己把自己绕进去了,出了一些自己也不理解的 bug。
impermanence 的配置文件,自从我一年前把它写好之后就没有大动过,遇到需要的时候就得过且过修修补补,现在它已经很混乱了,是时候重新设计一下了。
按照我的设想,`/home` 中的文件主要来自两个地方。
一个是 `/nix/persistent/home`,这些文件在每次重启后依然会保留;一个是 `/nix/rootfs/current/home`,这些文件在每次重启后都会丢失。
只有少量的文件挂载或软链接自别的地方。
## 需求
明确需求才能提出合理的解决方案。
最后解决方案需要满足所有的需求,也不需要过度设计,不要创造需求。
1. 只需要考虑 `/home` 挂载的问题。其它目录的挂载运行良好,不需要更改。
2. 集群上,一部分文件需要共享,另一部分则不能共享:
在集群中,`/home` 下的大多数文件需要在所有节点上共享(即,从机通过 NFS 来获得大部分文件)。
但是有一些文件和目录是不应该共享的,包括例如 `.config` `.zshrc` 等。
这些目录中包含许多 home-manager 生成的文件,其中指向的二进制文件在不同机器上不兼容。
3. 可复现与留存状态的平衡:
桌面用途下的 `chn` 用户是一个特例,`/home` 下的大部分文件应该在重启后丢失,只有少数留存。
除了这个特例以外,`/home` 下的大部分文件应该留存状态(即,在重启后不丢失,也即来自于 `/nix/persistent`
少部分文件(例如 `.cache`)应该为了确保可复现而丢失状态(即,在重启后丢失,也即来自于 `/nix/rootfs/current`)。
4. 设置正确的权限和所有者。
基本上就这些。
## 解决方案
1. `/home` 以外的挂载代码不动。
2. `/home` 本身不挂载。
3. 在所有挂载开始之前,确认 `/nix/persistent/home/user``/nix/rootfs/current/home/user` 存在并设置合理的权限。
这通过 `system.activationScripts` 来实现。
这个设置会在两个情况下起作用:一个是在启动时,在挂载好了根目录但还没有 switch root 前进行;另一个是 rebuild 时进行。
这里已经有了一些内容,包括:
* `users` 是 nixpkgs 设置用户的一些内容(例如创建家目录)。
* `createPersistentStorageDirs` 是 impermanence 生成的,
用于在挂载前用正确的权限创建需要的目录(指 target不是挂载点所在的目录如果 target 已经存在则不检查权限;
并根据 target 的权限调整挂载点及其父目录的权限。
在前者之后运行。
* `persist-files` 也是 impermanence 生成的,用于挂载需要的文件(不涉及目录)。
仔细阅读之后,确认现在的代码应该已经足够,不再需要手动在这里添加代码。
4. 挂载 `/home/user`。这分为几种情况:
* 在集群的主节点上,导出 `/nix/persistent/home`;再其它节点上,通过 NFS 挂载。
这个挂载需要在 `activationScripts` 之前完成(`neededForBoot = true`)。
* 对于桌面用途的 `chn` 用户,不需要挂载。
* 对于其它情况,挂载 `/nix/persistent/home/user``/home/user`
这通过 nixos 的 impermanence 模块实现(以设置正确的权限)。
5. 挂载更详细的目录。大部分使用 nixos 的 impermanence 中,`users.user` 来实现,有一个例外需要直接写 `systemd.mounts`
* 对于所有用户,`.cache` 需要在重启后丢失,它应该挂载自 `/nix/rootfs/current/home/user/.cache`
* 对于桌面的 `chn` 用户,有一些额外的目录需要挂载自 `/nix/persistent/home/chn``/nix/rootfs/current/home/chn`
* 对于集群的非主节点,需要采取额外的措施来避免覆写主节点的文件,包括:
* 禁用 home-manager 在家目录的根目录中创建的一些符号链接,包括 `.zshrc` 等;改而使用挂载。
* 额外从 `/nix/rootfs/current/home/user` 挂载一些目录过来,例如 `.ssh`home-manager 将需要覆写这些目录中的文件。
* 由于 impermanence 会将 target 及其父目录的权限复制给挂载点,这会导致一个问题:
挂载来自 nix store 的文件(即 home-manager 生成的那些文件)时,家目录会被改写为 `root:root 555`
这些文件改为直接用 `systemd.mounts` 来挂载。
最终代码在[这里](https://github.com/CHN-beta/nixos/tree/741b6185a4412f0e45fc5afd13bcfadb91c5de7e/modules/system/fileSystems)。
## 其中的坑
我遇到了一些问题。
第一个问题是,如果 home-manager 生成的文件也用 impermanence 来挂载(最开始我就是这样做的),
那么家目录的权限会在从机启动后被改写为 `root:root 555`
出现这个状况的原因在之前已经解释过了。
通过将这些文件直接用 `systemd.mounts` 来挂载,这个问题可以被避免——然后我就发现家目录权限被改成了 `root:root 755`
为什么会出现这个状况,我想了很久才想通。这个过程是这样的:
1. 在 NFS 挂载之前:`/nix/rootfs/current` 已经被挂载到了 `/`,而 `/home/user``/nix/rootfs/current/home/user` 都不存在。
2. 在 NFS 挂载时,会自动创建不存在的挂载点然后再挂载。
这样,在 NFS 挂载 `192.168.178.1:/nix/persistent/home/user``/home/user` 之后,
`/home/user` 的权限是远程文件系统的 `user:user 700`
`/nix/rootfs/current/home/user` 的权限是被自动创建的挂载点在挂载前的权限,也就是 `root:root 755`
3. 之后 `system.activationScripts` 中 impermanence 中的脚本会运行,
它发现 `/nix/rootfs/current/home/user` 已经存在了,就不会再创建或者修改它的权限;
然后它将 `/nix/rootfs/current/home/user` 的权限复制给 `/home/user`,这个行为也一并把远程的权限覆盖掉了。
直觉来说,只要告诉 systemd 创建挂载点时用某个用户、设定某个权限就好了;
但我翻了一圈资料,似乎没有设定所有者的办法(权限是可以设定的,通过 `X-mount.mkdir` 选项)。
所以最终解决办法是:
1. 先将 `192.168.178.1:/nix/persistent/home` 挂载到 `/remote/home`
`/remote/home` 的权限无所谓,随他便,这只是为了避免创建 `/nix/rootfs/current/home/user`
2. 再将 `/remote/home/user` 挂载到 `/home/user`,这一步通过 impermanence 进行,
以设定正确的权限(`/home/user``/nix/rootfs/current/home/user` 的权限都会被设定为 `user:user 700`)。
3. 之后impermanence 再挂载其它来自 `/nix/rootfs/current/home/user` 的目录或文件,都不会出问题了。