docker-rootless service: init

Changed files
+150
nixos
doc
manual
from_md
release-notes
release-notes
modules
tests
+8
nixos/doc/manual/from_md/release-notes/rl-2205.section.xml
···
</listitem>
<listitem>
<para>
+
<link xlink:href="https://docs.docker.com/engine/security/rootless/">rootless
+
Docker</link>, a <literal>systemd --user</literal> Docker
+
service which runs without root permissions. Available as
+
<link xlink:href="options.html#opt-virtualisation.docker.rootless.enable">virtualisation.docker.rootless.enable</link>.
+
</para>
+
</listitem>
+
<listitem>
+
<para>
<link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html">filebeat</link>,
a lightweight shipper for forwarding and centralizing log
data. Available as
+1
nixos/doc/manual/release-notes/rl-2205.section.md
···
## New Services {#sec-release-22.05-new-services}
- [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable).
+
- [rootless Docker](https://docs.docker.com/engine/security/rootless/), a `systemd --user` Docker service which runs without root permissions. Available as [virtualisation.docker.rootless.enable](options.html#opt-virtualisation.docker.rootless.enable).
- [filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html), a lightweight shipper for forwarding and centralizing log data. Available as [services.filebeat](#opt-services.filebeat.enable).
+1
nixos/modules/module-list.nix
···
./virtualisation/oci-containers.nix
./virtualisation/cri-o.nix
./virtualisation/docker.nix
+
./virtualisation/docker-rootless.nix
./virtualisation/ecs-agent.nix
./virtualisation/libvirtd.nix
./virtualisation/lxc.nix
+98
nixos/modules/virtualisation/docker-rootless.nix
···
+
{ config, lib, pkgs, ... }:
+
+
with lib;
+
+
let
+
+
cfg = config.virtualisation.docker.rootless;
+
proxy_env = config.networking.proxy.envVars;
+
settingsFormat = pkgs.formats.json {};
+
daemonSettingsFile = settingsFormat.generate "daemon.json" cfg.daemon.settings;
+
+
in
+
+
{
+
###### interface
+
+
options.virtualisation.docker.rootless = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
This option enables docker in a rootless mode, a daemon that manages
+
linux containers. To interact with the daemon, one needs to set
+
<command>DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock</command>.
+
'';
+
};
+
+
setSocketVariable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Point <command>DOCKER_HOST</command> to rootless Docker instance for
+
normal users by default.
+
'';
+
};
+
+
daemon.settings = mkOption {
+
type = settingsFormat.type;
+
default = { };
+
example = {
+
ipv6 = true;
+
"fixed-cidr-v6" = "fd00::/80";
+
};
+
description = ''
+
Configuration for docker daemon. The attributes are serialized to JSON used as daemon.conf.
+
See https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file
+
'';
+
};
+
+
package = mkOption {
+
default = pkgs.docker;
+
defaultText = literalExpression "pkgs.docker";
+
type = types.package;
+
example = literalExpression "pkgs.docker-edge";
+
description = ''
+
Docker package to be used in the module.
+
'';
+
};
+
};
+
+
###### implementation
+
+
config = mkIf cfg.enable {
+
environment.systemPackages = [ cfg.package ];
+
+
environment.extraInit = optionalString cfg.setSocketVariable ''
+
if [ -z "$DOCKER_HOST" -a -n "$XDG_RUNTIME_DIR" ]; then
+
export DOCKER_HOST="unix://$XDG_RUNTIME_DIR/docker.sock"
+
fi
+
'';
+
+
# Taken from https://github.com/moby/moby/blob/master/contrib/dockerd-rootless-setuptool.sh
+
systemd.user.services.docker = {
+
wantedBy = [ "default.target" ];
+
description = "Docker Application Container Engine (Rootless)";
+
# needs newuidmap from pkgs.shadow
+
path = [ "/run/wrappers" ];
+
environment = proxy_env;
+
unitConfig.StartLimitInterval = "60s";
+
serviceConfig = {
+
Type = "notify";
+
ExecStart = "${cfg.package}/bin/dockerd-rootless --config-file=${daemonSettingsFile}";
+
ExecReload = "${pkgs.procps}/bin/kill -s HUP $MAINPID";
+
TimeoutSec = 0;
+
RestartSec = 2;
+
Restart = "always";
+
StartLimitBurst = 3;
+
LimitNOFILE = "infinity";
+
LimitNPROC = "infinity";
+
LimitCORE = "infinity";
+
Delegate = true;
+
NotifyAccess = "all";
+
KillMode = "mixed";
+
};
+
};
+
};
+
+
}
+1
nixos/tests/all-tests.nix
···
dnscrypt-wrapper = handleTestOn ["x86_64-linux"] ./dnscrypt-wrapper {};
doas = handleTest ./doas.nix {};
docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
+
docker-rootless = handleTestOn ["x86_64-linux"] ./docker-rootless.nix {};
docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
docker-registry = handleTest ./docker-registry.nix {};
docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
+41
nixos/tests/docker-rootless.nix
···
+
# This test runs docker and checks if simple container starts
+
+
import ./make-test-python.nix ({ lib, pkgs, ...} : {
+
name = "docker-rootless";
+
meta = with pkgs.lib.maintainers; {
+
maintainers = [ abbradar ];
+
};
+
+
nodes = {
+
machine = { pkgs, ... }: {
+
virtualisation.docker.rootless.enable = true;
+
+
users.users.alice = {
+
uid = 1000;
+
isNormalUser = true;
+
};
+
};
+
};
+
+
testScript = { nodes, ... }:
+
let
+
user = nodes.machine.config.users.users.alice;
+
sudo = lib.concatStringsSep " " [
+
"XDG_RUNTIME_DIR=/run/user/${toString user.uid}"
+
"DOCKER_HOST=unix:///run/user/${toString user.uid}/docker.sock"
+
"sudo" "--preserve-env=XDG_RUNTIME_DIR,DOCKER_HOST" "-u" "alice"
+
];
+
in ''
+
machine.wait_for_unit("multi-user.target")
+
+
machine.succeed("loginctl enable-linger alice")
+
machine.wait_until_succeeds("${sudo} systemctl --user is-active docker.service")
+
+
machine.succeed("tar cv --files-from /dev/null | ${sudo} docker import - scratchimg")
+
machine.succeed(
+
"${sudo} docker run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
+
)
+
machine.succeed("${sudo} docker ps | grep sleeping")
+
machine.succeed("${sudo} docker stop sleeping")
+
'';
+
})