diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 6792fa4..ce81bf8 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -13,4 +13,5 @@ - [TODO](./todo.md) - [How-to]() - [Updates](./anleitung/updates.md) - - [Rollbacks](./anleitung/rollback.md) \ No newline at end of file + - [Rollbacks](./anleitung/rollback.md) + - [MicroVM](./anleitung/microvm.md) diff --git a/doc/src/anleitung/microvm.md b/doc/src/anleitung/microvm.md new file mode 100644 index 0000000..86f13c5 --- /dev/null +++ b/doc/src/anleitung/microvm.md @@ -0,0 +1,52 @@ +### Declaring a MicroVM + +The hosts nixosSystems modules should be declared using the ```makeMicroVM``` helper function. +Use durruti as orientation: +``` nix + modules = makeMicroVM "durruti" "10.0.0.5" [ + ./durruti/configuration.nix + ]; +``` + +"durruti" is the hostname. +"10.0.0.5" is the IP assigned to its tap interface. + +### Testing MicroVMs locally +MicroVMs can be built and run easily on your local host. +For durruti this is done by: +``` bash +sudo nix run .\#nixosConfigurations.durruti.config.microvm.declaredRunner +``` + +It seems to be necessary to run this as root so that the according tap interface can be created. +To be able to ping the VM or give Internet Access to the VM your host needs to be setup as described below. + +### Host Setup + +#### Network Bridge +To provide network access to the VMs a bridge interface needs to be created on your host. +For that: +- Add the infrastructure flake as input to your hosts flake +- Add ```inputs.malobeo.nixosModules.malobeo``` to your hosts imports +- enable the host bridge: ```services.malobeo.microvm.enableHostBridge = true;``` + +If you want to provide Internet access to the VM it is necessary to create a nat. +This could be done like this: +``` nix +networking.nat = { + enable = true; + internalInterfaces = [ "microvm" ]; + externalInterface = "eth0"; #change to your interface name +}; +``` +#### Auto Deploy VMs +By default no MicroVMs will be initialized on the host - this should be done using the microvm commandline tool. +But since we want to always deploy certain VMs it can be configured using the ```malobeo.microvm.deployHosts``` option. +VMs configured using this option will be initialized and autostarted at boot. +Updating still needs to be done imperative, or by enabling autoupdates.nix + +The following example would init and autostart durruti and gitea: +``` nix +malobeo.microvm.deployHosts = [ "durruti" "gitea" ]; +``` + diff --git a/flake.lock b/flake.lock index b4c528b..999afbf 100644 --- a/flake.lock +++ b/flake.lock @@ -21,6 +21,24 @@ "url": "https://git.dynamicdiscord.de/kalipso/ep3-bs.nix" } }, + "flake-utils": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -61,6 +79,28 @@ "type": "github" } }, + "microvm": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "spectrum": "spectrum" + }, + "locked": { + "lastModified": 1731240174, + "narHash": "sha256-HYu+bPoV3UILhwc4Ar5iQ7aF+DuQWHXl4mljN6Bwq6A=", + "owner": "astro", + "repo": "microvm.nix", + "rev": "dd89404e1885b8d7033106f3898eaef8db660cb2", + "type": "github" + }, + "original": { + "owner": "astro", + "repo": "microvm.nix", + "type": "github" + } + }, "nixlib": { "locked": { "lastModified": 1729386149, @@ -182,6 +222,7 @@ "ep3-bs": "ep3-bs", "home-manager": "home-manager", "mfsync": "mfsync", + "microvm": "microvm", "nixos-generators": "nixos-generators", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", @@ -212,6 +253,22 @@ "type": "github" } }, + "spectrum": { + "flake": false, + "locked": { + "lastModified": 1729945407, + "narHash": "sha256-iGNMamNOAnVTETnIVqDWd6fl74J8fLEi1ejdZiNjEtY=", + "ref": "refs/heads/main", + "rev": "f1d94ee7029af18637dbd5fdf4749621533693fa", + "revCount": 764, + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + }, + "original": { + "type": "git", + "url": "https://spectrum-os.org/git/spectrum" + } + }, "systems": { "locked": { "lastModified": 1681028828, @@ -257,6 +314,21 @@ "type": "github" } }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "tasklist": { "inputs": { "nixpkgs": [ @@ -315,7 +387,7 @@ }, "utils_3": { "inputs": { - "systems": "systems_3" + "systems": "systems_4" }, "locked": { "lastModified": 1726560853, diff --git a/flake.nix b/flake.nix index 68c262c..c02f881 100644 --- a/flake.nix +++ b/flake.nix @@ -8,6 +8,8 @@ sops-nix.url = "github:Mic92/sops-nix"; sops-nix.inputs.nixpkgs.follows = "nixpkgs"; mfsync.url = "github:k4lipso/mfsync"; + microvm.url = "github:astro/microvm.nix"; + microvm.inputs.nixpkgs.follows = "nixpkgs"; utils = { url = "github:numtide/flake-utils"; diff --git a/machines/configuration.nix b/machines/configuration.nix index 4509ea8..a2c2456 100644 --- a/machines/configuration.nix +++ b/machines/configuration.nix @@ -40,6 +40,39 @@ let } ]; defaultModules = baseModules; + + makeMicroVM = hostName: ipv4Addr: modules: [ + inputs.microvm.nixosModules.microvm + { + microvm = { + hypervisor = "qemu"; + shares = [ { + tag = "ro-store"; + source = "/nix/store"; + mountPoint = "/nix/.ro-store"; + } ]; + interfaces = [ + { + type = "tap"; + id = "vm-${hostName}"; + mac = "02:00:00:00:00:01"; + } + ]; + }; + + systemd.network.enable = true; + + systemd.network.networks."20-lan" = { + matchConfig.Type = "ether"; + networkConfig = { + Address = [ "${ipv4Addr}/24" ]; + Gateway = "10.0.0.1"; + DNS = ["1.1.1.1"]; + DHCP = "no"; + }; + }; + } + ] ++ defaultModules ++ modules; in { louise = nixosSystem { @@ -53,7 +86,7 @@ in durruti = nixosSystem { system = "x86_64-linux"; specialArgs.inputs = inputs; - modules = defaultModules ++ [ + modules = makeMicroVM "durruti" "10.0.0.5" [ ./durruti/configuration.nix ]; }; diff --git a/machines/durruti/configuration.nix b/machines/durruti/configuration.nix index 9b458a8..70c6837 100644 --- a/machines/durruti/configuration.nix +++ b/machines/durruti/configuration.nix @@ -5,7 +5,6 @@ with lib; { sops.defaultSopsFile = ./secrets.yaml; - boot.isContainer = true; networking = { hostName = mkDefault "durruti"; useDHCP = false; diff --git a/machines/durruti/host_config.nix b/machines/durruti/host_config.nix index c846990..418bbeb 100644 --- a/machines/durruti/host_config.nix +++ b/machines/durruti/host_config.nix @@ -44,6 +44,5 @@ in enableACME= true; locations."/".proxyPass = "http://${cfg.host_ip}:80"; }; - }; } diff --git a/machines/modules/malobeo/microvm_host.nix b/machines/modules/malobeo/microvm_host.nix new file mode 100644 index 0000000..8846a4b --- /dev/null +++ b/machines/modules/malobeo/microvm_host.nix @@ -0,0 +1,89 @@ +{ config, self, lib, inputs, options, pkgs, ... }: + +with lib; + +let + cfg = config.services.malobeo.microvm; +in +{ + options = { + services.malobeo.microvm = { + enableHostBridge = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc "Setup bridge device for microvms."; + }; + + enableHostBridgeUnstable = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc "Setup bridge device for microvms."; + }; + + deployHosts = mkOption { + default = []; + type = types.listOf types.str; + description = '' + List hostnames of MicroVMs that should be automatically initializes and autostart + ''; + }; + }; + }; + + + imports = [ + inputs.microvm.nixosModules.host + ]; + + config = { + assertions = [ + { + assertion = !(cfg.enableHostBridgeUnstable && cfg.enableHostBridge); + message = '' + Only enableHostBridge or enableHostBridgeUnstable! Not Both! + ''; + } + ]; + + systemd.network = mkIf (cfg.enableHostBridge || cfg.enableHostBridgeUnstable) { + enable = true; + # create a bride device that all the microvms will be connected to + netdevs."10-microvm".netdevConfig = { + Kind = "bridge"; + Name = "microvm"; + }; + + networks."10-microvm" = { + matchConfig.Name = "microvm"; + networkConfig = { + DHCPServer = true; + IPv6SendRA = true; + }; + addresses = if cfg.enableHostBridgeUnstable then [ + { Address = "10.0.0.1/24"; } + ] else [ + { addressConfig.Address = "10.0.0.1/24"; } + ]; + }; + + # connect the vms to the bridge + networks."11-microvm" = { + matchConfig.Name = "vm-*"; + networkConfig.Bridge = "microvm"; + }; + }; + + microvm.vms = + let + # Map the values to each hostname to then generate a Attrs using listToAttrs + mapperFunc = name: { inherit name; value = { + # Host build-time reference to where the MicroVM NixOS is defined + # under nixosConfigurations + flake = inputs.malobeo; + # Specify from where to let `microvm -u` update later on + updateFlake = "git+https://git.dynamicdiscord.de/kalipso/infrastructure?ref=microvm"; + }; }; + in + builtins.listToAttrs (map mapperFunc cfg.deployHosts); + }; +} diff --git a/outputs.nix b/outputs.nix index 042216d..3458614 100644 --- a/outputs.nix +++ b/outputs.nix @@ -41,7 +41,7 @@ in (utils.lib.eachSystem (builtins.filter filter_system utils.lib.defaultSystems apps = { docs = { type = "app"; - program = builtins.toString (pkgs.writeScript "docs" '' + program = builtins.toString (pkgs.writeShellScript "docs" '' ${pkgs.mdbook}/bin/mdbook serve --open ./doc ''); }; @@ -52,7 +52,10 @@ in (utils.lib.eachSystem (builtins.filter filter_system utils.lib.defaultSystems inherit inputs; }); - nixosModules.malobeo = import ./machines/durruti/host_config.nix; + nixosModules.malobeo.imports = [ + ./machines/durruti/host_config.nix + ./machines/modules/malobeo/microvm_host.nix + ]; hydraJobs = nixpkgs.lib.mapAttrs (_: nixpkgs.lib.hydraJob) ( let