at 23.11-pre 7.4 kB view raw
1{ config, lib, pkgs, ... }: 2let 3 cfg = config.virtualisation.podman; 4 json = pkgs.formats.json { }; 5 6 inherit (lib) mkOption types; 7 8 podmanPackage = (pkgs.podman.override { 9 extraPackages = cfg.extraPackages 10 # setuid shadow 11 ++ [ "/run/wrappers" ] 12 ++ lib.optional (builtins.elem "zfs" config.boot.supportedFilesystems) config.boot.zfs.package; 13 }); 14 15 # Provides a fake "docker" binary mapping to podman 16 dockerCompat = pkgs.runCommand "${podmanPackage.pname}-docker-compat-${podmanPackage.version}" 17 { 18 outputs = [ "out" "man" ]; 19 inherit (podmanPackage) meta; 20 } '' 21 mkdir -p $out/bin 22 ln -s ${podmanPackage}/bin/podman $out/bin/docker 23 24 mkdir -p $man/share/man/man1 25 for f in ${podmanPackage.man}/share/man/man1/*; do 26 basename=$(basename $f | sed s/podman/docker/g) 27 ln -s $f $man/share/man/man1/$basename 28 done 29 ''; 30 31in 32{ 33 imports = [ 34 (lib.mkRemovedOptionModule [ "virtualisation" "podman" "defaultNetwork" "dnsname" ] 35 "Use virtualisation.podman.defaultNetwork.settings.dns_enabled instead.") 36 (lib.mkRemovedOptionModule [ "virtualisation" "podman" "defaultNetwork" "extraPlugins" ] 37 "Netavark isn't compatible with CNI plugins.") 38 ./network-socket.nix 39 ]; 40 41 meta = { 42 maintainers = lib.teams.podman.members; 43 }; 44 45 options.virtualisation.podman = { 46 47 enable = 48 mkOption { 49 type = types.bool; 50 default = false; 51 description = lib.mdDoc '' 52 This option enables Podman, a daemonless container engine for 53 developing, managing, and running OCI Containers on your Linux System. 54 55 It is a drop-in replacement for the {command}`docker` command. 56 ''; 57 }; 58 59 dockerSocket.enable = mkOption { 60 type = types.bool; 61 default = false; 62 description = lib.mdDoc '' 63 Make the Podman socket available in place of the Docker socket, so 64 Docker tools can find the Podman socket. 65 66 Podman implements the Docker API. 67 68 Users must be in the `podman` group in order to connect. As 69 with Docker, members of this group can gain root access. 70 ''; 71 }; 72 73 dockerCompat = mkOption { 74 type = types.bool; 75 default = false; 76 description = lib.mdDoc '' 77 Create an alias mapping {command}`docker` to {command}`podman`. 78 ''; 79 }; 80 81 enableNvidia = mkOption { 82 type = types.bool; 83 default = false; 84 description = lib.mdDoc '' 85 Enable use of NVidia GPUs from within podman containers. 86 ''; 87 }; 88 89 extraPackages = mkOption { 90 type = with types; listOf package; 91 default = [ ]; 92 example = lib.literalExpression '' 93 [ 94 pkgs.gvisor 95 ] 96 ''; 97 description = lib.mdDoc '' 98 Extra packages to be installed in the Podman wrapper. 99 ''; 100 }; 101 102 autoPrune = { 103 enable = mkOption { 104 type = types.bool; 105 default = false; 106 description = lib.mdDoc '' 107 Whether to periodically prune Podman resources. If enabled, a 108 systemd timer will run `podman system prune -f` 109 as specified by the `dates` option. 110 ''; 111 }; 112 113 flags = mkOption { 114 type = types.listOf types.str; 115 default = []; 116 example = [ "--all" ]; 117 description = lib.mdDoc '' 118 Any additional flags passed to {command}`podman system prune`. 119 ''; 120 }; 121 122 dates = mkOption { 123 default = "weekly"; 124 type = types.str; 125 description = lib.mdDoc '' 126 Specification (in the format described by 127 {manpage}`systemd.time(7)`) of the time at 128 which the prune will occur. 129 ''; 130 }; 131 }; 132 133 package = lib.mkOption { 134 type = types.package; 135 default = podmanPackage; 136 internal = true; 137 description = lib.mdDoc '' 138 The final Podman package (including extra packages). 139 ''; 140 }; 141 142 defaultNetwork.settings = lib.mkOption { 143 type = json.type; 144 default = { }; 145 example = lib.literalExpression "{ dns_enabled = true; }"; 146 description = lib.mdDoc '' 147 Settings for podman's default network. 148 ''; 149 }; 150 151 }; 152 153 config = lib.mkIf cfg.enable 154 { 155 environment.systemPackages = [ cfg.package ] 156 ++ lib.optional cfg.dockerCompat dockerCompat; 157 158 # https://github.com/containers/podman/blob/097cc6eb6dd8e598c0e8676d21267b4edb11e144/docs/tutorials/basic_networking.md#default-network 159 environment.etc."containers/networks/podman.json" = lib.mkIf (cfg.defaultNetwork.settings != { }) { 160 source = json.generate "podman.json" ({ 161 dns_enabled = false; 162 driver = "bridge"; 163 id = "0000000000000000000000000000000000000000000000000000000000000000"; 164 internal = false; 165 ipam_options = { driver = "host-local"; }; 166 ipv6_enabled = false; 167 name = "podman"; 168 network_interface = "podman0"; 169 subnets = [{ gateway = "10.88.0.1"; subnet = "10.88.0.0/16"; }]; 170 } // cfg.defaultNetwork.settings); 171 }; 172 173 virtualisation.containers = { 174 enable = true; # Enable common /etc/containers configuration 175 containersConf.settings = { 176 network.network_backend = "netavark"; 177 } // lib.optionalAttrs cfg.enableNvidia { 178 engine = { 179 conmon_env_vars = [ "PATH=${lib.makeBinPath [ pkgs.nvidia-podman ]}" ]; 180 runtimes.nvidia = [ "${pkgs.nvidia-podman}/bin/nvidia-container-runtime" ]; 181 }; 182 }; 183 }; 184 185 systemd.packages = [ cfg.package ]; 186 187 systemd.services.podman-prune = { 188 description = "Prune podman resources"; 189 190 restartIfChanged = false; 191 unitConfig.X-StopOnRemoval = false; 192 193 serviceConfig.Type = "oneshot"; 194 195 script = '' 196 ${cfg.package}/bin/podman system prune -f ${toString cfg.autoPrune.flags} 197 ''; 198 199 startAt = lib.optional cfg.autoPrune.enable cfg.autoPrune.dates; 200 after = [ "podman.service" ]; 201 requires = [ "podman.service" ]; 202 }; 203 204 systemd.sockets.podman.wantedBy = [ "sockets.target" ]; 205 systemd.sockets.podman.socketConfig.SocketGroup = "podman"; 206 207 systemd.user.sockets.podman.wantedBy = [ "sockets.target" ]; 208 209 systemd.tmpfiles.packages = [ 210 # The /run/podman rule interferes with our podman group, so we remove 211 # it and let the systemd socket logic take care of it. 212 (pkgs.runCommand "podman-tmpfiles-nixos" { package = cfg.package; } '' 213 mkdir -p $out/lib/tmpfiles.d/ 214 grep -v 'D! /run/podman 0700 root root' \ 215 <$package/lib/tmpfiles.d/podman.conf \ 216 >$out/lib/tmpfiles.d/podman.conf 217 '') 218 ]; 219 220 systemd.tmpfiles.rules = 221 lib.optionals cfg.dockerSocket.enable [ 222 "L! /run/docker.sock - - - - /run/podman/podman.sock" 223 ]; 224 225 users.groups.podman = { }; 226 227 assertions = [ 228 { 229 assertion = cfg.dockerCompat -> !config.virtualisation.docker.enable; 230 message = "Option dockerCompat conflicts with docker"; 231 } 232 { 233 assertion = cfg.dockerSocket.enable -> !config.virtualisation.docker.enable; 234 message = '' 235 The options virtualisation.podman.dockerSocket.enable and virtualisation.docker.enable conflict, because only one can serve the socket. 236 ''; 237 } 238 ]; 239 }; 240}