at 25.11-pre 11 kB view raw
1# Systemd services for docker. 2 3{ 4 config, 5 lib, 6 utils, 7 pkgs, 8 ... 9}: 10 11with lib; 12 13let 14 15 cfg = config.virtualisation.docker; 16 proxy_env = config.networking.proxy.envVars; 17 settingsFormat = pkgs.formats.json { }; 18 daemonSettingsFile = settingsFormat.generate "daemon.json" cfg.daemon.settings; 19in 20 21{ 22 ###### interface 23 24 options.virtualisation.docker = { 25 enable = mkOption { 26 type = types.bool; 27 default = false; 28 description = '' 29 This option enables docker, a daemon that manages 30 linux containers. Users in the "docker" group can interact with 31 the daemon (e.g. to start or stop containers) using the 32 {command}`docker` command line tool. 33 ''; 34 }; 35 36 listenOptions = mkOption { 37 type = types.listOf types.str; 38 default = [ "/run/docker.sock" ]; 39 description = '' 40 A list of unix and tcp docker should listen to. The format follows 41 ListenStream as described in {manpage}`systemd.socket(5)`. 42 ''; 43 }; 44 45 enableOnBoot = mkOption { 46 type = types.bool; 47 default = true; 48 description = '' 49 When enabled dockerd is started on boot. This is required for 50 containers which are created with the 51 `--restart=always` flag to work. If this option is 52 disabled, docker might be started on demand by socket activation. 53 ''; 54 }; 55 56 daemon.settings = mkOption { 57 type = types.submodule { 58 freeformType = settingsFormat.type; 59 options = { 60 live-restore = mkOption { 61 type = types.bool; 62 # Prior to NixOS 24.11, this was set to true by default, while upstream defaulted to false. 63 # Keep the option unset to follow upstream defaults 64 default = versionOlder config.system.stateVersion "24.11"; 65 defaultText = literalExpression "lib.versionOlder config.system.stateVersion \"24.11\""; 66 description = '' 67 Allow dockerd to be restarted without affecting running container. 68 This option is incompatible with docker swarm. 69 ''; 70 }; 71 }; 72 }; 73 default = { }; 74 example = { 75 ipv6 = true; 76 "live-restore" = true; 77 "fixed-cidr-v6" = "fd00::/80"; 78 }; 79 description = '' 80 Configuration for docker daemon. The attributes are serialized to JSON used as daemon.conf. 81 See https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file 82 ''; 83 }; 84 85 enableNvidia = mkOption { 86 type = types.bool; 87 default = false; 88 description = '' 89 **Deprecated**, please use hardware.nvidia-container-toolkit.enable instead. 90 91 Enable nvidia-docker wrapper, supporting NVIDIA GPUs inside docker containers. 92 ''; 93 }; 94 95 storageDriver = mkOption { 96 type = types.nullOr ( 97 types.enum [ 98 "aufs" 99 "btrfs" 100 "devicemapper" 101 "overlay" 102 "overlay2" 103 "zfs" 104 ] 105 ); 106 default = null; 107 description = '' 108 This option determines which Docker 109 [storage driver](https://docs.docker.com/storage/storagedriver/select-storage-driver/) 110 to use. 111 By default it lets docker automatically choose the preferred storage 112 driver. 113 However, it is recommended to specify a storage driver explicitly, as 114 docker's default varies over versions. 115 116 ::: {.warning} 117 Changing the storage driver will cause any existing containers 118 and images to become inaccessible. 119 ::: 120 ''; 121 }; 122 123 logDriver = mkOption { 124 type = types.enum [ 125 "none" 126 "json-file" 127 "syslog" 128 "journald" 129 "gelf" 130 "fluentd" 131 "awslogs" 132 "splunk" 133 "etwlogs" 134 "gcplogs" 135 "local" 136 ]; 137 default = "journald"; 138 description = '' 139 This option determines which Docker log driver to use. 140 ''; 141 }; 142 143 extraOptions = mkOption { 144 type = types.separatedString " "; 145 default = ""; 146 description = '' 147 The extra command-line options to pass to 148 {command}`docker` daemon. 149 ''; 150 }; 151 152 autoPrune = { 153 enable = mkOption { 154 type = types.bool; 155 default = false; 156 description = '' 157 Whether to periodically prune Docker resources. If enabled, a 158 systemd timer will run `docker system prune -f` 159 as specified by the `dates` option. 160 ''; 161 }; 162 163 flags = mkOption { 164 type = types.listOf types.str; 165 default = [ ]; 166 example = [ "--all" ]; 167 description = '' 168 Any additional flags passed to {command}`docker system prune`. 169 ''; 170 }; 171 172 dates = mkOption { 173 default = "weekly"; 174 type = types.str; 175 description = '' 176 Specification (in the format described by 177 {manpage}`systemd.time(7)`) of the time at 178 which the prune will occur. 179 ''; 180 }; 181 182 randomizedDelaySec = mkOption { 183 default = "0"; 184 type = types.singleLineStr; 185 example = "45min"; 186 description = '' 187 Add a randomized delay before each auto prune. 188 The delay will be chosen between zero and this value. 189 This value must be a time span in the format specified by 190 {manpage}`systemd.time(7)` 191 ''; 192 }; 193 194 persistent = mkOption { 195 default = true; 196 type = types.bool; 197 example = false; 198 description = '' 199 Takes a boolean argument. If true, the time when the service 200 unit was last triggered is stored on disk. When the timer is 201 activated, the service unit is triggered immediately if it 202 would have been triggered at least once during the time when 203 the timer was inactive. Such triggering is nonetheless 204 subject to the delay imposed by RandomizedDelaySec=. This is 205 useful to catch up on missed runs of the service when the 206 system was powered down. 207 ''; 208 }; 209 }; 210 211 package = mkPackageOption pkgs "docker" { }; 212 213 extraPackages = mkOption { 214 type = types.listOf types.package; 215 default = [ ]; 216 example = literalExpression "with pkgs; [ criu ]"; 217 description = '' 218 Extra packages to add to PATH for the docker daemon process. 219 ''; 220 }; 221 }; 222 223 imports = [ 224 (mkRemovedOptionModule [ 225 "virtualisation" 226 "docker" 227 "socketActivation" 228 ] "This option was removed and socket activation is now always active") 229 (mkAliasOptionModule 230 [ "virtualisation" "docker" "liveRestore" ] 231 [ "virtualisation" "docker" "daemon" "settings" "live-restore" ] 232 ) 233 ]; 234 235 ###### implementation 236 237 config = mkIf cfg.enable (mkMerge [ 238 { 239 boot.kernelModules = [ 240 "bridge" 241 "veth" 242 "br_netfilter" 243 "xt_nat" 244 ]; 245 boot.kernel.sysctl = { 246 "net.ipv4.conf.all.forwarding" = mkOverride 98 true; 247 "net.ipv4.conf.default.forwarding" = mkOverride 98 true; 248 }; 249 environment.systemPackages = [ cfg.package ] ++ optional cfg.enableNvidia pkgs.nvidia-docker; 250 users.groups.docker.gid = config.ids.gids.docker; 251 systemd.packages = [ cfg.package ]; 252 253 # Docker 25.0.0 supports CDI by default 254 # (https://docs.docker.com/engine/release-notes/25.0/#new). Encourage 255 # moving to CDI as opposed to having deprecated runtime 256 # wrappers. 257 warnings = 258 lib.optionals (cfg.enableNvidia && (lib.strings.versionAtLeast cfg.package.version "25")) 259 [ 260 '' 261 You have set virtualisation.docker.enableNvidia. This option is deprecated, please set hardware.nvidia-container-toolkit.enable instead. 262 '' 263 ]; 264 265 systemd.services.docker = { 266 wantedBy = optional cfg.enableOnBoot "multi-user.target"; 267 after = [ 268 "network.target" 269 "docker.socket" 270 ]; 271 requires = [ "docker.socket" ]; 272 environment = proxy_env; 273 serviceConfig = { 274 Type = "notify"; 275 ExecStart = [ 276 "" 277 '' 278 ${cfg.package}/bin/dockerd \ 279 --config-file=${daemonSettingsFile} \ 280 ${cfg.extraOptions} 281 '' 282 ]; 283 ExecReload = [ 284 "" 285 "${pkgs.procps}/bin/kill -s HUP $MAINPID" 286 ]; 287 }; 288 289 path = 290 [ pkgs.kmod ] 291 ++ optional (cfg.storageDriver == "zfs") pkgs.zfs 292 ++ optional cfg.enableNvidia pkgs.nvidia-docker 293 ++ cfg.extraPackages; 294 }; 295 296 systemd.sockets.docker = { 297 description = "Docker Socket for the API"; 298 wantedBy = [ "sockets.target" ]; 299 socketConfig = { 300 ListenStream = cfg.listenOptions; 301 SocketMode = "0660"; 302 SocketUser = "root"; 303 SocketGroup = "docker"; 304 }; 305 }; 306 307 systemd.services.docker-prune = { 308 description = "Prune docker resources"; 309 310 restartIfChanged = false; 311 unitConfig.X-StopOnRemoval = false; 312 313 serviceConfig = { 314 Type = "oneshot"; 315 ExecStart = utils.escapeSystemdExecArgs ( 316 [ 317 (lib.getExe cfg.package) 318 "system" 319 "prune" 320 "-f" 321 ] 322 ++ cfg.autoPrune.flags 323 ); 324 }; 325 326 startAt = optional cfg.autoPrune.enable cfg.autoPrune.dates; 327 after = [ "docker.service" ]; 328 requires = [ "docker.service" ]; 329 }; 330 331 systemd.timers.docker-prune = mkIf cfg.autoPrune.enable { 332 timerConfig = { 333 RandomizedDelaySec = cfg.autoPrune.randomizedDelaySec; 334 Persistent = cfg.autoPrune.persistent; 335 }; 336 }; 337 338 assertions = [ 339 { 340 assertion = 341 cfg.enableNvidia && pkgs.stdenv.hostPlatform.isx86_64 342 -> config.hardware.graphics.enable32Bit or false; 343 message = "Option enableNvidia on x86_64 requires 32-bit support libraries"; 344 } 345 ]; 346 347 virtualisation.docker.daemon.settings = { 348 group = "docker"; 349 hosts = [ "fd://" ]; 350 log-driver = mkDefault cfg.logDriver; 351 storage-driver = mkIf (cfg.storageDriver != null) (mkDefault cfg.storageDriver); 352 runtimes = mkIf cfg.enableNvidia { 353 nvidia = { 354 # Use the legacy nvidia-container-runtime wrapper to allow 355 # the `--runtime=nvidia` approach to expose 356 # GPU's. Starting with Docker > 25, CDI can be used 357 # instead, removing the need for runtime wrappers. 358 path = lib.getExe' pkgs.nvidia-docker "nvidia-container-runtime.legacy"; 359 }; 360 }; 361 }; 362 } 363 ]); 364}