1 # Systemd services for lxd.
3 { config, lib, pkgs, ... }:
6 cfg = config.virtualisation.lxd;
7 preseedFormat = pkgs.formats.yaml {};
10 (lib.mkRemovedOptionModule [ "virtualisation" "lxd" "zfsPackage" ] "Override zfs in an overlay instead to override it globally")
16 virtualisation.lxd = {
17 enable = lib.mkOption {
18 type = lib.types.bool;
20 description = lib.mdDoc ''
21 This option enables lxd, a daemon that manages
22 containers. Users in the "lxd" group can interact with
23 the daemon (e.g. to start or stop containers) using the
24 {command}`lxc` command line tool, among others.
26 Most of the time, you'll also want to start lxcfs, so
27 that containers can "see" the limits:
29 virtualisation.lxc.lxcfs.enable = true;
34 package = lib.mkOption {
35 type = lib.types.package;
37 defaultText = lib.literalExpression "pkgs.lxd";
38 description = lib.mdDoc ''
39 The LXD package to use.
43 lxcPackage = lib.mkOption {
44 type = lib.types.package;
46 defaultText = lib.literalExpression "pkgs.lxc";
47 description = lib.mdDoc ''
48 The LXC package to use with LXD (required for AppArmor profiles).
52 zfsSupport = lib.mkOption {
53 type = lib.types.bool;
54 default = config.boot.zfs.enabled;
55 defaultText = lib.literalExpression "config.boot.zfs.enabled";
56 description = lib.mdDoc ''
57 Enables lxd to use zfs as a storage for containers.
59 This option is enabled by default if a zfs pool is configured
64 recommendedSysctlSettings = lib.mkOption {
65 type = lib.types.bool;
67 description = lib.mdDoc ''
68 Enables various settings to avoid common pitfalls when
69 running containers requiring many file operations.
70 Fixes errors like "Too many open files" or
71 "neighbour: ndisc_cache: neighbor table overflow!".
72 See https://lxd.readthedocs.io/en/latest/production-setup/
77 preseed = lib.mkOption {
78 type = lib.types.nullOr (lib.types.submodule {
79 freeformType = preseedFormat.type;
84 description = lib.mdDoc ''
85 Configuration for LXD preseed, see
86 <https://documentation.ubuntu.com/lxd/en/latest/howto/initialize/#initialize-preseed>
89 Changes to this will be re-applied to LXD which will overwrite existing entities or create missing ones,
90 but entities will *not* be removed by preseed.
93 example = lib.literalExpression ''
100 "ipv4.address" = "10.0.100.1/24";
128 source = "/var/lib/lxd/storage-pools/default";
136 startTimeout = lib.mkOption {
137 type = lib.types.int;
140 description = lib.mdDoc ''
141 Time to wait (in seconds) for LXD to become ready to process requests.
142 If LXD does not reply within the configured time, lxd.service will be
143 considered failed and systemd will attempt to restart it.
148 enable = lib.mkEnableOption (lib.mdDoc "(experimental) LXD UI");
150 package = lib.mkPackageOption pkgs.lxd-unwrapped "ui" { };
155 ###### implementation
156 config = lib.mkIf cfg.enable {
157 environment.systemPackages = [ cfg.package ];
159 # Note: the following options are also declared in virtualisation.lxc, but
160 # the latter can't be simply enabled to reuse the formers, because it
161 # does a bunch of unrelated things.
162 systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
164 security.apparmor = {
165 packages = [ cfg.lxcPackage ];
167 "bin.lxc-start".profile = ''
168 include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
170 "lxc-containers".profile = ''
171 include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
176 # TODO: remove once LXD gets proper support for cgroupsv2
177 # (currently most of the e.g. CPU accounting stuff doesn't work)
178 systemd.enableUnifiedCgroupHierarchy = false;
180 systemd.sockets.lxd = {
181 description = "LXD UNIX socket";
182 wantedBy = [ "sockets.target" ];
185 ListenStream = "/var/lib/lxd/unix.socket";
188 Service = "lxd.service";
192 systemd.services.lxd = {
193 description = "LXD Container Management Daemon";
195 wantedBy = [ "multi-user.target" ];
197 "network-online.target"
198 (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service")
201 "network-online.target"
203 (lib.mkIf config.virtualisation.lxc.lxcfs.enable "lxcfs.service")
205 documentation = [ "man:lxd(1)" ];
207 path = [ pkgs.util-linux ]
208 ++ lib.optional cfg.zfsSupport config.boot.zfs.package;
210 environment = lib.mkIf (cfg.ui.enable) {
211 "LXD_UI" = cfg.ui.package;
215 ExecStart = "@${cfg.package}/bin/lxd lxd --group lxd";
216 ExecStartPost = "${cfg.package}/bin/lxd waitready --timeout=${cfg.startTimeout}";
217 ExecStop = "${cfg.package}/bin/lxd shutdown";
219 KillMode = "process"; # when stopping, leave the containers alone
220 LimitMEMLOCK = "infinity";
221 LimitNOFILE = "1048576";
222 LimitNPROC = "infinity";
223 TasksMax = "infinity";
225 Restart = "on-failure";
226 TimeoutStartSec = "${cfg.startTimeout}s";
227 TimeoutStopSec = "30s";
229 # By default, `lxd` loads configuration files from hard-coded
230 # `/usr/share/lxc/config` - since this is a no-go for us, we have to
231 # explicitly tell it where the actual configuration files are
232 Environment = lib.mkIf (config.virtualisation.lxc.lxcfs.enable)
233 "LXD_LXC_TEMPLATE_CONFIG=${pkgs.lxcfs}/share/lxc/config";
237 systemd.services.lxd-preseed = lib.mkIf (cfg.preseed != null) {
238 description = "LXD initialization with preseed file";
239 wantedBy = ["multi-user.target"];
240 requires = ["lxd.service"];
241 after = ["lxd.service"];
244 ${pkgs.coreutils}/bin/cat ${preseedFormat.generate "lxd-preseed.yaml" cfg.preseed} | ${cfg.package}/bin/lxd init --preseed
252 users.groups.lxd = {};
255 subUidRanges = [ { startUid = 1000000; count = 65536; } ];
256 subGidRanges = [ { startGid = 1000000; count = 65536; } ];
259 boot.kernel.sysctl = lib.mkIf cfg.recommendedSysctlSettings {
260 "fs.inotify.max_queued_events" = 1048576;
261 "fs.inotify.max_user_instances" = 1048576;
262 "fs.inotify.max_user_watches" = 1048576;
263 "vm.max_map_count" = 262144; # TODO: Default vm.max_map_count has been increased system-wide
264 "kernel.dmesg_restrict" = 1;
265 "net.ipv4.neigh.default.gc_thresh3" = 8192;
266 "net.ipv6.neigh.default.gc_thresh3" = 8192;
267 "kernel.keys.maxkeys" = 2000;
270 boot.kernelModules = [ "veth" "xt_comment" "xt_CHECKSUM" "xt_MASQUERADE" "vhost_vsock" ]
271 ++ lib.optionals (!config.networking.nftables.enable) [ "iptable_mangle" ];