nix/vm: store service data in a shared folder on the host #466

merged
opened by winter.bsky.social targeting master from winter.bsky.social/core: push-tkullpkzpmst

This also switches away from nixos-shell in the process as by this point it wasn't really adding much to our setup except inflexibility.

Signed-off-by: Winter winter@winter.cafe

Changed files
+69 -48
docs
nix
+1
.gitignore
···
.env
*.rdb
.envrc
···
.env
*.rdb
.envrc
+
/nix/vm-data
+3 -5
docs/hacking.md
···
ideally in a `.envrc` with [direnv](https://direnv.net) so you
don't lose it.
-
You can now start a lightweight NixOS VM using
-
`nixos-shell` like so:
```bash
-
nix run .#vm
-
# or nixos-shell --flake .#vm
-
# hit Ctrl-a + c + q to exit the VM
```
This starts a knot on port 6000, a spindle on port 6555
···
ideally in a `.envrc` with [direnv](https://direnv.net) so you
don't lose it.
+
You can now start a lightweight NixOS VM like so:
```bash
+
nix run --impure .#vm
+
# type `poweroff` at the shell to exit the VM
```
This starts a knot on port 6000, a spindle on port 6555
+22 -27
flake.nix
···
program = ''${tailwind-watcher}/bin/run'';
};
vm = let
-
system =
if pkgs.stdenv.hostPlatform.isAarch64
-
then "aarch64"
-
else "x86_64";
-
-
nixos-shell = pkgs.nixos-shell.overrideAttrs (old: {
-
patches =
-
(old.patches or [])
-
++ [
-
# https://github.com/Mic92/nixos-shell/pull/94
-
(pkgs.fetchpatch {
-
name = "fix-foreign-vm.patch";
-
url = "https://github.com/Mic92/nixos-shell/commit/113e4cc55ae236b5b0b1fbd8b321e9b67c77580e.patch";
-
hash = "sha256-eauetBK0wXAOcd9PYbExokNCiwz2QyFnZ4FnwGi9VCo=";
-
})
-
];
-
});
in {
type = "app";
-
program = toString (pkgs.writeShellScript "vm" ''
-
${nixos-shell}/bin/nixos-shell --flake .#vm-${system} --guest-system ${system}-linux
-
'');
};
gomod2nix = {
type = "app";
···
services.tangled-spindle.package = lib.mkDefault self.packages.${pkgs.system}.spindle;
};
-
nixosConfigurations.vm-x86_64 = import ./nix/vm.nix {
-
inherit self nixpkgs;
-
system = "x86_64-linux";
-
};
-
nixosConfigurations.vm-aarch64 = import ./nix/vm.nix {
-
inherit self nixpkgs;
-
system = "aarch64-linux";
-
};
};
}
···
program = ''${tailwind-watcher}/bin/run'';
};
vm = let
+
guestSystem =
if pkgs.stdenv.hostPlatform.isAarch64
+
then "aarch64-linux"
+
else "x86_64-linux";
in {
type = "app";
+
program =
+
(pkgs.writeShellApplication {
+
name = "launch-vm";
+
text = ''
+
rootDir=$(jj --ignore-working-copy root || git rev-parse --show-toplevel) || (echo "error: can't find repo root?"; exit 1)
+
cd "$rootDir"
+
+
mkdir -p nix/vm-data/{knot,repos,spindle,spindle-logs}
+
+
export TANGLED_VM_DATA_DIR="$rootDir/nix/vm-data"
+
exec ${pkgs.lib.getExe
+
(import ./nix/vm.nix {
+
inherit nixpkgs self;
+
system = guestSystem;
+
hostSystem = system;
+
}).config.system.build.vm}
+
'';
+
})
+
+ /bin/launch-vm;
};
gomod2nix = {
type = "app";
···
services.tangled-spindle.package = lib.mkDefault self.packages.${pkgs.system}.spindle;
};
};
}
+43 -16
nix/vm.nix
···
{
nixpkgs,
system,
self,
}: let
envVar = name: let
···
self.nixosModules.knot
self.nixosModules.spindle
({
config,
pkgs,
...
}: {
-
nixos-shell = {
-
inheritPath = false;
-
mounts = {
-
mountHome = false;
-
mountNixProfile = false;
-
};
-
};
-
virtualisation = {
memorySize = 2048;
diskSize = 10 * 1024;
cores = 2;
···
guest.port = 6555;
}
];
};
services.getty.autologinUser = "root";
environment.systemPackages = with pkgs; [curl vim git sqlite litecli];
-
systemd.tmpfiles.rules = let
-
u = config.services.tangled-knot.gitUser;
-
g = config.services.tangled-knot.gitUser;
-
in [
-
"d /var/lib/knot 0770 ${u} ${g} - -" # Create the directory first
-
"f+ /var/lib/knot/secret 0660 ${u} ${g} - KNOT_SERVER_SECRET=${envVar "TANGLED_VM_KNOT_SECRET"}"
-
];
services.tangled-knot = {
enable = true;
motd = "Welcome to the development knot!\n";
server = {
-
secretFile = "/var/lib/knot/secret";
hostname = "localhost:6000";
listenAddr = "0.0.0.0:6000";
};
···
};
};
};
})
];
}
···
{
nixpkgs,
system,
+
hostSystem,
self,
}: let
envVar = name: let
···
self.nixosModules.knot
self.nixosModules.spindle
({
+
lib,
config,
pkgs,
...
}: {
+
virtualisation.vmVariant.virtualisation = {
+
host.pkgs = import nixpkgs {system = hostSystem;};
+
+
graphics = false;
memorySize = 2048;
diskSize = 10 * 1024;
cores = 2;
···
guest.port = 6555;
}
];
+
sharedDirectories = {
+
# We can't use the 9p mounts directly for most of these
+
# as SQLite is incompatible with them. So instead we
+
# mount the shared directories to a different location
+
# and copy the contents around on service start/stop.
+
knotData = {
+
source = "$TANGLED_VM_DATA_DIR/knot";
+
target = "/mnt/knot-data";
+
};
+
spindleData = {
+
source = "$TANGLED_VM_DATA_DIR/spindle";
+
target = "/mnt/spindle-data";
+
};
+
spindleLogs = {
+
source = "$TANGLED_VM_DATA_DIR/spindle-logs";
+
target = "/var/log/spindle";
+
};
+
};
};
services.getty.autologinUser = "root";
environment.systemPackages = with pkgs; [curl vim git sqlite litecli];
services.tangled-knot = {
enable = true;
motd = "Welcome to the development knot!\n";
server = {
+
secretFile = builtins.toFile "knot-secret" ("KNOT_SERVER_SECRET=" + (envVar "TANGLED_VM_KNOT_SECRET"));
hostname = "localhost:6000";
listenAddr = "0.0.0.0:6000";
};
···
};
};
};
+
systemd.services = let
+
mkDataSyncScripts = source: target: {
+
enableStrictShellChecks = true;
+
+
postStart = ''
+
[[ -d ${target} ]] || exit 0
+
${lib.getExe pkgs.rsync} -a ${source}/ ${target}
+
'';
+
+
postStop = ''
+
[[ -d ${target} ]] || exit 0
+
${lib.getExe pkgs.rsync} -a ${target}/ ${source}
+
'';
+
};
+
in {
+
knot = mkDataSyncScripts "/mnt/knot-data" config.services.tangled-knot.stateDir;
+
spindle = mkDataSyncScripts "/mnt/spindle-data" (builtins.dirOf config.services.tangled-spindle.server.dbPath);
+
};
})
];
}