This one got me off guard. Been on nixos for several years now, and I always
relied on files referenced by ./path/to/foo.env being available on the
target machine.
tl;dr - I believe there’s a few potential non-obvious things going on in here:
- files referenced with ./path/to/foo.env not being copied to remote
- nixos VMs opaquely accessing host’s /nix/store
- oci-containers’s environmentFiles too lazily evaluated (or not at all)
The other day I was setting up managed containers via oci-containers.
They rely on certain environment files in order to run.
The part that made this so hard to debug is - locally
everything works ok, but when pushed to a destination system (e.g. via
nixos-rebuild --target-host), .foo.env is not available.
It turns out that .foo.env is availble in the builder’s nix store, and when a
local VM is run via nixos-rebuild -f .#foo build-vm && ./result/bin/run-foo-vm,
the VM sees the file and works OK. Logging into the VM and manually checking
/nix/store path seems like the file was copied onto the VM, while in fact it’s
referencing the builder’s /nix/store.
For example, this is a barebone VM with fd as the only installed package,
and it’s finding cliamp in it’s nix store.
[alice@foo:~]$ fd cliamp /nix/store
/nix/store/y019w1npngzswvz94hl99bvghm55zb9v-system-path/bin/cliamp
/nix/store/wfq3f1cli2n02vcx3w913dkn1g174d3k-cliamp-1.39.1.drv
/nix/store/b3aa8mw38wr2c2w3wi1y22j92kvk287g-cliamp-1.35.0-go-modules.drv
...
Repro
Create an env file we’ll use:
$ echo FOO=bar > .foo.env
If in a git repo, git add .foo.env.
Add this module to a nixos machine:
virtualisation.oci-containers.containers = {
hello = {
cmd = [
"sh"
"-c"
"env | grep FOO || echo FOO is missing!"
];
environmentFiles = [
# ../.foo.env # <- file doesn't exist, flake builds no problem.
# ./doesnt-exist.env # self explanatory. builds normally
./.foo.env # <- file exists. TODO check if service can read it
];
image = "docker.io/library/alpine:latest";
};
};
Quick REPL check (foo is the VM, remotemachine is a real remote machine):
nix-repl> outputs.nixosConfigurations.foo.config.virtualisation.vmVariant.virtualisation.oci-containers.containers.hello.environmentFiles
[ /nix/store/1y2krcz9z3ds5w68j4ag0d6g4cniax5m-source/.foo.env ]
nix-repl> outputs.nixosConfigurations.remotemachine.config.virtualisation.oci-containers.containers.hello.environmentFiles
[ /nix/store/1y2krcz9z3ds5w68j4ag0d6g4cniax5m-source/.foo.env ]
Build and run the VM:
$ nixos-rebuild --flake .#foo build-vm && ./result/bin/run-foo-vm -nographic
Check for FOO in the VM:
[alice@foo:~]$ journalctl -eu podman-hello | grep -E 'FOO|Error'
Aug 05 21:06:57 foo hello[702]: FOO=bar
Build and deploy the same module to the remote machine:
$ sudo nixos-rebuild --flake .#remotemachine --target-host remotemachine switch
$ ssh remotemachine "journalctl -eu podman-hello | grep -E 'FOO|Error'"
Aug 05 16:55:19 mx-001 podman-hello-start[8599]: Error: parsing file "/nix/store/1y2krcz9z3ds5w68j4ag0d6g4cniax5m-source/.foo.env": open /nix/store/1y2krcz9z3ds5w68j4ag0d6g4cniax5m-source/.foo.env: no such file or directory
Expected
Referencing files with ./path/to/foo.env copies them over to the target host.