diff --git a/nixos/doc/manual/from_md/installation/installing-kexec.section.xml b/nixos/doc/manual/from_md/installation/installing-kexec.section.xml new file mode 100644 index 00000000000..46ea0d59b6c --- /dev/null +++ b/nixos/doc/manual/from_md/installation/installing-kexec.section.xml @@ -0,0 +1,94 @@ +
+ <quote>Booting</quote> into NixOS via kexec + + In some cases, your system might already be booted into/preinstalled + with another Linux distribution, and booting NixOS by attaching an + installation image is quite a manual process. + + + This is particularly useful for (cloud) providers where you can’t + boot a custom image, but get some Debian or Ubuntu installation. + + + In these cases, it might be easier to use kexec + to jump into NixOS from the running system, which + only assumes bash and kexec to + be installed on the machine. + + + Note that kexec may not work correctly on some hardware, as devices + are not fully re-initialized in the process. In practice, this + however is rarely the case. + + + To build the necessary files from your current version of nixpkgs, + you can run: + + +nix-build -A kexec.x86_64-linux '<nixpkgs/nixos/release.nix>' + + + This will create a result directory containing + the following: + + + + + bzImage (the Linux kernel) + + + + + initrd (the initrd file) + + + + + kexec-boot (a shellscript invoking + kexec) + + + + + These three files are meant to be copied over to the other already + running Linux Distribution. + + + Note it’s symlinks pointing elsewhere, so cd in, + and use scp * root@$destination to copy it over, + rather than rsync. + + + Once you finished copying, execute kexec-boot + on the destination, and after some seconds, the + machine should be booting into an (ephemeral) NixOS installation + medium. + + + In case you want to describe your own system closure to kexec into, + instead of the default installer image, you can build your own + configuration.nix: + + +{ modulesPath, ... }: { + imports = [ + (modulesPath + "/installer/netboot/netboot-minimal.nix") + ]; + + services.openssh.enable = true; + users.users.root.openssh.authorizedKeys.keys = [ + "my-ssh-pubkey" + ]; +} + + +nix-build '<nixpkgs/nixos>' \ + --arg configuration ./configuration.nix + --attr config.system.build.kexecTree + + + Make sure your configuration.nix does still + import netboot-minimal.nix (or + netboot-base.nix). + +
diff --git a/nixos/doc/manual/from_md/installation/installing.chapter.xml b/nixos/doc/manual/from_md/installation/installing.chapter.xml index aee0b30a707..19ff841f5a6 100644 --- a/nixos/doc/manual/from_md/installation/installing.chapter.xml +++ b/nixos/doc/manual/from_md/installation/installing.chapter.xml @@ -638,6 +638,7 @@ $ passwd eelco Additional installation notes + diff --git a/nixos/doc/manual/installation/installing-kexec.section.md b/nixos/doc/manual/installation/installing-kexec.section.md new file mode 100644 index 00000000000..286cbbda6a6 --- /dev/null +++ b/nixos/doc/manual/installation/installing-kexec.section.md @@ -0,0 +1,64 @@ +# "Booting" into NixOS via kexec {#sec-booting-via-kexec} + +In some cases, your system might already be booted into/preinstalled with +another Linux distribution, and booting NixOS by attaching an installation +image is quite a manual process. + +This is particularly useful for (cloud) providers where you can't boot a custom +image, but get some Debian or Ubuntu installation. + +In these cases, it might be easier to use `kexec` to "jump into NixOS" from the +running system, which only assumes `bash` and `kexec` to be installed on the +machine. + +Note that kexec may not work correctly on some hardware, as devices are not +fully re-initialized in the process. In practice, this however is rarely the +case. + +To build the necessary files from your current version of nixpkgs, +you can run: + +```ShellSession +nix-build -A kexec.x86_64-linux '' +``` + +This will create a `result` directory containing the following: + - `bzImage` (the Linux kernel) + - `initrd` (the initrd file) + - `kexec-boot` (a shellscript invoking `kexec`) + +These three files are meant to be copied over to the other already running +Linux Distribution. + +Note it's symlinks pointing elsewhere, so `cd` in, and use +`scp * root@$destination` to copy it over, rather than rsync. + +Once you finished copying, execute `kexec-boot` *on the destination*, and after +some seconds, the machine should be booting into an (ephemeral) NixOS +installation medium. + +In case you want to describe your own system closure to kexec into, instead of +the default installer image, you can build your own `configuration.nix`: + +```nix +{ modulesPath, ... }: { + imports = [ + (modulesPath + "/installer/netboot/netboot-minimal.nix") + ]; + + services.openssh.enable = true; + users.users.root.openssh.authorizedKeys.keys = [ + "my-ssh-pubkey" + ]; +} +``` + + +```ShellSession +nix-build '' \ + --arg configuration ./configuration.nix + --attr config.system.build.kexecTree +``` + +Make sure your `configuration.nix` does still import `netboot-minimal.nix` (or +`netboot-base.nix`). diff --git a/nixos/doc/manual/installation/installing.chapter.md b/nixos/doc/manual/installation/installing.chapter.md index 8a46d68ae3b..7e830f8e458 100644 --- a/nixos/doc/manual/installation/installing.chapter.md +++ b/nixos/doc/manual/installation/installing.chapter.md @@ -476,6 +476,7 @@ With a partitioned disk. ```{=docbook} + diff --git a/nixos/modules/installer/kexec/kexec-boot.nix b/nixos/modules/installer/kexec/kexec-boot.nix deleted file mode 100644 index 2d062214efc..00000000000 --- a/nixos/modules/installer/kexec/kexec-boot.nix +++ /dev/null @@ -1,51 +0,0 @@ -# This module exposes a config.system.build.kexecBoot attribute, -# which returns a directory with kernel, initrd and a shell script -# running the necessary kexec commands. - -# It's meant to be scp'ed to a machine with working ssh and kexec binary -# installed. - -# This is useful for (cloud) providers where you can't boot a custom image, but -# get some Debian or Ubuntu installation. - -{ pkgs -, modulesPath -, config -, ... -}: -{ - imports = [ - (modulesPath + "/installer/netboot/netboot-minimal.nix") - ]; - - config = { - system.build.kexecBoot = - let - kexecScript = pkgs.writeScript "kexec-boot" '' - #!/usr/bin/env bash - if ! kexec -v >/dev/null 2>&1; then - echo "kexec not found: please install kexec-tools" 2>&1 - exit 1 - fi - SCRIPT_DIR=$( cd -- "$( dirname -- "''${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) - kexec --load ''${SCRIPT_DIR}/bzImage \ - --initrd=''${SCRIPT_DIR}/initrd.gz \ - --command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" - kexec -e - ''; in - pkgs.linkFarm "kexec-tree" [ - { - name = "initrd.gz"; - path = "${config.system.build.netbootRamdisk}/initrd"; - } - { - name = "bzImage"; - path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}"; - } - { - name = "kexec-boot"; - path = kexecScript; - } - ]; - }; -} diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix index a459e7304cd..3127bdc436f 100644 --- a/nixos/modules/installer/netboot/netboot.nix +++ b/nixos/modules/installer/netboot/netboot.nix @@ -101,6 +101,37 @@ with lib; boot ''; + # A script invoking kexec on ./bzImage and ./initrd.gz. + # Usually used through system.build.kexecTree, but exposed here for composability. + system.build.kexecScript = pkgs.writeScript "kexec-boot" '' + #!/usr/bin/env bash + if ! kexec -v >/dev/null 2>&1; then + echo "kexec not found: please install kexec-tools" 2>&1 + exit 1 + fi + SCRIPT_DIR=$( cd -- "$( dirname -- "''${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + kexec --load ''${SCRIPT_DIR}/bzImage \ + --initrd=''${SCRIPT_DIR}/initrd.gz \ + --command-line "init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" + kexec -e + ''; + + # A tree containing initrd.gz, bzImage and a kexec-boot script. + system.build.kexecTree = pkgs.linkFarm "kexec-tree" [ + { + name = "initrd.gz"; + path = "${config.system.build.netbootRamdisk}/initrd"; + } + { + name = "bzImage"; + path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}"; + } + { + name = "kexec-boot"; + path = config.system.build.kexecScript; + } + ]; + boot.loader.timeout = 10; boot.postBootCommands = diff --git a/nixos/release.nix b/nixos/release.nix index e0d782bcaec..beafdf9ff5b 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -151,6 +151,13 @@ in rec { # Build the initial ramdisk so Hydra can keep track of its size over time. initialRamdisk = buildFromConfig ({ ... }: { }) (config: config.system.build.initialRamdisk); + kexec = forMatchingSystems supportedSystems (system: (import lib/eval-config.nix { + inherit system; + modules = [ + ./modules/installer/netboot/netboot-minimal.nix + ]; + }).config.system.build.kexecTree); + netboot = forMatchingSystems supportedSystems (system: makeNetboot { module = ./modules/installer/netboot/netboot-minimal.nix; inherit system; diff --git a/nixos/tests/kexec.nix b/nixos/tests/kexec.nix index 7238a9f58e0..3f5a6f521af 100644 --- a/nixos/tests/kexec.nix +++ b/nixos/tests/kexec.nix @@ -18,8 +18,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { virtualisation.vlans = [ ]; environment.systemPackages = [ pkgs.hello ]; imports = [ - "${modulesPath}/installer/kexec/kexec-boot.nix" - "${modulesPath}/profiles/minimal.nix" + "${modulesPath}/installer/netboot/netboot-minimal.nix" ]; }; }; @@ -33,14 +32,14 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { node1.connect() node1.wait_for_unit("multi-user.target") - # Check if the machine with kexec-boot.nix profile boots up + # Check if the machine with netboot-minimal.nix profile boots up node2.wait_for_unit("multi-user.target") node2.shutdown() # Kexec node1 to the toplevel of node2 via the kexec-boot script node1.succeed('touch /run/foo') node1.fail('hello') - node1.execute('${nodes.node2.config.system.build.kexecBoot}/kexec-boot', check_return=False) + node1.execute('${nodes.node2.config.system.build.kexecTree}/kexec-boot', check_return=False) node1.succeed('! test -e /run/foo') node1.succeed('hello') node1.succeed('[ "$(hostname)" = "node2" ]')