summary refs log tree commit diff
diff options
context:
space:
mode:
authorNikita Uvarov <uv.nikita@gmail.com>2019-08-18 21:37:38 +0200
committerNikita Uvarov <uv.nikita@gmail.com>2019-08-19 15:21:35 +0200
commitc740f0d4003330cd902de72fdb124ce276616d33 (patch)
tree4ee30c3821f775f73d55fc41f5cf3d7e0755d1fd
parent44099371b245326a86370a92f5ee0f17a491d764 (diff)
downloadnixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.tar
nixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.tar.gz
nixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.tar.bz2
nixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.tar.lz
nixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.tar.xz
nixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.tar.zst
nixpkgs-c740f0d4003330cd902de72fdb124ce276616d33.zip
nixos/containers: add 'ephemeral' option
-rw-r--r--nixos/modules/virtualisation/containers.nix36
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/containers-ephemeral.nix56
3 files changed, 86 insertions, 7 deletions
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index c10e2b162cc..e1a91f7704e 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -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
             {
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index c24c8ae61a5..166816777f3 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -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 {};
diff --git a/nixos/tests/containers-ephemeral.nix b/nixos/tests/containers-ephemeral.nix
new file mode 100644
index 00000000000..1ef8717d9a0
--- /dev/null
+++ b/nixos/tests/containers-ephemeral.nix
@@ -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");
+  '';
+})