diff options
Diffstat (limited to 'nixpkgs/nixos/modules/virtualisation/nixos-containers.nix')
-rw-r--r-- | nixpkgs/nixos/modules/virtualisation/nixos-containers.nix | 127 |
1 files changed, 70 insertions, 57 deletions
diff --git a/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix b/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix index 0838a57f0f37..1285563c6463 100644 --- a/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix +++ b/nixpkgs/nixos/modules/virtualisation/nixos-containers.nix @@ -4,6 +4,11 @@ with lib; let + configurationPrefix = optionalString (versionAtLeast config.system.stateVersion "22.05") "nixos-"; + configurationDirectoryName = "${configurationPrefix}containers"; + configurationDirectory = "/etc/${configurationDirectoryName}"; + stateDirectory = "/var/lib/${configurationPrefix}containers"; + # The container's init script, a small wrapper around the regular # NixOS stage-2 init script. containerInit = (cfg: @@ -77,7 +82,7 @@ let startScript = cfg: '' mkdir -p -m 0755 "$root/etc" "$root/var/lib" - mkdir -p -m 0700 "$root/var/lib/private" "$root/root" /run/containers + mkdir -p -m 0700 "$root/var/lib/private" "$root/root" /run/nixos-containers if ! [ -e "$root/etc/os-release" ]; then touch "$root/etc/os-release" fi @@ -127,7 +132,7 @@ let # If the host is 64-bit and the container is 32-bit, add a # --personality flag. - ${optionalString (config.nixpkgs.localSystem.system == "x86_64-linux") '' + ${optionalString (pkgs.stdenv.hostPlatform.system == "x86_64-linux") '' if [ "$(< ''${SYSTEM_PATH:-/nix/var/nix/profiles/per-container/$INSTANCE/system}/system)" = i686-linux ]; then extraFlags+=" --personality=x86" fi @@ -249,11 +254,11 @@ let SyslogIdentifier = "container %i"; - EnvironmentFile = "-/etc/containers/%i.conf"; + EnvironmentFile = "-${configurationDirectory}/%i.conf"; Type = "notify"; - RuntimeDirectory = lib.optional cfg.ephemeral "containers/%i"; + RuntimeDirectory = lib.optional cfg.ephemeral "${configurationDirectoryName}/%i"; # Note that on reboot, systemd-nspawn returns 133, so this # unit will be restarted. On poweroff, it returns 0, so the @@ -279,7 +284,7 @@ let DeviceAllow = map (d: "${d.node} ${d.modifier}") cfg.allowedDevices; }; - system = config.nixpkgs.localSystem.system; + inherit (config.nixpkgs) localSystem; kernelVersion = config.boot.kernelPackages.kernel.version; bindMountOpts = { name, ... }: { @@ -288,18 +293,18 @@ let mountPoint = mkOption { example = "/mnt/usb"; type = types.str; - description = "Mount point on the container file system."; + description = lib.mdDoc "Mount point on the container file system."; }; hostPath = mkOption { default = null; example = "/home/alice"; type = types.nullOr types.str; - description = "Location of the host path to be mounted."; + description = lib.mdDoc "Location of the host path to be mounted."; }; isReadOnly = mkOption { default = true; type = types.bool; - description = "Determine whether the mounted path will be accessed in read-only mode."; + description = lib.mdDoc "Determine whether the mounted path will be accessed in read-only mode."; }; }; @@ -314,16 +319,16 @@ let node = mkOption { example = "/dev/net/tun"; type = types.str; - description = "Path to device node"; + description = lib.mdDoc "Path to device node"; }; modifier = mkOption { example = "rw"; type = types.str; - description = '' + description = lib.mdDoc '' Device node access modifier. Takes a combination - <literal>r</literal> (read), <literal>w</literal> (write), and - <literal>m</literal> (mknod). See the - <literal>systemd.resource-control(5)</literal> man page for more + `r` (read), `w` (write), and + `m` (mknod). See the + `systemd.resource-control(5)` man page for more information.''; }; }; @@ -341,7 +346,7 @@ let type = types.nullOr types.str; default = null; example = "br0"; - description = '' + description = lib.mdDoc '' Put the host-side of the veth-pair into the named bridge. Only one of hostAddress* or hostBridge can be given. ''; @@ -353,22 +358,22 @@ let protocol = mkOption { type = types.str; default = "tcp"; - description = "The protocol specifier for port forwarding between host and container"; + description = lib.mdDoc "The protocol specifier for port forwarding between host and container"; }; hostPort = mkOption { type = types.int; - description = "Source port of the external interface on host"; + description = lib.mdDoc "Source port of the external interface on host"; }; containerPort = mkOption { type = types.nullOr types.int; default = null; - description = "Target port of container"; + description = lib.mdDoc "Target port of container"; }; }; }); default = []; example = [ { protocol = "tcp"; hostPort = 8080; containerPort = 80; } ]; - description = '' + description = lib.mdDoc '' List of forwarded ports from host to container. Each forwarded port is specified by protocol, hostPort and containerPort. By default, protocol is tcp and hostPort and containerPort are assumed to be @@ -381,7 +386,7 @@ let type = types.nullOr types.str; default = null; example = "10.231.136.1"; - description = '' + description = lib.mdDoc '' The IPv4 address assigned to the host interface. (Not used when hostBridge is set.) ''; @@ -391,7 +396,7 @@ let type = types.nullOr types.str; default = null; example = "fc00::1"; - description = '' + description = lib.mdDoc '' The IPv6 address assigned to the host interface. (Not used when hostBridge is set.) ''; @@ -401,7 +406,7 @@ let type = types.nullOr types.str; default = null; example = "10.231.136.2"; - description = '' + description = lib.mdDoc '' The IPv4 address assigned to the interface in the container. If a hostBridge is used, this should be given with netmask to access the whole network. Otherwise the default netmask is /32 and routing is @@ -413,7 +418,7 @@ let type = types.nullOr types.str; default = null; example = "fc00::2"; - description = '' + description = lib.mdDoc '' The IPv6 address assigned to the interface in the container. If a hostBridge is used, this should be given with netmask to access the whole network. Otherwise the default netmask is /128 and routing is @@ -445,7 +450,7 @@ in boot.isContainer = mkOption { type = types.bool; default = false; - description = '' + description = lib.mdDoc '' Whether this NixOS machine is a lightweight container running in another NixOS system. ''; @@ -454,7 +459,7 @@ in boot.enableContainers = mkOption { type = types.bool; default = true; - description = '' + description = lib.mdDoc '' Whether to enable support for NixOS containers. Defaults to true (at no cost if containers are not actually used). ''; @@ -466,19 +471,19 @@ in { options = { config = mkOption { - description = '' + description = lib.mdDoc '' A specification of the desired configuration of this container, as a NixOS module. ''; type = lib.mkOptionType { name = "Toplevel NixOS config"; merge = loc: defs: (import "${toString config.nixpkgs}/nixos/lib/eval-config.nix" { - inherit system; modules = let extraConfig = { _file = "module at ${__curPos.file}:${toString __curPos.line}"; config = { + nixpkgs = { inherit localSystem; }; boot.isContainer = true; networking.hostName = mkDefault name; networking.useDHCP = false; @@ -508,9 +513,9 @@ in path = mkOption { type = types.path; example = "/nix/var/nix/profiles/per-container/webserver"; - description = '' + description = lib.mdDoc '' As an alternative to specifying - <option>config</option>, you can specify the path to + {option}`config`, you can specify the path to the evaluated NixOS system configuration, typically a symlink to a system profile. ''; @@ -520,7 +525,7 @@ in type = types.listOf types.str; default = []; example = [ "CAP_NET_ADMIN" "CAP_MKNOD" ]; - description = '' + description = lib.mdDoc '' Grant additional capabilities to the container. See the capabilities(7) and systemd-nspawn(1) man pages for more information. @@ -564,21 +569,21 @@ in enableTun = mkOption { type = types.bool; default = false; - description = '' + description = lib.mdDoc '' Allows the container to create and setup tunnel interfaces - by granting the <literal>NET_ADMIN</literal> capability and - enabling access to <literal>/dev/net/tun</literal>. + by granting the `NET_ADMIN` capability and + enabling access to `/dev/net/tun`. ''; }; privateNetwork = mkOption { type = types.bool; default = false; - description = '' + description = lib.mdDoc '' Whether to give the container its own private virtual Ethernet interface. The interface is called - <literal>eth0</literal>, and is hooked up to the interface - <literal>ve-<replaceable>container-name</replaceable></literal> + `eth0`, and is hooked up to the interface + `ve-«container-name»` on the host. If this option is not set, then the container shares the network interfaces of the host, and can bind to any port on any interface. @@ -589,7 +594,7 @@ in type = types.listOf types.str; default = []; example = [ "eth1" "eth2" ]; - description = '' + description = lib.mdDoc '' The list of interfaces to be moved into the container. ''; }; @@ -598,7 +603,7 @@ in type = types.listOf types.str; default = []; example = [ "eth1" "eth2" ]; - description = '' + description = lib.mdDoc '' The list of host interfaces from which macvlans will be created. For each interface specified, a macvlan interface will be created and moved to the container. @@ -608,7 +613,7 @@ in extraVeths = mkOption { type = with types; attrsOf (submodule { options = networkOptions; }); default = {}; - description = '' + description = lib.mdDoc '' Extra veth-pairs to be created for the container. ''; }; @@ -616,7 +621,7 @@ in autoStart = mkOption { type = types.bool; default = false; - description = '' + description = lib.mdDoc '' Whether the container is automatically started at boot-time. ''; }; @@ -624,11 +629,10 @@ in timeoutStartSec = mkOption { type = types.str; default = "1min"; - description = '' + description = lib.mdDoc '' Time for the container to start. In case of a timeout, the container processes get killed. - See <citerefentry><refentrytitle>systemd.time</refentrytitle> - <manvolnum>7</manvolnum></citerefentry> + See {manpage}`systemd.time(7)` for more information about the format. ''; }; @@ -643,7 +647,7 @@ in ''; description = - '' + lib.mdDoc '' An extra list of directories that is bound to the container. ''; }; @@ -652,7 +656,7 @@ in type = with types; listOf (submodule allowedDeviceOpts); default = []; example = [ { node = "/dev/net/tun"; modifier = "rw"; } ]; - description = '' + description = lib.mdDoc '' A list of device nodes to which the containers has access to. ''; }; @@ -661,7 +665,7 @@ in type = types.listOf types.str; default = []; example = [ "/var" ]; - description = '' + description = lib.mdDoc '' Mounts a set of tmpfs file systems into the container. Multiple paths can be specified. Valid items must conform to the --tmpfs argument @@ -673,7 +677,7 @@ in type = types.listOf types.str; default = []; example = [ "--drop-capability=CAP_SYS_CHROOT" ]; - description = '' + description = lib.mdDoc '' Extra flags passed to the systemd-nspawn command. See systemd-nspawn(1) for details. ''; @@ -723,12 +727,12 @@ in }; } ''; - description = '' + description = lib.mdDoc '' A set of NixOS system configurations to be run as lightweight containers. Each container appears as a service - <literal>container-<replaceable>name</replaceable></literal> + `container-«name»` on the host system, allowing it to be started and stopped via - <command>systemctl</command>. + {command}`systemctl`. ''; }; @@ -740,12 +744,12 @@ in unit = { description = "Container '%i'"; - unitConfig.RequiresMountsFor = "/var/lib/containers/%i"; + unitConfig.RequiresMountsFor = "${stateDirectory}/%i"; path = [ pkgs.iproute2 ]; environment = { - root = "/var/lib/containers/%i"; + root = "${stateDirectory}/%i"; INSTANCE = "%i"; }; @@ -760,6 +764,11 @@ in serviceConfig = serviceDirectives dummyConfig; }; in { + warnings = + (optional (config.virtualisation.containers.enable && versionOlder config.system.stateVersion "22.05") '' + Enabling both boot.enableContainers & virtualisation.containers on system.stateVersion < 22.05 is unsupported. + ''); + systemd.targets.multi-user.wants = [ "machines.target" ]; systemd.services = listToAttrs (filter (x: x.value != null) ( @@ -782,8 +791,8 @@ in script = startScript containerConfig; postStart = postStartScript containerConfig; serviceConfig = serviceDirectives containerConfig; - unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "/var/lib/containers/%i"; - environment.root = if containerConfig.ephemeral then "/run/containers/%i" else "/var/lib/containers/%i"; + unitConfig.RequiresMountsFor = lib.optional (!containerConfig.ephemeral) "${stateDirectory}/%i"; + environment.root = if containerConfig.ephemeral then "/run/nixos-containers/%i" else "${stateDirectory}/%i"; } // ( if containerConfig.autoStart then { @@ -792,7 +801,7 @@ in after = [ "network.target" ]; restartTriggers = [ containerConfig.path - config.environment.etc."containers/${name}.conf".source + config.environment.etc."${configurationDirectoryName}/${name}.conf".source ]; restartIfChanged = true; } @@ -800,12 +809,12 @@ in )) config.containers) )); - # Generate a configuration file in /etc/containers for each + # Generate a configuration file in /etc/nixos-containers for each # container so that container@.target can get the container # configuration. environment.etc = let mkPortStr = p: p.protocol + ":" + (toString p.hostPort) + ":" + (if p.containerPort == null then toString p.hostPort else toString p.containerPort); - in mapAttrs' (name: cfg: nameValuePair "containers/${name}.conf" + in mapAttrs' (name: cfg: nameValuePair "${configurationDirectoryName}/${name}.conf" { text = '' SYSTEM_PATH=${cfg.path} @@ -854,7 +863,11 @@ in ENV{INTERFACE}=="v[eb]-*", ENV{NM_UNMANAGED}="1" ''; - environment.systemPackages = [ pkgs.nixos-container ]; + environment.systemPackages = [ + (pkgs.nixos-container.override { + inherit stateDirectory configurationDirectory; + }) + ]; boot.kernelModules = [ "bridge" |