Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Networkd containers #140669

Draft
wants to merge 79 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
202254d
nixos/systemd-nspawn: Allow to modify .nspawn-units with a derivation
Ma27 Apr 14, 2020
80045ce
nixos/containers-next: initialize first draft for new NixOS container…
Ma27 Oct 13, 2020
6068759
nixos/containers-next: implement small wrapper for nspawn port-forwards
Ma27 Feb 14, 2021
fe18e25
nixos/containers-next: implement more advanced networking tests
Ma27 Mar 5, 2021
e727866
nixos/tests/container-migration: init
Ma27 Mar 10, 2021
891b998
nixos/containers-next: allow static configuration for a virtual zone …
Ma27 Mar 12, 2021
3199c8f
nixos/switch-to-configuration: import old config activation changes
Ma27 Feb 22, 2021
1f9aca8
nixos/containers-next: fix broken machinectl reboot and probably more
Ma27 Mar 16, 2021
4738b8e
nixos/switch-to-configuration: Implement more generic decisions for c…
Ma27 Mar 17, 2021
e33228f
nixos/containers-next: add read-only `nixos.containers.rendered` option
Ma27 Apr 3, 2021
bcf4864
nixos/all-tests: register tests
Ma27 Apr 12, 2021
a5db036
nixos/containers-next: make sure that the module works fine with `res…
Ma27 Apr 12, 2021
aa7956b
nixos/containers-next: add test for SSH inside a nspawn machine
Ma27 Apr 29, 2021
bcb6671
nixos/containers-next: enable private users by default
Ma27 Apr 29, 2021
a3a28fc
nixos/systemd-nspawn: make `/etc/systemd/nspawn` mutable
Ma27 May 15, 2021
184f470
nixos/containers-next: fix eval after 21.05 breaking changes
Ma27 Jul 2, 2021
7423d9a
nixos-nspawn: init
Ma27 Aug 29, 2021
8811e17
nixos/containers-next: implement proper user-namespacing support
Ma27 Sep 1, 2021
b769a0a
nixos/containers-next: add support for `LoadCredential=`
Ma27 Sep 3, 2021
8fc451d
nixos/containers-next-imperative: init
Ma27 Sep 3, 2021
e12408a
sudo-nspawn: init
Ma27 Sep 5, 2021
10214d0
nixos/switch-to-configuration: fix a few problems with nspawn instances
Ma27 Sep 10, 2021
107d4ca
nixos-nspawn: misc improvements & cleanups
Ma27 Sep 12, 2021
cbdf5d3
nixos/containers-next: move to subdir and factor out defaults for con…
Ma27 Sep 13, 2021
ea7bd5a
nixos-nspawn: implement activation & networking
Ma27 Sep 13, 2021
85b8882
nixos/activation-scripts: turn off `var`-script for containers
Ma27 Sep 22, 2021
0caa260
Revert "nixos/activation-scripts: turn off `var`-script for containers"
Ma27 Sep 24, 2021
c8355e5
nixos/containers-next: only create OS structure in `/var/lib/machines…
Ma27 Sep 24, 2021
62e4520
nixos/tests/containers-next: add testcase for custom `ResolvConf`-set…
Ma27 Sep 24, 2021
6467ce6
nixos/container-migration-test: confirm that nixos-container is still…
Ma27 Sep 24, 2021
9f80931
nixos/containers-next: assert that networkd is used
Ma27 Sep 24, 2021
82a3419
nixos/tests/containers-next-imperative: ensure that imperative contai…
Ma27 Sep 24, 2021
ebcdc12
nixos/tests/container-migration: fix eval
Ma27 Nov 27, 2021
a33d4ca
nixos/containers-next: fix eval
Ma27 Jan 3, 2022
9a3b5ec
nixos/qemu-vm: increase /boot to 120M
Ma27 Jan 3, 2022
40a8152
nixos/container-migration: actually move state of containers
Ma27 Jan 3, 2022
ba4d079
nixos/containers-next: fix test
Ma27 Jan 3, 2022
d4a16d5
nixos/containers-next: s/literalExample/literalExpression/g
Ma27 Jan 4, 2022
7006d0d
nixos/useHostResolvConf: deprecate option
Ma27 Jan 4, 2022
5d8c6e1
nixos/containers-next-imperative: fix test
Ma27 Jan 4, 2022
f93309d
nixos/containers-next: fix `systemd-networkd-wait-online.service` han…
Ma27 Jan 4, 2022
2c2b642
nixos/containers-next: config -> system-config
Ma27 Jan 4, 2022
7ab5a06
nixos/containers-next: confirm that exposed hostnames also work for s…
Ma27 Jan 4, 2022
b371881
nixos/containers-next: review fixes
Ma27 Jan 4, 2022
1fd3769
sudo-nspawn: merge with `pkgs.sudo`
Ma27 Jan 4, 2022
2f08185
nixos-nspawn: refactor python setup
Ma27 Jan 4, 2022
cd533c3
Merge branch 'master' into networkd-containers
Ma27 Jun 12, 2022
feffb03
nixos/qemu-vm: fix manual evaluation
Ma27 Jun 12, 2022
c1443db
Merge branch 'master' into networkd-containers
Ma27 Dec 9, 2022
dc7aaba
nixos/containers-next-imperative: workarounds to get the test green f…
Ma27 Dec 9, 2022
e6cc908
nixos/containers-next: fix option doc wording
Ma27 Feb 16, 2023
b69a0b5
Merge branch 'master' into networkd-containers
Ma27 Feb 16, 2023
fa25e04
nixos/module-list: fix merge
Ma27 Feb 16, 2023
be5fa64
nixos/containers-next: remove forwardPorts option
Ma27 Feb 16, 2023
d9fdcef
nixos/containers-next-macvlan: init
Ma27 Feb 16, 2023
c262041
nixos/tests: move all rfc108 related tests into a common subdir
Ma27 Feb 17, 2023
b81a276
nixos/tests/containers-next/wireguard: init
Ma27 Feb 17, 2023
6d0511f
nixos/tests/containers-next/basic: clean up
Ma27 Feb 17, 2023
29bb8dc
nixos/tests/containers-next: rm skipLint
Ma27 Feb 17, 2023
d0c7529
nixos: use mdDoc for rfc108 related changes
Ma27 Feb 18, 2023
f4e5691
nixos/containers-next: remove `rendered` option
Ma27 Feb 19, 2023
d6dded1
nixos/containers-next: remove `|| true` from creation of `/etc/{os-re…
Ma27 Feb 19, 2023
6ba0180
nixos/tests/containers-next/config-activation: remove unneeded f-str …
Ma27 Feb 19, 2023
c050ae4
nixos/systemd-nspawn: Updates to switch-to-configuration.pl
m1cr0man Mar 31, 2023
d39b85f
nixos/switch-to-configuration: query active nspawn instance names via…
Ma27 Apr 2, 2023
4611773
Merge branch 'master' into networkd-containers
Ma27 Apr 2, 2023
08b30c7
nixos/tests/containers-next: fix handling of underscores in container…
Ma27 Apr 3, 2023
a76c41e
nixos/switch-to-configuration: fix comment position
Ma27 Apr 3, 2023
4f4c56d
nixos/tests/containers-next: fix test
Ma27 Apr 3, 2023
8cc3b52
nixos/containers-next: minor refactorings / cleanups
Ma27 Apr 3, 2023
b418f0e
nixos/containers-next: simplify networkd expressions, prohibit contai…
Ma27 Apr 4, 2023
ddd47d6
nixos/tests: default.nix for containers-next
Ma27 Apr 4, 2023
bac3021
nixos/containers-next: add support for v6 nat
Ma27 Apr 4, 2023
71d3cd8
nixos/containers-next: simplify / refactor tests
Ma27 Apr 4, 2023
60f41e6
nixos/containers-next: make start timeout configurable
Ma27 Apr 4, 2023
5b8eb90
nixos/containers-next: fix bind-mounts of daemon-socket
Ma27 Apr 4, 2023
5d7d31e
nixos/containers-next: only enable DHCP for a container's host0 if ne…
Ma27 Apr 4, 2023
d20ccb1
nixos/containers-next: test privateuserschown on container migration
Ma27 Apr 4, 2023
d09cddd
nixos/containers-next: fix manual build
Ma27 Apr 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions jobset.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# FIXME remove before merging!

{ nixpkgs }:
Ma27 marked this conversation as resolved.
Show resolved Hide resolved
let
release = import ./nixos/release.nix {
supportedSystems = [ "x86_64-linux" ];
inherit nixpkgs;
};
in

{
container-tests = {
general = release.tests.containers-next;
migration = release.tests.containers-migration;
activation = release.tests.containers-config-activation;
imperative = release.tests.containers-next-imperative;
};
}
9 changes: 9 additions & 0 deletions nixos/lib/test-driver/test_driver/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,15 @@ def systemctl(self, q: str, user: Optional[str] = None) -> Tuple[int, str]:
)
return self.execute("systemctl {}".format(q))

def wait_until_unit_stops(self, unit: str) -> None:
def wait_inactive(_: Any) -> bool:
info = self.get_unit_info(unit)
state = info["ActiveState"]
return state == "inactive"

with self.nested(f"waiting for unit '{unit}' to stop"):
retry(wait_inactive)

def require_unit_state(self, unit: str, require_state: str = "active") -> None:
with self.nested(
"checking if unit ‘{}’ has reached state '{}'".format(unit, require_state)
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,7 @@
./virtualisation/container-config.nix
./virtualisation/containerd.nix
./virtualisation/containers.nix
./virtualisation/containers-next
./virtualisation/nixos-containers.nix
./virtualisation/oci-containers.nix
./virtualisation/cri-o.nix
Expand Down
130 changes: 125 additions & 5 deletions nixos/modules/system/activation/switch-to-configuration.pl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Net::DBus;
use Sys::Syslog qw(:standard :macros);
use Cwd 'abs_path';
use experimental 'smartmatch';

my $out = "@out@";

Expand Down Expand Up @@ -128,6 +129,24 @@ sub parseKeyValues {
}
}

sub parseNspawn {
my ($filename) = @_;
my $info = {};
parseKeyValuesArray($info, read_file($filename));
return $info;
}

sub parseKeyValuesArray {
my $info = shift;
foreach my $line (@_) {
$line =~ /^([^=]+)=(.*)$/ or next;
unless (exists $info->{$1}) {
$info->{$1} = ();
}
push @{$info->{$1}}, $2;
}
}

sub boolIsTrue {
my ($s) = @_;
return $s eq "yes" || $s eq "true";
Expand Down Expand Up @@ -209,11 +228,15 @@ sub handleModifiedUnit {
# We write this to a file to ensure that the
# service gets restarted if we're interrupted.
if (!$socketActivated) {
$unitsToStart->{$unit} = 1;
recordUnit($startListFile, $unit);
if (index($unit, "systemd-nspawn@") == -1) {
$unitsToStart->{$unit} = 1;
recordUnit($startListFile, $unit);
}
}

$unitsToStop->{$unit} = 1;
if (index($unit, "systemd-nspawn@") == -1) {
$unitsToStop->{$unit} = 1;
}
}
}
}
Expand All @@ -233,6 +256,86 @@ sub handleModifiedUnit {
$unitsToReload{$_} = 1 foreach
split('\n', read_file($reloadListFile, err_mode => 'quiet') // "");


sub deepCmp {
my ($a, $b) = @_;
if (@$a != @$b) {
return 1;
}
foreach (my $i = 0; $i < @$a; $i++) {
if (@$a[$i] ne @$b[$i]) {
return 1;
}
}
return 0;
}

sub compareNspawnUnits {
my ($old, $new) = @_;
my $contentsOld = parseNspawn($old);
my $contentsNew = parseNspawn($new);

foreach (keys %$contentsOld) {
my $oldKey = $_;
foreach (keys %$contentsNew) {
my $newKey = $_;
next if $newKey ne $oldKey
or $newKey eq 'Parameters'
or $newKey eq 'X-ActivationStrategy';

if (deepCmp($contentsOld->{$oldKey}, $contentsNew->{$newKey}) != 0) {
return (1, $contentsNew->{'X-ActivationStrategy'}[0] // "dynamic");
}
}
}

return (0, $contentsNew->{'X-ActivationStrategy'}[0] // "dynamic");
}

my $activeContainersOut = `machinectl list`;
sub isContainerRunning {
my ($name) = @_;
if (index($activeContainersOut, $name) != -1) {
return 1;
}
return 0;
}

my @currentNspawnUnits = glob("/etc/systemd/nspawn/*.nspawn");
Ma27 marked this conversation as resolved.
Show resolved Hide resolved
my @upcomingNspawnUnits = glob("$out/etc/systemd/nspawn/*.nspawn");
foreach (@upcomingNspawnUnits) {
my $unit = basename($_);
$unit =~ s/\.nspawn//;
my $unitName = "systemd-nspawn\@$unit.service";
my $orig = $_;
$orig =~ s/^$out//;
if ($orig ~~ @currentNspawnUnits) {
if (fingerprintUnit($_) ne fingerprintUnit($orig)) {
my ($eq, $strategy) = compareNspawnUnits($orig, $_);
if ($strategy ne "none") {
if ($strategy ne "restart" and ($eq == 0 or $strategy eq "reload")) {
if (isContainerRunning($unit) == 1) {
$unitsToReload{$unitName} = 1;
}
} elsif ($eq == 1) {
$unitsToRestart{$unitName} = 1;
}
}
}
} else {
$unitsToStart{$unitName} = 1;
}
}

foreach (@currentNspawnUnits) {
unless (-f "$out$_") {
my $unit = basename($_);
$unit =~ s/\.nspawn//;
my $unitName = "systemd-nspawn\@$unit.service";
$unitsToStop{$unitName} = 1;
}
}

my $activePrev = getActiveUnits;
while (my ($unit, $state) = each %{$activePrev}) {
my $baseUnit = $unit;
Expand Down Expand Up @@ -477,8 +580,25 @@ sub filterUnits {
# Reload units that need it. This includes remounting changed mount
# units.
if (scalar(keys %unitsToReload) > 0) {
print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n";
system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4;
my @to_reload = sort(keys %unitsToReload);
my (@services, @containers);
print STDERR "reloading the following units: ", join(", ", @to_reload), "\n";
foreach my $s (@to_reload) {
if (index($s, "systemd-nspawn@") == 0) {
push @containers, $s;
} else {
push @services, $s;
}
}

# Reloading containers & dbus.service in the same transaction causes
# the system to stall for about 1 minute.
if (scalar(@services) > 0) {
system("@systemd@/bin/systemctl", "reload", "--", @services) == 0 or $res = 4;
}
if (scalar(@containers) > 0) {
system("@systemd@/bin/systemctl", "reload", "--", @containers) == 0 or $res = 4;
}
unlink($reloadListFile);
unlink($reloadByActivationFile);
}
Expand Down
73 changes: 50 additions & 23 deletions nixos/modules/system/boot/systemd-nspawn.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ with lib;

let
cfg = config.systemd.nspawn;

checkExec = checkUnitConfig "Exec" [
(assertOnlyFields [
"Boot" "ProcessTwo" "Parameters" "Environment" "User" "WorkingDirectory"
Expand All @@ -16,7 +15,7 @@ let
"LimitNOFILE" "LimitAS" "LimitNPROC" "LimitMEMLOCK" "LimitLOCKS"
"LimitSIGPENDING" "LimitMSGQUEUE" "LimitNICE" "LimitRTPRIO" "LimitRTTIME"
"OOMScoreAdjust" "CPUAffinity" "Hostname" "ResolvConf" "Timezone"
"LinkJournal"
"LinkJournal" "Ephemeral" "X-ActivationStrategy"
])
(assertValueOneOf "Boot" boolValues)
(assertValueOneOf "ProcessTwo" boolValues)
Expand Down Expand Up @@ -79,24 +78,57 @@ let
<manvolnum>5</manvolnum></citerefentry> for details.
'';
};

extraDrvConfig = mkOption {
type = types.nullOr types.package;
default = null;
description = ''
Extra config for an nspawn-unit that is generated via `nix-build`.
This is necessary since nspawn doesn't support overrides in
<literal>/etc/systemd/nspawn</literal> natively and sometimes a derivation
is needed for configs (e.g. to determine all needed store-paths to bind-mount
into a machine).
'';
};
};

};

makeUnit' = name: def:
if def.extraDrvConfig == null || !def.enable
then pkgs.runCommand "nspawn-inst" { } ("cat ${makeUnit name def}/${shellEscape name} > $out")
else pkgs.runCommand "nspawn-${mkPathSafeName name}-custom"
{ preferLocalBuild = true;
allowSubstitutes = false;
} (let
name' = shellEscape name;
in ''
if [ ! -f "${def.extraDrvConfig}" ]; then
echo "systemd.nspawn.${name}.extraDrvConfig is not a file!"
exit 1
fi

touch $out
cat ${makeUnit name def}/${name'} > $out
cat ${def.extraDrvConfig} >> $out
'');

instanceToUnit = name: def:
let base = {
text = ''
[Exec]
${attrsToSection def.execConfig}
let
base = {
text = ''
[Exec]
${attrsToSection def.execConfig}

[Files]
${attrsToSection def.filesConfig}
[Files]
${attrsToSection def.filesConfig}

[Network]
${attrsToSection def.networkConfig}
'';
} // def;
in base // { unit = makeUnit name base; };
[Network]
${attrsToSection def.networkConfig}
'';
} // (filterAttrs (n: const (elem n optWhitelist)) def);
optWhitelist = [ "extraDrvConfig" "enable" ];
in makeUnit' name base;

in {

Expand All @@ -112,22 +144,17 @@ in {

config =
let
units = mapAttrs' (n: v: let nspawnFile = "${n}.nspawn"; in nameValuePair nspawnFile (instanceToUnit nspawnFile v)) cfg;
units = mapAttrs' (name: value: {
name = "systemd/nspawn/${name}.nspawn";
value.source = instanceToUnit "${name}.nspawn" value;
}) cfg;
in
mkMerge [
(mkIf (cfg != {}) {
environment.etc."systemd/nspawn".source = mkIf (cfg != {}) (generateUnits' false "nspawn" units [] []);
environment.etc = units;
})
{
systemd.targets.multi-user.wants = [ "machines.target" ];

# Workaround for https://github.com/NixOS/nixpkgs/pull/67232#issuecomment-531315437 and https://github.com/systemd/systemd/issues/13622
# Once systemd fixes this upstream, we can re-enable -U
systemd.services."systemd-nspawn@".serviceConfig.ExecStart = [
"" # deliberately empty. signals systemd to override the ExecStart
# Only difference between upstream is that we do not pass the -U flag
"${config.systemd.package}/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth --settings=override --machine=%i"
];
}
];
}
12 changes: 6 additions & 6 deletions nixos/modules/tasks/filesystems.nix
Original file line number Diff line number Diff line change
Expand Up @@ -365,19 +365,19 @@ in

# Sync mount options with systemd's src/core/mount-setup.c: mount_table.
boot.specialFileSystems = {
"/proc" = { fsType = "proc"; options = [ "nosuid" "noexec" "nodev" ]; };
"/run" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=755" "size=${config.boot.runSize}" ]; };
"/dev" = { fsType = "devtmpfs"; options = [ "nosuid" "strictatime" "mode=755" "size=${config.boot.devSize}" ]; };
"/dev/shm" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=1777" "size=${config.boot.devShmSize}" ]; };
"/dev/pts" = { fsType = "devpts"; options = [ "nosuid" "noexec" "mode=620" "ptmxmode=0666" "gid=${toString config.ids.gids.tty}" ]; };

# To hold secrets that shouldn't be written to disk
"/run/keys" = { fsType = "ramfs"; options = [ "nosuid" "nodev" "mode=750" ]; };
} // optionalAttrs (!config.boot.isContainer) {
# systemd-nspawn populates /sys by itself, and remounting it causes all
# kinds of weird issues (most noticeably, waiting for host disk device
# nodes).
"/sys" = { fsType = "sysfs"; options = [ "nosuid" "noexec" "nodev" ]; };

"/proc" = { fsType = "proc"; options = [ "nosuid" "noexec" "nodev" ]; };
"/run" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=755" "size=${config.boot.runSize}" ]; };
"/dev" = { fsType = "devtmpfs"; options = [ "nosuid" "strictatime" "mode=755" "size=${config.boot.devSize}" ]; };
"/dev/shm" = { fsType = "tmpfs"; options = [ "nosuid" "nodev" "strictatime" "mode=1777" "size=${config.boot.devShmSize}" ]; };
"/dev/pts" = { fsType = "devpts"; options = [ "nosuid" "noexec" "mode=620" "ptmxmode=0666" "gid=${toString config.ids.gids.tty}" ]; };
};

};
Expand Down
2 changes: 1 addition & 1 deletion nixos/modules/tasks/network-interfaces.nix
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ in
type = types.bool;
default = false;
description = ''
In containers, whether to use the
<emphasis>Deprecated:</emphasis> in containers, whether to use the
<filename>resolv.conf</filename> supplied by the host.
'';
};
Expand Down
29 changes: 29 additions & 0 deletions nixos/modules/virtualisation/containers-next/container-profile.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{ pkgs, lib, ... }: with lib; {
boot.isContainer = true;

# We need a static libsudoers if we bind-mount into a user-namespaced
# container since the bind-mounts are owned by `nouser:nogroup` then (including
# `/nix/store`) and this doesn't like sudo.
security.sudo.package = mkDefault pkgs.sudo-nspawn;

# Containers are supposed to use systemd-networkd to have a proper
# networking stack even during boot-up.
networking = {
useHostResolvConf = false;
useDHCP = false;
useNetworkd = true;
};
systemd.network.networks."20-host0" = {
matchConfig = {
Virtualization = "container";
Name = "host0";
};
dhcpConfig.UseTimezone = "yes";
networkConfig = {
DHCP = "yes";
LLDP = "yes";
EmitLLDP = "customer-bridge";
LinkLocalAddressing = mkDefault "ipv6";
};
};
}
Loading