vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / virtualisation / lxd.nix
blobbdcd60a0560f4d782f0be063c6e8360a4596a667
1 # Systemd services for lxd.
3 { config, lib, pkgs, ... }:
5 let
6   cfg = config.virtualisation.lxd;
7   preseedFormat = pkgs.formats.yaml {};
8 in {
9   imports = [
10     (lib.mkRemovedOptionModule [ "virtualisation" "lxd" "zfsPackage" ] "Override zfs in an overlay instead to override it globally")
11   ];
13   options = {
14     virtualisation.lxd = {
15       enable = lib.mkOption {
16         type = lib.types.bool;
17         default = false;
18         description = ''
19           This option enables lxd, a daemon that manages
20           containers. Users in the "lxd" group can interact with
21           the daemon (e.g. to start or stop containers) using the
22           {command}`lxc` command line tool, among others.
24           Most of the time, you'll also want to start lxcfs, so
25           that containers can "see" the limits:
26           ```
27           virtualisation.lxc.lxcfs.enable = true;
28           ```
29         '';
30       };
32       package = lib.mkPackageOption pkgs "lxd-lts" { };
34       lxcPackage = lib.mkOption {
35         type = lib.types.package;
36         default = config.virtualisation.lxc.package;
37         defaultText = lib.literalExpression "config.virtualisation.lxc.package";
38         description = "The lxc package to use.";
39       };
41       zfsSupport = lib.mkOption {
42         type = lib.types.bool;
43         default = config.boot.zfs.enabled;
44         defaultText = lib.literalExpression "config.boot.zfs.enabled";
45         description = ''
46           Enables lxd to use zfs as a storage for containers.
48           This option is enabled by default if a zfs pool is configured
49           with nixos.
50         '';
51       };
53       recommendedSysctlSettings = lib.mkOption {
54         type = lib.types.bool;
55         default = false;
56         description = ''
57           Enables various settings to avoid common pitfalls when
58           running containers requiring many file operations.
59           Fixes errors like "Too many open files" or
60           "neighbour: ndisc_cache: neighbor table overflow!".
61           See https://lxd.readthedocs.io/en/latest/production-setup/
62           for details.
63         '';
64       };
66       preseed = lib.mkOption {
67         type = lib.types.nullOr (lib.types.submodule {
68           freeformType = preseedFormat.type;
69         });
71         default = null;
73         description = ''
74           Configuration for LXD preseed, see
75           <https://documentation.ubuntu.com/lxd/en/latest/howto/initialize/#initialize-preseed>
76           for supported values.
78           Changes to this will be re-applied to LXD which will overwrite existing entities or create missing ones,
79           but entities will *not* be removed by preseed.
80         '';
82         example = lib.literalExpression ''
83           {
84             networks = [
85               {
86                 name = "lxdbr0";
87                 type = "bridge";
88                 config = {
89                   "ipv4.address" = "10.0.100.1/24";
90                   "ipv4.nat" = "true";
91                 };
92               }
93             ];
94             profiles = [
95               {
96                 name = "default";
97                 devices = {
98                   eth0 = {
99                     name = "eth0";
100                     network = "lxdbr0";
101                     type = "nic";
102                   };
103                   root = {
104                     path = "/";
105                     pool = "default";
106                     size = "35GiB";
107                     type = "disk";
108                   };
109                 };
110               }
111             ];
112             storage_pools = [
113               {
114                 name = "default";
115                 driver = "dir";
116                 config = {
117                   source = "/var/lib/lxd/storage-pools/default";
118                 };
119               }
120             ];
121           }
122         '';
123       };
125       startTimeout = lib.mkOption {
126         type = lib.types.int;
127         default = 600;
128         apply = toString;
129         description = ''
130           Time to wait (in seconds) for LXD to become ready to process requests.
131           If LXD does not reply within the configured time, lxd.service will be
132           considered failed and systemd will attempt to restart it.
133         '';
134       };
136       ui = {
137         enable = lib.mkEnableOption "(experimental) LXD UI";
139         package = lib.mkPackageOption pkgs [ "lxd-ui" ] { };
140       };
141     };
142   };
144   ###### implementation
145   config = lib.mkIf cfg.enable {
146     environment.systemPackages = [ cfg.package ];
148     # Note: the following options are also declared in virtualisation.lxc, but
149     # the latter can't be simply enabled to reuse the formers, because it
150     # does a bunch of unrelated things.
151     systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
153     security.apparmor = {
154       packages = [ cfg.lxcPackage ];
155       policies = {
156         "bin.lxc-start".profile = ''
157           include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
158         '';
159         "lxc-containers".profile = ''
160           include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
161         '';
162       };
163     };
165     systemd.sockets.lxd = {
166       description = "LXD UNIX socket";
167       wantedBy = [ "sockets.target" ];
169       socketConfig = {
170         ListenStream = "/var/lib/lxd/unix.socket";
171         SocketMode = "0660";
172         SocketGroup = "lxd";
173         Service = "lxd.service";
174       };
175     };
177     systemd.services.lxd = {
178       description = "LXD Container Management Daemon";
180       wantedBy = [ "multi-user.target" ];
181       after = [
182         "network-online.target"
183         (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service")
184       ];
185       requires = [
186         "network-online.target"
187         "lxd.socket"
188         (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service")
189       ];
190       documentation = [ "man:lxd(1)" ];
192       path = [ pkgs.util-linux ]
193         ++ lib.optional cfg.zfsSupport config.boot.zfs.package;
195       environment = lib.mkIf (cfg.ui.enable) {
196         "LXD_UI" = cfg.ui.package;
197       };
199       serviceConfig = {
200         ExecStart = "@${cfg.package}/bin/lxd lxd --group lxd";
201         ExecStartPost = "${cfg.package}/bin/lxd waitready --timeout=${cfg.startTimeout}";
202         ExecStop = "${cfg.package}/bin/lxd shutdown";
204         KillMode = "process"; # when stopping, leave the containers alone
205         LimitMEMLOCK = "infinity";
206         LimitNOFILE = "1048576";
207         LimitNPROC = "infinity";
208         TasksMax = "infinity";
209         Delegate = true; # LXD needs to manage cgroups in its subtree
211         # By default, `lxd` loads configuration files from hard-coded
212         # `/usr/share/lxc/config` - since this is a no-go for us, we have to
213         # explicitly tell it where the actual configuration files are
214         Environment = lib.mkIf (config.virtualisation.lxc.lxcfs.enable)
215           "LXD_LXC_TEMPLATE_CONFIG=${pkgs.lxcfs}/share/lxc/config";
216       };
218       unitConfig.ConditionPathExists = "!/var/lib/incus/.migrated-from-lxd";
219     };
221     systemd.services.lxd-preseed = lib.mkIf (cfg.preseed != null) {
222       description = "LXD initialization with preseed file";
223       wantedBy = ["multi-user.target"];
224       requires = ["lxd.service"];
225       after = ["lxd.service"];
227       script = ''
228         ${pkgs.coreutils}/bin/cat ${preseedFormat.generate "lxd-preseed.yaml" cfg.preseed} | ${cfg.package}/bin/lxd init --preseed
229       '';
231       serviceConfig = {
232         Type = "oneshot";
233       };
234     };
236     users.groups.lxd = {};
238     users.users.root = {
239       subUidRanges = [ { startUid = 1000000; count = 65536; } ];
240       subGidRanges = [ { startGid = 1000000; count = 65536; } ];
241     };
243     boot.kernel.sysctl = lib.mkIf cfg.recommendedSysctlSettings {
244       "fs.inotify.max_queued_events" = 1048576;
245       "fs.inotify.max_user_instances" = 1048576;
246       "fs.inotify.max_user_watches" = 1048576;
247       "vm.max_map_count" = 262144; # TODO: Default vm.max_map_count has been increased system-wide
248       "kernel.dmesg_restrict" = 1;
249       "net.ipv4.neigh.default.gc_thresh3" = 8192;
250       "net.ipv6.neigh.default.gc_thresh3" = 8192;
251       "kernel.keys.maxkeys" = 2000;
252     };
254     boot.kernelModules = [ "veth" "xt_comment" "xt_CHECKSUM" "xt_MASQUERADE" "vhost_vsock" ]
255       ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ];
256   };