nixos/containers: add 'ephemeral' option

This commit is contained in:
Nikita Uvarov 2019-08-18 21:37:38 +02:00
parent 44099371b2
commit c740f0d400
No known key found for this signature in database
GPG Key ID: F7A5FB3A7C10EF96
3 changed files with 86 additions and 7 deletions

View File

@ -70,7 +70,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"
if ! [ -e "$root/etc/os-release" ]; then
touch "$root/etc/os-release"
fi
@ -138,7 +138,7 @@ let
--bind-ro=/nix/var/nix/daemon-socket \
--bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
--bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
--link-journal=try-guest \
${optionalString (!cfg.ephemeral) "--link-journal=try-guest"} \
--setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
--setenv HOST_BRIDGE="$HOST_BRIDGE" \
--setenv HOST_ADDRESS="$HOST_ADDRESS" \
@ -147,6 +147,7 @@ let
--setenv LOCAL_ADDRESS6="$LOCAL_ADDRESS6" \
--setenv HOST_PORT="$HOST_PORT" \
--setenv PATH="$PATH" \
${optionalString cfg.ephemeral "--ephemeral"} \
${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then
''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else ""
} \
@ -247,6 +248,8 @@ let
Type = "notify";
RuntimeDirectory = [ "containers" ] ++ lib.optional cfg.ephemeral "containers/%i";
# Note that on reboot, systemd-nspawn returns 133, so this
# unit will be restarted. On poweroff, it returns 0, so the
# unit won't be restarted.
@ -419,6 +422,7 @@ let
{
extraVeths = {};
additionalCapabilities = [];
ephemeral = false;
allowedDevices = [];
hostAddress = null;
hostAddress6 = null;
@ -511,6 +515,26 @@ in
information.
'';
};
ephemeral = mkOption {
type = types.bool;
default = false;
description = ''
Runs container in ephemeral mode with the empty root filesystem at boot.
This way container will be bootstrapped from scratch on each boot
and will be cleaned up on shutdown leaving no traces behind.
Useful for completely stateless, reproducible containers.
Note that this option might require to do some adjustments to the container configuration,
e.g. you might want to set
<varname>systemd.network.networks.$interface.dhcpConfig.ClientIdentifier</varname> to "mac"
if you use <varname>macvlans</varname> option.
This way dhcp client identifier will be stable between the container restarts.
Note that the container journal will not be linked to the host if this option is enabled.
'';
};
enableTun = mkOption {
type = types.bool;
default = false;
@ -659,13 +683,8 @@ in
unit = {
description = "Container '%i'";
unitConfig.RequiresMountsFor = [ "/var/lib/containers/%i" ];
path = [ pkgs.iproute ];
environment.INSTANCE = "%i";
environment.root = "/var/lib/containers/%i";
preStart = preStartScript dummyConfig;
script = startScript dummyConfig;
@ -708,6 +727,9 @@ 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";
environment.INSTANCE = "%i";
} // (
if containerConfig.autoStart then
{

View File

@ -47,6 +47,7 @@ in
codimd = handleTest ./codimd.nix {};
colord = handleTest ./colord.nix {};
containers-bridge = handleTest ./containers-bridge.nix {};
containers-ephemeral = handleTest ./containers-ephemeral.nix {};
containers-extra_veth = handleTest ./containers-extra_veth.nix {};
containers-hosts = handleTest ./containers-hosts.nix {};
containers-imperative = handleTest ./containers-imperative.nix {};

View File

@ -0,0 +1,56 @@
# Test for NixOS' container support.
import ./make-test.nix ({ pkgs, ...} : {
name = "containers-ephemeral";
machine = { pkgs, ... }: {
virtualisation.memorySize = 768;
virtualisation.writableStore = true;
containers.webserver = {
ephemeral = true;
privateNetwork = true;
hostAddress = "10.231.136.1";
localAddress = "10.231.136.2";
config = {
services.nginx = {
enable = true;
virtualHosts.localhost = {
root = (pkgs.runCommand "localhost" {} ''
mkdir "$out"
echo hello world > "$out/index.html"
'');
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
};
};
};
testScript = ''
$machine->succeed("nixos-container list") =~ /webserver/ or die;
# Start the webserver container.
$machine->succeed("nixos-container start webserver");
# Check that container got its own root folder
$machine->succeed("ls /run/containers/webserver");
# Check that container persistent directory is not created
$machine->fail("ls /var/lib/containers/webserver");
# Since "start" returns after the container has reached
# multi-user.target, we should now be able to access it.
my $ip = $machine->succeed("nixos-container show-ip webserver");
chomp $ip;
$machine->succeed("ping -n -c1 $ip");
$machine->succeed("curl --fail http://$ip/ > /dev/null");
# Stop the container.
$machine->succeed("nixos-container stop webserver");
$machine->fail("curl --fail --connect-timeout 2 http://$ip/ > /dev/null");
# Check that container's root folder was removed
$machine->fail("ls /run/containers/webserver");
'';
})