From 14ce29fd6ca4a3d145e065030466e7cc666212e2 Mon Sep 17 00:00:00 2001 From: chn Date: Wed, 16 Aug 2023 19:51:55 +0800 Subject: [PATCH] add rootless docker --- modules/services/default.nix | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/modules/services/default.nix b/modules/services/default.nix index 506260bb..7afd0dac 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -119,6 +119,36 @@ inputs: postgresql.enable = mkOption { type = types.bool; default = false; }; rsshub.enable = mkOption { type = types.bool; default = false; }; wallabag.enable = mkOption { type = types.bool; default = false; }; + docker = mkOption + { + type = types.attrsOf (types.submodule (inputs: { options = + { + user = mkOption { type = types.nullOr types.nonEmptyStr; default = inputs.config._module.args.name; }; + image = mkOption { type = types.package; }; + imageName = mkOption + { + type = types.nonEmptyStr; + default = "${inputs.image.imageName}:${inputs.image.imageTag}"; + }; + ports = mkOption + { + type = types.listOf (types.oneOf + [ + types.ints.unsigned + types.submodule (inputs: { options = + { + hostIp = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; }; + hostPort = mkOption { type = types.ints.unsigned; }; + containerPort = mkOption { type = types.ints.unsigned; }; + protocol = mkOption { type = types.enum [ "tcp" "udp" ]; default = "tcp"; }; + };}) + ]); + default = []; + }; + environmentFile = mkOption { type = types.oneOf [ types.bool types.nonEmptyStr ]; default = false; }; + };})); + default = {}; + }; }; config = let @@ -1174,5 +1204,64 @@ inputs: # }; } ) + ( + mkMerge + ( + (map + (container: + { + virtualisation.oci-containers.containers.${container.name} = + { + image = container.value.imageName; + imageFile = container.value.image; + ports = map + (port: + ( + if builtins.typeOf port == "int" then "127.0.0.1::${toString port}" + else ("${port.value.hostIp}:${toString port.value.hostPort}" + + ":${toString port.value.containerPort}/${port.value.protocol}") + )) + container.value.ports; + extraOptions = [ "--add-host=host.docker.internal:host-gateway" ]; + environmentFiles = + if builtins.typeOf container.value.environmentFile == "bool" && container.value.environmentFile + then [ inputs.config.sops.templates."${container.name}/env".path ] + else if builtins.typeOf container.value.environmentFile == "bool" then [] + else [ container.value.environmentFile ]; + }; + systemd = + { + tmpfiles.rules = [ "d /var/run/docker-rootless 0777" ]; + services = + { + "docker-${container.value.user}-daemon" = + { + wantedBy = [ "multi-user.target" ]; + inherit (inputs.systemd.user.services.docker) description path; + serviceConfig = inputs.systemd.user.services.docker.serviceConfig // + { + User = container.value.user; + Group = container.value.user; + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + ExecStart = inputs.systemd.user.services.docker.serviceConfig.ExecStart + + " -H unix:///var/run/docker-rootless/${container.value.user}.sock"; + }; + unitConfig = { inherit (inputs.systemd.user.services.docker.unitConfig) StartLimitInterval; }; + }; + "docker-${container.name}" = + { + requires = [ "docker-${container.value.user}-daemon.service" ]; + after = [ "docker-${container.value.user}-daemon.service" ]; + environment.DOCKER_HOST = "unix:///var/run/docker-rootless/${container.value.user}.sock"; + serviceConfig = { User = container.value.user; Group = container.value.user; }; + }; + }; + }; + + }) + (attrsToList services.docker.containers)) + ++ [{ nixos.virtualization.docker.enable = true; }] + ) + ) ]; }