grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / virtualisation / podman / default.nix
blobaa1d383738ad655fd7ecf3e7694f15fe26ce90d0
1 { config, lib, pkgs, ... }:
2 let
3   cfg = config.virtualisation.podman;
4   json = pkgs.formats.json { };
6   inherit (lib) mkOption types;
8   podmanPackage = pkgs.podman.override {
9     extraPackages = cfg.extraPackages
10       # setuid shadow
11       ++ [ "/run/wrappers" ]
12       ++ lib.optional (config.boot.supportedFilesystems.zfs or false) config.boot.zfs.package;
13     extraRuntimes = [ pkgs.runc ]
14       ++ lib.optionals (config.virtualisation.containers.containersConf.settings.network.default_rootless_network_cmd or "" == "slirp4netns") (with pkgs; [
15       slirp4netns
16     ]);
17   };
19   # Provides a fake "docker" binary mapping to podman
20   dockerCompat = pkgs.runCommand "${podmanPackage.pname}-docker-compat-${podmanPackage.version}"
21     {
22       outputs = [ "out" "man" ];
23       inherit (podmanPackage) meta;
24       preferLocalBuild = true;
25     } ''
26     mkdir -p $out/bin
27     ln -s ${podmanPackage}/bin/podman $out/bin/docker
29     mkdir -p $man/share/man/man1
30     for f in ${podmanPackage.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   '';
38   imports = [
39     (lib.mkRemovedOptionModule [ "virtualisation" "podman" "defaultNetwork" "dnsname" ]
40       "Use virtualisation.podman.defaultNetwork.settings.dns_enabled instead.")
41     (lib.mkRemovedOptionModule [ "virtualisation" "podman" "defaultNetwork" "extraPlugins" ]
42       "Netavark isn't compatible with CNI plugins.")
43     ./network-socket.nix
44   ];
46   meta = {
47     maintainers = lib.teams.podman.members;
48   };
50   options.virtualisation.podman = {
52     enable =
53       mkOption {
54         type = types.bool;
55         default = false;
56         description = ''
57           This option enables Podman, a daemonless container engine for
58           developing, managing, and running OCI Containers on your Linux System.
60           It is a drop-in replacement for the {command}`docker` command.
61         '';
62       };
64     dockerSocket.enable = mkOption {
65       type = types.bool;
66       default = false;
67       description = ''
68         Make the Podman socket available in place of the Docker socket, so
69         Docker tools can find the Podman socket.
71         Podman implements the Docker API.
73         Users must be in the `podman` group in order to connect. As
74         with Docker, members of this group can gain root access.
75       '';
76     };
78     dockerCompat = mkOption {
79       type = types.bool;
80       default = false;
81       description = ''
82         Create an alias mapping {command}`docker` to {command}`podman`.
83       '';
84     };
86     enableNvidia = mkOption {
87       type = types.bool;
88       default = false;
89       description = ''
90         **Deprecated**, please use hardware.nvidia-container-toolkit.enable instead.
92         Enable use of Nvidia GPUs from within podman containers.
93       '';
94     };
96     extraPackages = mkOption {
97       type = with types; listOf package;
98       default = [ ];
99       example = lib.literalExpression ''
100         [
101           pkgs.gvisor
102         ]
103       '';
104       description = ''
105         Extra packages to be installed in the Podman wrapper.
106       '';
107     };
109     autoPrune = {
110       enable = mkOption {
111         type = types.bool;
112         default = false;
113         description = ''
114           Whether to periodically prune Podman resources. If enabled, a
115           systemd timer will run `podman system prune -f`
116           as specified by the `dates` option.
117         '';
118       };
120       flags = mkOption {
121         type = types.listOf types.str;
122         default = [];
123         example = [ "--all" ];
124         description = ''
125           Any additional flags passed to {command}`podman system prune`.
126         '';
127       };
129       dates = mkOption {
130         default = "weekly";
131         type = types.str;
132         description = ''
133           Specification (in the format described by
134           {manpage}`systemd.time(7)`) of the time at
135           which the prune will occur.
136         '';
137       };
138     };
140     package = lib.mkOption {
141       type = types.package;
142       default = podmanPackage;
143       internal = true;
144       description = ''
145         The final Podman package (including extra packages).
146       '';
147     };
149     defaultNetwork.settings = lib.mkOption {
150       type = json.type;
151       default = { };
152       example = lib.literalExpression "{ dns_enabled = true; }";
153       description = ''
154         Settings for podman's default network.
155       '';
156     };
158   };
160   config =
161     let
162       networkConfig = ({
163         dns_enabled = false;
164         driver = "bridge";
165         id = "0000000000000000000000000000000000000000000000000000000000000000";
166         internal = false;
167         ipam_options = { driver = "host-local"; };
168         ipv6_enabled = false;
169         name = "podman";
170         network_interface = "podman0";
171         subnets = [{ gateway = "10.88.0.1"; subnet = "10.88.0.0/16"; }];
172       } // cfg.defaultNetwork.settings);
173       inherit (networkConfig) dns_enabled network_interface;
174     in
175     lib.mkIf cfg.enable {
176       warnings = lib.optionals cfg.enableNvidia [
177         ''
178           You have set virtualisation.podman.enableNvidia. This option is deprecated, please set hardware.nvidia-container-toolkit.enable instead.
179         ''
180       ];
182       environment.systemPackages = [ cfg.package ]
183         ++ lib.optional cfg.dockerCompat dockerCompat;
185       # https://github.com/containers/podman/blob/097cc6eb6dd8e598c0e8676d21267b4edb11e144/docs/tutorials/basic_networking.md#default-network
186       environment.etc."containers/networks/podman.json" = lib.mkIf (cfg.defaultNetwork.settings != { }) {
187         source = json.generate "podman.json" networkConfig;
188       };
190       # containers cannot reach aardvark-dns otherwise
191       networking.firewall.interfaces.${network_interface}.allowedUDPPorts = lib.mkIf dns_enabled [ 53 ];
193       virtualisation.containers = {
194         enable = true; # Enable common /etc/containers configuration
195         containersConf.settings = {
196           network.network_backend = "netavark";
197         };
198       };
200       systemd.packages = [ cfg.package ];
202       systemd.services.podman-prune = {
203         description = "Prune podman resources";
205         restartIfChanged = false;
206         unitConfig.X-StopOnRemoval = false;
208         serviceConfig.Type = "oneshot";
210         script = ''
211           ${cfg.package}/bin/podman system prune -f ${toString cfg.autoPrune.flags}
212         '';
214         startAt = lib.optional cfg.autoPrune.enable cfg.autoPrune.dates;
215         after = [ "podman.service" ];
216         requires = [ "podman.service" ];
217       };
219       systemd.services.podman.environment = config.networking.proxy.envVars;
220       systemd.sockets.podman.wantedBy = [ "sockets.target" ];
221       systemd.sockets.podman.socketConfig.SocketGroup = "podman";
222       # Podman does not support multiple sockets, as of podman 5.0.2, so we use
223       # a symlink. Unfortunately this does not let us use an alternate group,
224       # such as `docker`.
225       systemd.sockets.podman.socketConfig.Symlinks =
226         lib.mkIf cfg.dockerSocket.enable [ "/run/docker.sock" ];
228       systemd.user.services.podman.environment = config.networking.proxy.envVars;
229       systemd.user.sockets.podman.wantedBy = [ "sockets.target" ];
231       systemd.timers.podman-prune.timerConfig = lib.mkIf cfg.autoPrune.enable {
232         Persistent = true;
233         RandomizedDelaySec = 1800;
234       };
236       systemd.tmpfiles.packages = [
237         # The /run/podman rule interferes with our podman group, so we remove
238         # it and let the systemd socket logic take care of it.
239         (pkgs.runCommand "podman-tmpfiles-nixos" {
240           package = cfg.package;
241           preferLocalBuild = true;
242         } ''
243           mkdir -p $out/lib/tmpfiles.d/
244           grep -v 'D! /run/podman 0700 root root' \
245             <$package/lib/tmpfiles.d/podman.conf \
246             >$out/lib/tmpfiles.d/podman.conf
247         '')
248       ];
250       users.groups.podman = { };
252       assertions = [
253         {
254           assertion = cfg.dockerCompat -> !config.virtualisation.docker.enable;
255           message = "Option dockerCompat conflicts with docker";
256         }
257         {
258           assertion = cfg.dockerSocket.enable -> !config.virtualisation.docker.enable;
259           message = ''
260             The options virtualisation.podman.dockerSocket.enable and virtualisation.docker.enable conflict, because only one can serve the socket.
261           '';
262         }
263       ];
264     };