Open ashraffouda opened 2 years ago
nix-shell without arguments needs either a default.nix or a shell.nix file. not sure what that should do here. since the build image is generated out of the source there is no "need" to ship the configuration in the image itself. but you can put it in the image yourself. sometimes system.copySystemConfiguration
is enough, but this usually breaks if your configuration consists of multiple files.
and what about /etc/nixos/configuration.nix
? I built the image with system.copySystemConfiguration = true;
and after I booted the image /etc/nixos/configuration.nix doesn't exist, is it normal? I don't have enough experience about nixos
also what does system.copySystemConfiguration = true;
actually do? from where does it copy the files?
ah, interesting. I imaged system.copySystemConfiguration = true;
working at some point but I haven't tested it in a while.
I guess the best way forward would be to copy the current workingDirectory via nix. Sadly this is quite advanced and not sure if really useful. can't you just rsync/scp the configuration.nix in there or maybe git clone it? What are you trying to do?
I'm just trying to build an image for our cloud infrastructure, now I managed to build it, but not sure if configuration.nix should be there? or the user should add it him self after his machine is deployed
also what does
system.copySystemConfiguration = true;
actually do? from where does it copy the files?
good question, I checked the sourcecode, it just symlinks $NIXOS_CONFIG
from $NIX_PATH
to system.build.out/configuration.nix. So it's not really useful here
I'm just trying to build an image for our cloud infrastructure, now I managed to build it, but not sure if configuration.nix should be there? or the user should add it him self after his machine is deployed
usually the usecase for this repo is to build a "final" image which is not updated further through itself but instead rebuild. I guess you can do this anyway, but it's not really straight forward right now sadly
I was struggling with this myself, as I use nixos-generators to generate fresh boot disks for my nodes, and I want my nodes to be able to autoupdate themselves without me re-flashing their boot disks.
I have now solved this for my needs using flakes. In flake.nix, I have defined both a nixosGenerate
as an attr in packages.x86_64-linux
and a nixosSystem
as an attr in nixosConfigurations
. I define both attrs for each node I want to deploy with nixos-generators. I then include this flake in the nix store for use with system.autoUpgrade
.
Using this, I can generate a disk image for a flash drive using nix build .#<hostname>
, while making sure that nixos-upgrade.service
also has access to the flake to be able to generate a new profile for itself after deployment. This automation is super useful for me to ensure that the configuration running on the machine is always in sync with my git repository, even if I leave it running for months without interacting with it; While also still staying up to date with the latest nixos updates.
Here is an example of a nix flake that can do this, with some magic to make it easy to define multiple nodes in the same flake: (my full code is available at https://github.com/JustinLex/jlh-h5b/tree/main/nodes)
# flake.nix
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-23.11";
nixos-generators = {
url = "github:nix-community/nixos-generators";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, nixos-generators, ... }:
let
nodes = [
# List hostnames here for configuration
"my-nix-machine"
];
generator = (
# Function that templates out a value for the `packages` attrset.
# Used for defining the NixOS generator for a given node.
# docs: https://github.com/nix-community/nixos-generators/blob/master/README.md
nodename:
nixos-generators.nixosGenerate {
system = "x86_64-linux";
format = "raw-efi";
modules = [
./common.nix
# ./nodes/${nodename}.nix # Can be used to extend config for each node
];
specialArgs = {
# additional arguments to pass to modules
self = self;
nodeHostName = nodename;
};
}
);
configuration = (
# Function that templates out a value for the `nixosConfigurations` attrset.
# Used for bundling a nixos configuration for the node to be used for autoUpgrades after deployment.
nodename:
nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./raw-efi.nix # Duplicate some bits of config from upstream nixox-generators so that we can use nixos-rebuild
./common.nix
# ./nodes/${nodename}.nix # Can be used to extend config for each node
];
specialArgs = {
# additional arguments to pass to modules
self = self;
nodeHostName = nodename;
};
}
);
in {
# This attrset evaluates to: {"my-nix-machine" = nixos-generators.nixosGenerate {...}; ... }
packages.x86_64-linux = builtins.listToAttrs (
map
( nodename: { "name" = nodename; "value" = generator(nodename); } )
( nodes ) # List of nodes to generate images for
);
# This attrset evaluates to: {"my-nix-machine" = nixpkgs.lib.nixosSystem {...}; ... }
nixosConfigurations = builtins.listToAttrs (
map
( nodename: { "name" = nodename; "value" = configuration(nodename); } )
( nodes ) # List of nodes to generate NixOS Configurations for
);
};
}
# common.nix
{ config, pkgs, self, nodeHostName, ... }:
{
networking.hostName = nodeHostName;
environment.systemPackages = with pkgs; [
htop
];
# Enable automatic updates
# https://nixos.wiki/wiki/Automatic_system_upgrades
system.autoUpgrade = {
enable = true;
# dates = "Sun *-*-* 03:00 Europe/Stockholm";
# randomizedDelaySec = "6hr";
allowReboot = true;
flake = "path:${self.outPath}#${nodeHostName}"; # flake path must be preceded with "path:" because otherwise nix build will get confused when we ask to build a flake in the nix store
flags = [
"--update-input"
"nixpkgs"
"-L" # print build logs
];
};
system.stateVersion = "23.11";
}
# raw-efi.nix
# Duplicate nixox-generators' config so that we can use nixos-rebuild
# https://github.com/nix-community/nixos-generators/blob/master/formats/raw-efi.nix
# Fixes failed assertions with running nixos-rebuild:
# - The ‘fileSystems’ option does not specify your root file system.
# - You must set the option ‘boot.loader.grub.devices’ or 'boot.loader.grub.mirroredBoots' to make the system bootable.
{ config, pkgs, ... }:
{
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-label/ESP";
fsType = "vfat";
};
boot = {
growPartition = true;
kernelParams = ["console=ttyS0"];
loader.grub = {
device = "nodev";
efiSupport = true;
efiInstallAsRemovable = true;
};
loader.timeout = 0;
initrd.availableKernelModules = ["uas"];
};
}
I'm super happy that NixOS and NixOS-generators enables this kind of automation for edge/homelab deployments. I hope this configuration helps others also wanting to rebuild NixOS profiles after deployment.
@JustinLex thanks for sharing your config! I wanted to do a very similar thing and ended up making a separate flake that wraps modified versions of your generator and configuration functions along with the right bootloader code for raw-efi
and sd-aarch64
. I figured I'd post it here for the next person who comes across this so they don't have to struggle as much as I did
I built a qcow image and now /etc/nixos/configuration.nix doesn't exist doesn't exist any clue how to make it exists by default on the resulting image also executing nix-shell doesn't work
shouldn't those files shipped by default on the images?