forked from mirrors_public/oddlama_nix-config
feat: wip: add container backend to guests
This commit is contained in:
parent
83f1908e21
commit
abb8330d86
23 changed files with 256 additions and 208 deletions
|
@ -9,6 +9,6 @@
|
|||
''This is \e{cyan}\n\e{reset} [\e{lightblue}\l\e{reset}] (\s \m \r)''
|
||||
]
|
||||
# Disabled for guests because of frequent redraws (-> pushed to syslog on the host)
|
||||
++ lib.optional (!config.guests.isGuest) ''\e{halfbright}\4\e{reset} \e{halfbright}\6\e{reset}''
|
||||
++ lib.optional (config.node.type == "host") ''\e{halfbright}\4\e{reset} \e{halfbright}\6\e{reset}''
|
||||
++ [""]);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
./config/system.nix
|
||||
./config/users.nix
|
||||
|
||||
./guests
|
||||
|
||||
./meta/kanidm.nix
|
||||
./meta/microvms.nix
|
||||
./meta/nginx.nix
|
||||
./meta/oauth2-proxy.nix
|
||||
./meta/promtail.nix
|
||||
|
|
31
modules/guests/common-guest-config.nix
Normal file
31
modules/guests/common-guest-config.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
_guestName: guestCfg: {lib, ...}: let
|
||||
inherit (lib) mkForce;
|
||||
in {
|
||||
node.name = guestCfg.nodeName;
|
||||
node.type = guestCfg.backend;
|
||||
|
||||
nix = {
|
||||
settings.auto-optimise-store = mkForce false;
|
||||
optimise.automatic = mkForce false;
|
||||
gc.automatic = mkForce false;
|
||||
};
|
||||
|
||||
systemd.network.networks = {
|
||||
"10-${guestCfg.networking.mainLinkName}" = {
|
||||
DHCP = "yes";
|
||||
dhcpV4Config.UseDNS = false;
|
||||
dhcpV6Config.UseDNS = false;
|
||||
ipv6AcceptRAConfig.UseDNS = false;
|
||||
networkConfig = {
|
||||
IPv6PrivacyExtensions = "yes";
|
||||
MulticastDNS = true;
|
||||
IPv6AcceptRA = true;
|
||||
};
|
||||
linkConfig.RequiredForOnline = "routable";
|
||||
};
|
||||
};
|
||||
|
||||
networking.nftables.firewall = {
|
||||
zones.untrusted.interfaces = [guestCfg.networking.mainLinkName];
|
||||
};
|
||||
}
|
29
modules/guests/container.nix
Normal file
29
modules/guests/container.nix
Normal file
|
@ -0,0 +1,29 @@
|
|||
guestName: guestCfg: {
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
} @ attrs: let
|
||||
inherit (lib) mkMerge;
|
||||
in {
|
||||
autoStart = guestCfg.autostart;
|
||||
specialArgs =
|
||||
attrs
|
||||
// {
|
||||
parentNode = config;
|
||||
};
|
||||
macvlans = [guestCfg.container.macvlan];
|
||||
ephemeral = true;
|
||||
privateNetwork = true;
|
||||
config = mkMerge (guestCfg.modules
|
||||
++ [
|
||||
(import ./common-guest-config.nix guestName guestCfg)
|
||||
{
|
||||
systemd.network.networks = {
|
||||
"10-${guestCfg.networking.mainLinkName}" = {
|
||||
matchConfig.OriginalName = "mv-${guestCfg.container.macvlan}";
|
||||
linkConfig.Name = guestCfg.networking.mainLinkName;
|
||||
};
|
||||
};
|
||||
}
|
||||
]);
|
||||
}
|
|
@ -4,12 +4,10 @@
|
|||
lib,
|
||||
pkgs,
|
||||
utils,
|
||||
minimal,
|
||||
...
|
||||
}: let
|
||||
} @ attrs: let
|
||||
inherit
|
||||
(lib)
|
||||
attrNames
|
||||
attrValues
|
||||
any
|
||||
disko
|
||||
|
@ -17,19 +15,13 @@
|
|||
makeBinPath
|
||||
mapAttrsToList
|
||||
mergeToplevelConfigs
|
||||
mkDefault
|
||||
mkEnableOption
|
||||
mkForce
|
||||
mkIf
|
||||
mkOption
|
||||
net
|
||||
optional
|
||||
types
|
||||
;
|
||||
|
||||
cfg = config.guests;
|
||||
nodeName = config.node.name;
|
||||
inherit (cfg) guests;
|
||||
|
||||
# Configuration required on the host for a specific guest
|
||||
defineGuest = guestName: guestCfg: {
|
||||
|
@ -79,115 +71,18 @@
|
|||
requires = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath guestCfg.zfs.mountpoint}.service"];
|
||||
after = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath guestCfg.zfs.mountpoint}.service"];
|
||||
};
|
||||
};
|
||||
|
||||
microvm.vms.${guestName} = let
|
||||
mac = (net.mac.assignMacs "02:01:27:00:00:00" 24 [] (attrNames guests)).${guestName};
|
||||
in
|
||||
mkIf (guestCfg.backend == "microvm") {
|
||||
# Allow children microvms to know which node is their parent
|
||||
specialArgs = {
|
||||
parentNode = config;
|
||||
inherit (inputs.self) nodes;
|
||||
inherit (inputs.self.pkgs.${guestCfg.microvm.system}) lib;
|
||||
inherit inputs;
|
||||
inherit minimal;
|
||||
};
|
||||
pkgs = inputs.self.pkgs.${guestCfg.microvm.system};
|
||||
inherit (guestCfg) autostart;
|
||||
config = {
|
||||
imports = guestCfg.modules;
|
||||
node.name = guestCfg.nodeName;
|
||||
node.isGuest = true;
|
||||
|
||||
# TODO needed because of https://github.com/NixOS/nixpkgs/issues/102137
|
||||
environment.noXlibs = mkForce false;
|
||||
lib.microvm.mac = mac;
|
||||
|
||||
microvm = {
|
||||
hypervisor = mkDefault "qemu";
|
||||
|
||||
# Give them some juice by default
|
||||
mem = mkDefault (2 * 1024);
|
||||
|
||||
# MACVTAP bridge to the host's network
|
||||
interfaces = [
|
||||
{
|
||||
type = "macvtap";
|
||||
id = "vm-${guestName}";
|
||||
inherit mac;
|
||||
macvtap = {
|
||||
link = cfg.networking.macvtapInterface;
|
||||
mode = "bridge";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
shares =
|
||||
[
|
||||
# Share the nix-store of the host
|
||||
{
|
||||
source = "/nix/store";
|
||||
mountPoint = "/nix/.ro-store";
|
||||
tag = "ro-store";
|
||||
proto = "virtiofs";
|
||||
}
|
||||
{
|
||||
source = "/state/guests/${guestName}";
|
||||
mountPoint = "/state";
|
||||
tag = "state";
|
||||
proto = "virtiofs";
|
||||
}
|
||||
]
|
||||
# Mount persistent data from the host
|
||||
++ optional guestCfg.zfs.enable {
|
||||
source = guestCfg.zfs.mountpoint;
|
||||
mountPoint = "/persist";
|
||||
tag = "persist";
|
||||
proto = "virtiofs";
|
||||
};
|
||||
};
|
||||
|
||||
# FIXME this should be changed in microvm.nix to mkDefault in oder to not require mkForce here
|
||||
fileSystems."/state".neededForBoot = mkForce true;
|
||||
fileSystems."/persist".neededForBoot = mkForce true;
|
||||
|
||||
# Add a writable store overlay, but since this is always ephemeral
|
||||
# disable any store optimization from nix.
|
||||
microvm.writableStoreOverlay = "/nix/.rw-store";
|
||||
nix = {
|
||||
settings.auto-optimise-store = mkForce false;
|
||||
optimise.automatic = mkForce false;
|
||||
gc.automatic = mkForce false;
|
||||
};
|
||||
|
||||
networking.renameInterfacesByMac.${guestCfg.networking.mainLinkName} = mac;
|
||||
|
||||
systemd.network.networks = {
|
||||
"10-${guestCfg.networking.mainLinkName}" = {
|
||||
matchConfig.MACAddress = mac;
|
||||
DHCP = "yes";
|
||||
dhcpV4Config.UseDNS = false;
|
||||
dhcpV6Config.UseDNS = false;
|
||||
ipv6AcceptRAConfig.UseDNS = false;
|
||||
networkConfig = {
|
||||
IPv6PrivacyExtensions = "yes";
|
||||
MulticastDNS = true;
|
||||
IPv6AcceptRA = true;
|
||||
};
|
||||
linkConfig.RequiredForOnline = "routable";
|
||||
};
|
||||
};
|
||||
|
||||
networking.nftables.firewall = {
|
||||
zones.untrusted.interfaces = [guestCfg.networking.mainLinkName];
|
||||
};
|
||||
"container@${guestName}" = mkIf (guestCfg.backend == "container") {
|
||||
requires = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath guestCfg.zfs.mountpoint}.service"];
|
||||
after = [fsMountUnit "zfs-chown-${utils.escapeSystemdPath guestCfg.zfs.mountpoint}.service"];
|
||||
};
|
||||
};
|
||||
|
||||
microvm.vms.${guestName} =
|
||||
mkIf (guestCfg.backend == "microvm") (import ./microvm.nix guestName guestCfg attrs);
|
||||
|
||||
containers.${guestName} =
|
||||
mkIf (guestCfg.backend == "microvm") {
|
||||
};
|
||||
mkIf (guestCfg.backend == "container") (import ./container.nix guestName guestCfg attrs);
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
|
@ -198,31 +93,16 @@ in {
|
|||
microvm.host.enable =
|
||||
any
|
||||
(guestCfg: guestCfg.backend == "microvm")
|
||||
(attrValues guests);
|
||||
(attrValues config.guests);
|
||||
}
|
||||
];
|
||||
|
||||
options.node.isGuest = mkOption {
|
||||
type = types.bool;
|
||||
description = "Whether this machine is a guest on another machine.";
|
||||
default = false;
|
||||
options.node.type = mkOption {
|
||||
type = types.enum ["host" "microvm" "container"];
|
||||
description = "The type of this machine.";
|
||||
default = "host";
|
||||
};
|
||||
|
||||
# networking = {
|
||||
# baseMac = mkOption {
|
||||
# type = types.net.mac;
|
||||
# description = ''
|
||||
# This MAC address will be used as a base address to derive all MicroVM MAC addresses from.
|
||||
# A good practise is to use the physical address of the macvtap interface.
|
||||
# '';
|
||||
# };
|
||||
#
|
||||
# macvtapInterface = mkOption {
|
||||
# type = types.str;
|
||||
# description = "The macvtap interface to which MicroVMs should be attached";
|
||||
# };
|
||||
# };
|
||||
|
||||
options.guests = mkOption {
|
||||
default = {};
|
||||
description = "Defines the actual vms and handles the necessary base setup for them.";
|
||||
|
@ -252,6 +132,19 @@ in {
|
|||
type = types.str;
|
||||
description = "The system that this microvm should use";
|
||||
};
|
||||
|
||||
macvtapInterface = mkOption {
|
||||
type = types.str;
|
||||
description = "The host macvtap interface to which the microvm should be attached";
|
||||
};
|
||||
};
|
||||
|
||||
# Options for the container backend
|
||||
container = {
|
||||
macvlan = mkOption {
|
||||
type = types.str;
|
||||
description = "The host interface to which the container should be attached";
|
||||
};
|
||||
};
|
||||
|
||||
networking = {
|
||||
|
@ -298,5 +191,7 @@ in {
|
|||
}));
|
||||
};
|
||||
|
||||
config = mkIf (guests != {}) (mergeToplevelConfigs ["disko" "microvm" "systemd"] (mapAttrsToList defineGuest guests));
|
||||
config =
|
||||
mkIf (config.guests != {})
|
||||
(mergeToplevelConfigs ["containers" "disko" "microvm" "systemd"] (mapAttrsToList defineGuest config.guests));
|
||||
}
|
||||
|
|
101
modules/guests/microvm.nix
Normal file
101
modules/guests/microvm.nix
Normal file
|
@ -0,0 +1,101 @@
|
|||
guestName: guestCfg: {
|
||||
config,
|
||||
inputs,
|
||||
lib,
|
||||
pkgs,
|
||||
minimal,
|
||||
...
|
||||
}: let
|
||||
inherit
|
||||
(lib)
|
||||
attrNames
|
||||
mkDefault
|
||||
mkForce
|
||||
net
|
||||
optional
|
||||
;
|
||||
|
||||
mac = (net.mac.assignMacs "02:01:27:00:00:00" 24 [] (attrNames config.guests)).${guestName};
|
||||
in {
|
||||
specialArgs = {
|
||||
parentNode = config;
|
||||
inherit (inputs.self) nodes;
|
||||
inherit (inputs.self.pkgs.${guestCfg.microvm.system}) lib;
|
||||
inherit inputs;
|
||||
inherit minimal;
|
||||
};
|
||||
pkgs = inputs.self.pkgs.${guestCfg.microvm.system};
|
||||
inherit (guestCfg) autostart;
|
||||
config = {
|
||||
imports = guestCfg.modules ++ [(import ./common-guest-config.nix guestName guestCfg)];
|
||||
|
||||
# TODO needed because of https://github.com/NixOS/nixpkgs/issues/102137
|
||||
environment.noXlibs = mkForce false;
|
||||
lib.microvm.mac = mac;
|
||||
|
||||
microvm = {
|
||||
hypervisor = mkDefault "qemu";
|
||||
|
||||
# Give them some juice by default
|
||||
mem = mkDefault (2 * 1024);
|
||||
|
||||
# MACVTAP bridge to the host's network
|
||||
interfaces = [
|
||||
{
|
||||
type = "macvtap";
|
||||
id = "vm-${guestName}";
|
||||
inherit mac;
|
||||
macvtap = {
|
||||
link = guestCfg.microvm.macvtapInterface;
|
||||
mode = "bridge";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
shares =
|
||||
[
|
||||
# Share the nix-store of the host
|
||||
{
|
||||
source = "/nix/store";
|
||||
mountPoint = "/nix/.ro-store";
|
||||
tag = "ro-store";
|
||||
proto = "virtiofs";
|
||||
}
|
||||
{
|
||||
source = "/state/guests/${guestName}";
|
||||
mountPoint = "/state";
|
||||
tag = "state";
|
||||
proto = "virtiofs";
|
||||
}
|
||||
]
|
||||
# Mount persistent data from the host
|
||||
++ optional guestCfg.zfs.enable {
|
||||
source = guestCfg.zfs.mountpoint;
|
||||
mountPoint = "/persist";
|
||||
tag = "persist";
|
||||
proto = "virtiofs";
|
||||
};
|
||||
};
|
||||
|
||||
# FIXME this should be changed in microvm.nix to mkDefault in oder to not require mkForce here
|
||||
fileSystems."/state".neededForBoot = mkForce true;
|
||||
fileSystems."/persist".neededForBoot = mkForce true;
|
||||
|
||||
# Add a writable store overlay, but since this is always ephemeral
|
||||
# disable any store optimization from nix.
|
||||
microvm.writableStoreOverlay = "/nix/.rw-store";
|
||||
nix = {
|
||||
settings.auto-optimise-store = mkForce false;
|
||||
optimise.automatic = mkForce false;
|
||||
gc.automatic = mkForce false;
|
||||
};
|
||||
|
||||
networking.renameInterfacesByMac.${guestCfg.networking.mainLinkName} = mac;
|
||||
|
||||
systemd.network.networks = {
|
||||
"10-${guestCfg.networking.mainLinkName}" = {
|
||||
matchConfig.MACAddress = mac;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue