Merge pull request #66846 from uvNikita/containers/ephemeral

nixos/containers: add 'ephemeral' option
This commit is contained in:
Marek Mahut 2019-08-19 20:55:33 +02:00 committed by GitHub
commit 94c51859df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 86 additions and 7 deletions

View File

@ -70,7 +70,7 @@ let
startScript = cfg: startScript = cfg:
'' ''
mkdir -p -m 0755 "$root/etc" "$root/var/lib" 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 if ! [ -e "$root/etc/os-release" ]; then
touch "$root/etc/os-release" touch "$root/etc/os-release"
fi fi
@ -138,7 +138,7 @@ let
--bind-ro=/nix/var/nix/daemon-socket \ --bind-ro=/nix/var/nix/daemon-socket \
--bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \ --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
--bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \ --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 PRIVATE_NETWORK="$PRIVATE_NETWORK" \
--setenv HOST_BRIDGE="$HOST_BRIDGE" \ --setenv HOST_BRIDGE="$HOST_BRIDGE" \
--setenv HOST_ADDRESS="$HOST_ADDRESS" \ --setenv HOST_ADDRESS="$HOST_ADDRESS" \
@ -147,6 +147,7 @@ let
--setenv LOCAL_ADDRESS6="$LOCAL_ADDRESS6" \ --setenv LOCAL_ADDRESS6="$LOCAL_ADDRESS6" \
--setenv HOST_PORT="$HOST_PORT" \ --setenv HOST_PORT="$HOST_PORT" \
--setenv PATH="$PATH" \ --setenv PATH="$PATH" \
${optionalString cfg.ephemeral "--ephemeral"} \
${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then ${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then
''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else "" ''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else ""
} \ } \
@ -247,6 +248,8 @@ let
Type = "notify"; Type = "notify";
RuntimeDirectory = [ "containers" ] ++ lib.optional cfg.ephemeral "containers/%i";
# Note that on reboot, systemd-nspawn returns 133, so this # Note that on reboot, systemd-nspawn returns 133, so this
# unit will be restarted. On poweroff, it returns 0, so the # unit will be restarted. On poweroff, it returns 0, so the
# unit won't be restarted. # unit won't be restarted.
@ -419,6 +422,7 @@ let
{ {
extraVeths = {}; extraVeths = {};
additionalCapabilities = []; additionalCapabilities = [];
ephemeral = false;
allowedDevices = []; allowedDevices = [];
hostAddress = null; hostAddress = null;
hostAddress6 = null; hostAddress6 = null;
@ -511,6 +515,26 @@ in
information. 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 { enableTun = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@ -659,13 +683,8 @@ in
unit = { unit = {
description = "Container '%i'"; description = "Container '%i'";
unitConfig.RequiresMountsFor = [ "/var/lib/containers/%i" ];
path = [ pkgs.iproute ]; path = [ pkgs.iproute ];
environment.INSTANCE = "%i";
environment.root = "/var/lib/containers/%i";
preStart = preStartScript dummyConfig; preStart = preStartScript dummyConfig;
script = startScript dummyConfig; script = startScript dummyConfig;
@ -708,6 +727,9 @@ in
script = startScript containerConfig; script = startScript containerConfig;
postStart = postStartScript containerConfig; postStart = postStartScript containerConfig;
serviceConfig = serviceDirectives 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 if containerConfig.autoStart then
{ {

View File

@ -47,6 +47,7 @@ in
codimd = handleTest ./codimd.nix {}; codimd = handleTest ./codimd.nix {};
colord = handleTest ./colord.nix {}; colord = handleTest ./colord.nix {};
containers-bridge = handleTest ./containers-bridge.nix {}; containers-bridge = handleTest ./containers-bridge.nix {};
containers-ephemeral = handleTest ./containers-ephemeral.nix {};
containers-extra_veth = handleTest ./containers-extra_veth.nix {}; containers-extra_veth = handleTest ./containers-extra_veth.nix {};
containers-hosts = handleTest ./containers-hosts.nix {}; containers-hosts = handleTest ./containers-hosts.nix {};
containers-imperative = handleTest ./containers-imperative.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");
'';
})