at master 9.9 kB view raw
1{ 2 config, 3 lib, 4 utils, 5 pkgs, 6 ... 7}: 8let 9 cfg = config.virtualisation.podman; 10 json = pkgs.formats.json { }; 11 12 inherit (lib) mkOption types; 13 14 # Provides a fake "docker" binary mapping to podman 15 dockerCompat = 16 pkgs.runCommand "${cfg.package.pname}-docker-compat-${cfg.package.version}" 17 { 18 outputs = [ 19 "out" 20 "man" 21 ]; 22 inherit (cfg.package) meta; 23 preferLocalBuild = true; 24 } 25 '' 26 mkdir -p $out/bin 27 ln -s ${cfg.package}/bin/podman $out/bin/docker 28 29 mkdir -p $man/share/man/man1 30 for f in ${cfg.package.man}/share/man/man1/*; do 31 basename=$(basename $f | sed s/podman/docker/g) 32 ln -s $f $man/share/man/man1/$basename 33 done 34 ''; 35 36in 37{ 38 imports = [ 39 (lib.mkRemovedOptionModule [ 40 "virtualisation" 41 "podman" 42 "defaultNetwork" 43 "dnsname" 44 ] "Use virtualisation.podman.defaultNetwork.settings.dns_enabled instead.") 45 (lib.mkRemovedOptionModule [ 46 "virtualisation" 47 "podman" 48 "defaultNetwork" 49 "extraPlugins" 50 ] "Netavark isn't compatible with CNI plugins.") 51 ./network-socket.nix 52 ]; 53 54 meta = { 55 maintainers = lib.teams.podman.members; 56 }; 57 58 options.virtualisation.podman = { 59 60 enable = mkOption { 61 type = types.bool; 62 default = false; 63 description = '' 64 This option enables Podman, a daemonless container engine for 65 developing, managing, and running OCI Containers on your Linux System. 66 67 It is a drop-in replacement for the {command}`docker` command. 68 ''; 69 }; 70 71 dockerSocket.enable = mkOption { 72 type = types.bool; 73 default = false; 74 description = '' 75 Make the Podman socket available in place of the Docker socket, so 76 Docker tools can find the Podman socket. 77 78 Podman implements the Docker API. 79 80 Users must be in the `podman` group in order to connect. As 81 with Docker, members of this group can gain root access. 82 ''; 83 }; 84 85 dockerCompat = mkOption { 86 type = types.bool; 87 default = false; 88 description = '' 89 Create an alias mapping {command}`docker` to {command}`podman`. 90 ''; 91 }; 92 93 enableNvidia = mkOption { 94 type = types.bool; 95 default = false; 96 description = '' 97 **Deprecated**, please use hardware.nvidia-container-toolkit.enable instead. 98 99 Enable use of Nvidia GPUs from within podman containers. 100 ''; 101 }; 102 103 extraPackages = mkOption { 104 type = with types; listOf package; 105 default = [ ]; 106 description = '' 107 Extra dependencies for podman to be placed on $PATH in the wrapper. 108 ''; 109 }; 110 111 extraRuntimes = mkOption { 112 type = with types; listOf package; 113 # keep the default in sync with the podman package 114 default = lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs.runc ]; 115 defaultText = lib.literalExpression ''lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs.runc ]''; 116 example = lib.literalExpression '' 117 [ 118 pkgs.gvisor 119 ] 120 ''; 121 description = '' 122 Extra runtime packages to be installed in the Podman wrapper. 123 Those are then placed in libexec/podman, i.e. are seen as podman internal commands. 124 ''; 125 }; 126 127 autoPrune = { 128 enable = mkOption { 129 type = types.bool; 130 default = false; 131 description = '' 132 Whether to periodically prune Podman resources. If enabled, a 133 systemd timer will run `podman system prune -f` 134 as specified by the `dates` option. 135 ''; 136 }; 137 138 flags = mkOption { 139 type = types.listOf types.str; 140 default = [ ]; 141 example = [ "--all" ]; 142 description = '' 143 Any additional flags passed to {command}`podman system prune`. 144 ''; 145 }; 146 147 dates = mkOption { 148 default = "weekly"; 149 type = types.str; 150 description = '' 151 Specification (in the format described by 152 {manpage}`systemd.time(7)`) of the time at 153 which the prune will occur. 154 ''; 155 }; 156 }; 157 158 package = 159 (lib.mkPackageOption pkgs "podman" { 160 extraDescription = '' 161 This package will automatically include extra packages and runtimes. 162 ''; 163 }) 164 // { 165 apply = 166 pkg: 167 pkg.override { 168 extraPackages = 169 cfg.extraPackages 170 ++ [ 171 "/run/wrappers" # setuid shadow 172 config.systemd.package # To allow systemd-based container healthchecks 173 ] 174 ++ lib.optional (config.boot.supportedFilesystems.zfs or false) config.boot.zfs.package; 175 extraRuntimes = 176 cfg.extraRuntimes 177 ++ 178 lib.optionals 179 ( 180 config.virtualisation.containers.containersConf.settings.network.default_rootless_network_cmd or "" 181 == "slirp4netns" 182 ) 183 ( 184 with pkgs; 185 [ 186 slirp4netns 187 ] 188 ); 189 }; 190 }; 191 192 defaultNetwork.settings = lib.mkOption { 193 type = json.type; 194 default = { }; 195 example = lib.literalExpression "{ dns_enabled = true; }"; 196 description = '' 197 Settings for podman's default network. 198 ''; 199 }; 200 201 }; 202 203 config = 204 let 205 networkConfig = ( 206 { 207 dns_enabled = false; 208 driver = "bridge"; 209 id = "0000000000000000000000000000000000000000000000000000000000000000"; 210 internal = false; 211 ipam_options = { 212 driver = "host-local"; 213 }; 214 ipv6_enabled = false; 215 name = "podman"; 216 network_interface = "podman0"; 217 subnets = [ 218 { 219 gateway = "10.88.0.1"; 220 subnet = "10.88.0.0/16"; 221 } 222 ]; 223 } 224 // cfg.defaultNetwork.settings 225 ); 226 inherit (networkConfig) dns_enabled network_interface; 227 in 228 lib.mkIf cfg.enable { 229 warnings = lib.optionals cfg.enableNvidia [ 230 '' 231 You have set virtualisation.podman.enableNvidia. This option is deprecated, please set hardware.nvidia-container-toolkit.enable instead. 232 '' 233 ]; 234 235 environment.systemPackages = [ cfg.package ] ++ lib.optional cfg.dockerCompat dockerCompat; 236 237 # https://github.com/containers/podman/blob/097cc6eb6dd8e598c0e8676d21267b4edb11e144/docs/tutorials/basic_networking.md#default-network 238 environment.etc."containers/networks/podman.json" = lib.mkIf (cfg.defaultNetwork.settings != { }) { 239 source = json.generate "podman.json" networkConfig; 240 }; 241 242 # containers cannot reach aardvark-dns otherwise 243 networking.firewall.interfaces.${network_interface}.allowedUDPPorts = lib.mkIf dns_enabled [ 53 ]; 244 245 virtualisation.containers = { 246 enable = true; # Enable common /etc/containers configuration 247 containersConf.settings = { 248 network = { 249 network_backend = "netavark"; 250 firewall_driver = lib.mkIf config.networking.nftables.enable "nftables"; 251 }; 252 }; 253 }; 254 255 systemd.packages = [ cfg.package ]; 256 257 systemd.services.podman-prune = { 258 description = "Prune podman resources"; 259 260 restartIfChanged = false; 261 unitConfig.X-StopOnRemoval = false; 262 263 serviceConfig = { 264 Type = "oneshot"; 265 ExecStart = utils.escapeSystemdExecArgs ( 266 [ 267 (lib.getExe cfg.package) 268 "system" 269 "prune" 270 "-f" 271 ] 272 ++ cfg.autoPrune.flags 273 ); 274 }; 275 276 startAt = lib.optional cfg.autoPrune.enable cfg.autoPrune.dates; 277 after = [ "podman.service" ]; 278 requires = [ "podman.service" ]; 279 }; 280 281 systemd.services.podman.environment = config.networking.proxy.envVars; 282 systemd.sockets.podman.wantedBy = [ "sockets.target" ]; 283 systemd.sockets.podman.socketConfig.SocketGroup = "podman"; 284 # Podman does not support multiple sockets, as of podman 5.0.2, so we use 285 # a symlink. Unfortunately this does not let us use an alternate group, 286 # such as `docker`. 287 systemd.sockets.podman.socketConfig.Symlinks = lib.mkIf cfg.dockerSocket.enable [ 288 "/run/docker.sock" 289 ]; 290 291 systemd.user.services.podman.environment = config.networking.proxy.envVars; 292 systemd.user.sockets.podman.wantedBy = [ "sockets.target" ]; 293 294 systemd.timers.podman-prune.timerConfig = lib.mkIf cfg.autoPrune.enable { 295 Persistent = true; 296 RandomizedDelaySec = 1800; 297 }; 298 299 systemd.tmpfiles.packages = [ 300 # The /run/podman rule interferes with our podman group, so we remove 301 # it and let the systemd socket logic take care of it. 302 (pkgs.runCommand "podman-tmpfiles-nixos" 303 { 304 package = cfg.package; 305 preferLocalBuild = true; 306 } 307 '' 308 mkdir -p $out/lib/tmpfiles.d/ 309 grep -v 'D! /run/podman 0700 root root' \ 310 <$package/lib/tmpfiles.d/podman.conf \ 311 >$out/lib/tmpfiles.d/podman.conf 312 '' 313 ) 314 ]; 315 316 users.groups.podman = { }; 317 318 assertions = [ 319 { 320 assertion = cfg.dockerCompat -> !config.virtualisation.docker.enable; 321 message = "Option dockerCompat conflicts with docker"; 322 } 323 { 324 assertion = cfg.dockerSocket.enable -> !config.virtualisation.docker.enable; 325 message = '' 326 The options virtualisation.podman.dockerSocket.enable and virtualisation.docker.enable conflict, because only one can serve the socket. 327 ''; 328 } 329 ]; 330 }; 331}