{ config, pkgs, ... }: { # https://nixos.wiki/wiki/Docker#Installation # TODO: rootless Docker equivalent with root privileges? https://nixos.wiki/wiki/Docker#Rootless_docker # TODO: run as systemd services. https://nixos.wiki/wiki/Docker#docker_containers_as_systemd_services virtualisation = { docker = { enable = true; # As we use btrfs, we enable the according storageDriver option. storageDriver = "btrfs"; # IPv6 support. # https://search.nixos.org/options?channel=23.05&show=virtualisation.docker.daemon.settings # https://docs.docker.com/config/daemon/ipv6/#use-ipv6-for-the-default-bridge-network # TODO: See notes in Jinja-Compose/proxy.yml.jinja2 why this is not yet ready to use. # daemon.settings = { # # Enable IPv6 networking on the default network. # ipv6 = true; # # Assign a subnet to the default bridge network, enabling dynamic IPv6 address allocation. # fixed-cidr-v6 = "2001:db8:1::/64"; # # Enable additional IPv6 packet filter rules, providing network isolation and port mapping. # # This parameter requires experimental to be set to `true`. # ip6tables = true; # experimental = true; # }; # Run `docker system prune -f ${autoPrune.flags}` every week. # This creates `docker-prune.service` and `docker-prune.timer`. autoPrune.enable = true; autoPrune.dates = "weekly"; # https://docs.docker.com/engine/reference/commandline/system_prune/#options autoPrune.flags = [ "--all" # https://docs.docker.com/engine/reference/commandline/system_prune/#filter # https://pkg.go.dev/maze.io/x/duration#ParseDuration # `7d` could not be parsed, thus we use `168h` "--filter until=168h" # `--volumes` can't be used together with `--filter`. # Thus we added our own service below. #--volumes ]; }; }; # Prune docker volumes. # This is a slightly modified copy of https://github.com/NixOS/nixpkgs/blob/5a237aecb57296f67276ac9ab296a41c23981f56/nixos/modules/virtualisation/docker.nix#L211C5-L226 systemd.services."docker-prune-volumes" = { description = "Prune docker volumes"; restartIfChanged = false; unitConfig.X-StopOnRemoval = false; serviceConfig.Type = "oneshot"; script = '' ${pkgs.docker}/bin/docker system prune -f --all --volumes ''; # Run weekly after `docker-prune.service` has finished. # Reason: Only one `docker system prune` command can be run at a time. startAt = "weekly"; # Start the specified units when this unit is started, # and stop this unit when the specified units are stopped or fail. requires = [ "docker.service" ]; # If the specified units are started at the same time as this unit, # delay this unit until they have started. after = [ "docker.service" "docker-prune.service" ]; }; # Monitor unhealthy Docker containers. systemd.timers."docker-health" = { wantedBy = [ "timers.target" ]; partOf = [ "docker-health.service" ]; timerConfig = { OnBootSec = "0m"; OnUnitInactiveSec = "3m"; AccuracySec = "15s"; RandomizedDelaySec = "15s"; }; }; systemd.services."docker-health" = { serviceConfig = { Type = "oneshot"; PrivateTmp = true; # `docker` requires root access. User = "root"; Nice = 19; IOSchedulingClass = "idle"; }; path = with pkgs; [ docker ]; # If there are no unhealthy Docker containers, the output of `docker ps -f health=unhealthy` is just one line: # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES # We filter this line with `grep -v`. # As a result, grep returns exit code 1 if there are no unhealthy containers (as not a single line is printed). # Thus, we prefix the whole command with `!`. # Lastly, we redirect stdout to stderr with `1>&2` so that unhealthy containers are written to stderr. script = '' set -eu -o pipefail ! docker ps -f health=unhealthy | grep -v 'CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES' 1>&2 ''; }; }