Last active
October 21, 2023 09:16
-
-
Save Thesola10/999b4e6d1eca84b9ce1d380ced2934dd to your computer and use it in GitHub Desktop.
Build and spin up a NixOS configuration or flake as a systemd-nspawn container on non-NixOS systems.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# nixos-spawn (c) Karim Vergnes <me@thesola.io> | |
# This script launches systemd-nspawn in an empty root, with an overlay of the | |
# host's Nix Store. This takes advantage of the NixOS stage 2 init's ability to | |
# populate an empty system automatically. | |
# By default, no changes are persisted anywhere -- use an additional bind mount | |
# to add permanent storage. | |
: ${NIXOS_CHANNEL:=nixpkgs} | |
if [[ $UID != 0 ]] | |
then | |
>&2 echo "This script is meant to be run as root. Try 'sudo $0'." | |
exit 1 | |
elif [[ $# < 1 ]] | |
then | |
>&2 echo "Usage: $0 <nixos configuration file or flake ref> [systemd-nspawn options...]" | |
exit 1 | |
fi | |
if [[ ! -d /run/nixos-container/nix/var/nix/db ]] | |
then | |
# Setting up Nix Store overlay area | |
mkdir -p /run/nixos-container/nix/.rw-{store,db} | |
mkdir -p /run/nixos-container/nix/{store,var/nix/db} | |
# Telling systemd-nspawn to shut up | |
mkdir -p /run/nixos-container/usr/bin | |
fi | |
if [[ -e $1 ]] | |
then | |
# Systematically enable the `boot.isContainer' option. This bypasses a bunch of | |
# errors related to bootloader config, as well as stage 2 mounts. | |
# We also enable systemd-networkd, a hard requirement for working network setup | |
# in nspawn containers. (oh and systemd-resolved too for convenience) | |
nix-build -E "(import <$NIXOS_CHANNEL/nixos> { configuration = builtins.toFile ''config'' | |
'' | |
{lib, ...}: | |
{ imports = [ $(realpath $1) ]; | |
boot.isContainer = lib.mkForce true; | |
systemd.network.enable = lib.mkForce true; | |
services.resolved.enable = lib.mkForce true; | |
networking.useHostResolvConf = lib.mkForce false; | |
networking.firewall.enable = lib.mkDefault false; | |
} | |
''; }).system" -o system \ | |
|| { >&2 echo "NixOS system failed to build. Check output above for more information."; exit 1; } | |
else | |
if nix eval --raw "$1".config.system.build.toplevel >&/dev/null 2>&1 | |
then | |
[[ $(nix eval "$1".config.boot.isContainer) == "false" ]] && \ | |
>&2 echo "WARNING: This NixOS configuration is not a container, and may fail to boot." | |
nix build "$1".config.system.build.toplevel -o system \ | |
|| { >&2 echo "NixOS system failed to build. Check output above for more information."; exit 1; } | |
elif nix eval --raw "$1".nixosLabel >&/dev/null 2>&1 | |
then | |
>&2 echo "WARNING: NixOS toplevel package passed. This is not recommended, since" | |
>&2 echo "I can't determine whether it is a container or not." | |
>&2 echo "Prefer using a \`nixosConfiguration' output." | |
nix build "$1" -o system \ | |
|| { >&2 echo "NixOS system failed to build. Check output above for more information."; exit 1; } | |
else | |
>&2 echo "Flake reference \`$1' does not resolve to a NixOS configuration or toplevel package." | |
exit 1 | |
fi | |
fi | |
shift 1 | |
systemd-nspawn -xD/run/nixos-container \ | |
--overlay=/nix/store:+/nix/.rw-store:/nix/store \ | |
--overlay=/nix/var/nix/db:+/nix/.rw-db:/nix/var/nix/db \ | |
"$@" $(readlink ./system)/init |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you haven't installed Nix on your host system, and still want to use this script to invoke a NixOS container, then you may want to use the
nix-build
command provided by the Nix Portable project, then apply the following changes to the script:If all you need is a dev environment, consider using Nixie