1# Systemd services for docker.
2
3{ config, lib, pkgs, ... }:
4
5with lib;
6
7let
8
9 cfg = config.virtualisation.docker;
10 proxy_env = config.networking.proxy.envVars;
11
12in
13
14{
15 ###### interface
16
17 options.virtualisation.docker = {
18 enable =
19 mkOption {
20 type = types.bool;
21 default = false;
22 description =
23 ''
24 This option enables docker, a daemon that manages
25 linux containers. Users in the "docker" group can interact with
26 the daemon (e.g. to start or stop containers) using the
27 <command>docker</command> command line tool.
28 '';
29 };
30
31 listenOptions =
32 mkOption {
33 type = types.listOf types.str;
34 default = ["/run/docker.sock"];
35 description =
36 ''
37 A list of unix and tcp docker should listen to. The format follows
38 ListenStream as described in systemd.socket(5).
39 '';
40 };
41
42 enableOnBoot =
43 mkOption {
44 type = types.bool;
45 default = true;
46 description =
47 ''
48 When enabled dockerd is started on boot. This is required for
49 containers which are created with the
50 <literal>--restart=always</literal> flag to work. If this option is
51 disabled, docker might be started on demand by socket activation.
52 '';
53 };
54
55 enableNvidia =
56 mkOption {
57 type = types.bool;
58 default = false;
59 description = ''
60 Enable nvidia-docker wrapper, supporting NVIDIA GPUs inside docker containers.
61 '';
62 };
63
64 liveRestore =
65 mkOption {
66 type = types.bool;
67 default = true;
68 description =
69 ''
70 Allow dockerd to be restarted without affecting running container.
71 This option is incompatible with docker swarm.
72 '';
73 };
74
75 storageDriver =
76 mkOption {
77 type = types.nullOr (types.enum ["aufs" "btrfs" "devicemapper" "overlay" "overlay2" "zfs"]);
78 default = null;
79 description =
80 ''
81 This option determines which Docker storage driver to use. By default
82 it let's docker automatically choose preferred storage driver.
83 '';
84 };
85
86 logDriver =
87 mkOption {
88 type = types.enum ["none" "json-file" "syslog" "journald" "gelf" "fluentd" "awslogs" "splunk" "etwlogs" "gcplogs"];
89 default = "journald";
90 description =
91 ''
92 This option determines which Docker log driver to use.
93 '';
94 };
95
96 extraOptions =
97 mkOption {
98 type = types.separatedString " ";
99 default = "";
100 description =
101 ''
102 The extra command-line options to pass to
103 <command>docker</command> daemon.
104 '';
105 };
106
107 autoPrune = {
108 enable = mkOption {
109 type = types.bool;
110 default = false;
111 description = ''
112 Whether to periodically prune Docker resources. If enabled, a
113 systemd timer will run <literal>docker system prune -f</literal>
114 as specified by the <literal>dates</literal> option.
115 '';
116 };
117
118 flags = mkOption {
119 type = types.listOf types.str;
120 default = [];
121 example = [ "--all" ];
122 description = ''
123 Any additional flags passed to <command>docker system prune</command>.
124 '';
125 };
126
127 dates = mkOption {
128 default = "weekly";
129 type = types.str;
130 description = ''
131 Specification (in the format described by
132 <citerefentry><refentrytitle>systemd.time</refentrytitle>
133 <manvolnum>7</manvolnum></citerefentry>) of the time at
134 which the prune will occur.
135 '';
136 };
137 };
138
139 package = mkOption {
140 default = pkgs.docker;
141 defaultText = literalExpression "pkgs.docker";
142 type = types.package;
143 example = literalExpression "pkgs.docker-edge";
144 description = ''
145 Docker package to be used in the module.
146 '';
147 };
148 };
149
150 ###### implementation
151
152 config = mkIf cfg.enable (mkMerge [{
153 boot.kernelModules = [ "bridge" "veth" ];
154 boot.kernel.sysctl = {
155 "net.ipv4.conf.all.forwarding" = mkOverride 98 true;
156 "net.ipv4.conf.default.forwarding" = mkOverride 98 true;
157 };
158 environment.systemPackages = [ cfg.package ]
159 ++ optional cfg.enableNvidia pkgs.nvidia-docker;
160 users.groups.docker.gid = config.ids.gids.docker;
161 systemd.packages = [ cfg.package ];
162
163 systemd.services.docker = {
164 wantedBy = optional cfg.enableOnBoot "multi-user.target";
165 after = [ "network.target" "docker.socket" ];
166 requires = [ "docker.socket" ];
167 environment = proxy_env;
168 serviceConfig = {
169 Type = "notify";
170 ExecStart = [
171 ""
172 ''
173 ${cfg.package}/bin/dockerd \
174 --group=docker \
175 --host=fd:// \
176 --log-driver=${cfg.logDriver} \
177 ${optionalString (cfg.storageDriver != null) "--storage-driver=${cfg.storageDriver}"} \
178 ${optionalString cfg.liveRestore "--live-restore" } \
179 ${optionalString cfg.enableNvidia "--add-runtime nvidia=${pkgs.nvidia-docker}/bin/nvidia-container-runtime" } \
180 ${cfg.extraOptions}
181 ''];
182 ExecReload=[
183 ""
184 "${pkgs.procps}/bin/kill -s HUP $MAINPID"
185 ];
186 };
187
188 path = [ pkgs.kmod ] ++ optional (cfg.storageDriver == "zfs") pkgs.zfs
189 ++ optional cfg.enableNvidia pkgs.nvidia-docker;
190 };
191
192 systemd.sockets.docker = {
193 description = "Docker Socket for the API";
194 wantedBy = [ "sockets.target" ];
195 socketConfig = {
196 ListenStream = cfg.listenOptions;
197 SocketMode = "0660";
198 SocketUser = "root";
199 SocketGroup = "docker";
200 };
201 };
202
203 systemd.services.docker-prune = {
204 description = "Prune docker resources";
205
206 restartIfChanged = false;
207 unitConfig.X-StopOnRemoval = false;
208
209 serviceConfig.Type = "oneshot";
210
211 script = ''
212 ${cfg.package}/bin/docker system prune -f ${toString cfg.autoPrune.flags}
213 '';
214
215 startAt = optional cfg.autoPrune.enable cfg.autoPrune.dates;
216 };
217
218 assertions = [
219 { assertion = cfg.enableNvidia -> config.hardware.opengl.driSupport32Bit or false;
220 message = "Option enableNvidia requires 32bit support libraries";
221 }];
222 }
223 ]);
224
225 imports = [
226 (mkRemovedOptionModule ["virtualisation" "docker" "socketActivation"] "This option was removed and socket activation is now always active")
227 ];
228
229}