From c9196a1c11ba86a4912da643da925c3a40dc3b24 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Wed, 10 Apr 2024 15:21:01 +0200 Subject: [PATCH 1/2] feat: support rootless containers via home-manager --- README.md | 80 ++++++++++++++++++++++++++++++--- container.nix | 2 + flake.nix | 6 ++- home-manager-module.nix | 99 +++++++++++++++++++++++++++++++++++++++++ nixos-module.nix | 10 ++++- 5 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 home-manager-module.nix diff --git a/README.md b/README.md index f1bd819..1480c3b 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,19 @@ Manages Podman containers and networks on NixOS via [Quadlet](https://docs.podma Compared to alternatives like [`virtualisation.oci-containers`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/oci-containers.nix) or [`arion`](https://github.com/hercules-ci/arion), `quadlet-nix` is special in that: -| | `quadlet-nix` | `oci-containers` | `arion` | -| -------------------------------------------------------- | ------------- | ---------------- | ------- | -| **Supports networks** | ✅ | ❌ | ✅ | -| **Updates / deletes networks on change** | ✅ | / | ❌ | -| **Supports [podman-auto-update](podman-auto-update)** | ✅ | ✅ | ❌ | +| | `quadlet-nix` | `oci-containers` | `arion` | +|-------------------------------------------------------|---------------|------------------|---------| +| **Supports networks** | ✅ | ❌ | ✅ | +| **Updates / deletes networks on change** | ✅ | / | ❌ | +| **Supports [podman-auto-update][podman-auto-update]** | ✅ | ✅ | ❌ | +| **Supports rootless containers** | ✅ | ❌ | ❓ | [podman-auto-update]: https://docs.podman.io/en/latest/markdown/podman-auto-update.1.html -## How + +## How (rootful) + +See [`container.nix`](./container.nix) and [`network.nix`](./network.nix) for all options. ### `flake.nix` @@ -55,4 +59,68 @@ Compared to alternatives like [`virtualisation.oci-containers`](https://github.c } ``` +## How (rootless) + See [`container.nix`](./container.nix) and [`network.nix`](./network.nix) for all options. + +### `flake.nix` + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + home-manager.url = "github:nix-community/home-manager"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + quadlet-nix.url = "github:SEIAROTg/quadlet-nix"; + quadlet-nix.inputs.nixpkgs.follows = "nixpkgs"; + quadlet-nix.inputs.home-manager.follows = "home-manager"; + }; + outputs = { nixpkgs, quadlet-nix, home-manager, ... }@attrs: { + nixosConfigurations.machine = nixpksg.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + ./configuration.nix + home-manager.nixosModules.home-manager + quadlet-nix.nixosModules.quadlet + ]; + }; + }; +} +``` + +### `configuration.nix` + +```nix +{ + # ... + users.users.alice = { + # ... insert your user config here + # The follow lines are the important ones for rootless podman + home = "/home/alice"; + linger = true; + autoSubUidGidRange = true; + }; + home-manager.users.alice = + { pkgs, config, ... }: + { + imports = [ inputs.quadlet-nix.homeManagerModules.default ]; + home.stateVersion = "21.11"; + home.homeDirectory = "/home/alice"; + systemd.user.startServices = "sd-switch"; # This is crucial to ensure the systemd services are (re)started + virtualisation.user.quadlet.containers = { + echo-server = { + autoStart = true; + serviceConfig = { + RestartSec = "10"; + Restart = "always"; + }; + containerConfig = { + image = "docker.io/mendhak/http-https-echo:31"; + publishPorts = [ "127.0.0.1:8080:8080" ]; + userns = "keep-id"; + }; + }; + }; + }; +} +``` diff --git a/container.nix b/container.nix index 15d12fb..a51fd30 100644 --- a/container.nix +++ b/container.nix @@ -431,6 +431,8 @@ let serviceConfigDefault = { Restart = "always"; + # podman rootless requires "newuidmap" (the suid version, not the non-suid one from pkgs.shadow) + Environment = "PATH=/run/wrappers/bin"; TimeoutStartSec = 900; }; in { diff --git a/flake.nix b/flake.nix index 617091d..a60c934 100644 --- a/flake.nix +++ b/flake.nix @@ -1,14 +1,16 @@ { - description = "NixOS module for Podman Quadlet"; + description = "NixOS and home-manager module for Podman Quadlets"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; }; - outputs = { nixpkgs, ... }: + outputs = { self, nixpkgs, ... }: let libUtils = import "${nixpkgs}/nixos/lib/utils.nix"; in { nixosModules.quadlet = import ./nixos-module.nix { inherit libUtils; }; + homeManagerModules.quadlet = import ./home-manager-module.nix { inherit libUtils; }; + homeManagerModules.default = self.homeManagerModules.quadlet; }; } diff --git a/home-manager-module.nix b/home-manager-module.nix new file mode 100644 index 0000000..c2e24b1 --- /dev/null +++ b/home-manager-module.nix @@ -0,0 +1,99 @@ +{ libUtils }: +{ + config, + osConfig, + options, + lib, + pkgs, + ... +}: +let + cfg = config.virtualisation.user.quadlet; + quadletUtils = import ./utils.nix { + inherit lib; + systemdLib = (libUtils { inherit lib config pkgs; }).systemdUtils.lib; + }; + containerOpts = lib.types.submodule (import ./container.nix { inherit quadletUtils; }); + networkOpts = lib.types.submodule (import ./network.nix { inherit quadletUtils pkgs; }); +in +{ + options.virtualisation.user.quadlet = { + autoUpdate = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + }; + calendar = lib.mkOption { + type = lib.types.str; + default = "*-*-* 00:00:00"; + }; + }; + containers = lib.mkOption { + type = lib.types.attrsOf containerOpts; + default = { }; + }; + networks = lib.mkOption { + type = lib.types.attrsOf networkOpts; + default = { }; + }; + }; + config = + let + allObjects = (lib.attrValues cfg.containers) ++ (lib.attrValues cfg.networks); + in + { + xdg.configFile = + let + links = pkgs.linkFarm "user-quadlet-service-symlinks" ( + map (p: { + name = p._unitName; + path = "/run/user/${ + toString osConfig.users.users.${config.home.username}.uid + }/systemd/generator/${p._unitName}"; + }) allObjects + ); + in + lib.mergeAttrsList ( + map (p: { + # Install the .container, .network, etc files + "containers/systemd/${p._configName}" = { + text = p._configText; + }; + # Link the corresponding .service files so that the home-manager activation process knows about them + "systemd/user/${p._unitName}" = { + source = "${links}/${p._unitName}"; + }; + # Inject X-RestartIfChanged=${hash} for NixOS to detect changes. + "systemd/user/${p._unitName}.d/override.conf" = { + text = "[Unit]\nX-RestartIfChanged=${builtins.hashString "sha256" p._configText}"; + }; + }) allObjects + ); + systemd.user.services.podman-auto-update = lib.mkIf cfg.autoUpdate.enable { + Unit = { + Description = "Podman auto-update service"; + Documentation = "man:podman-auto-update(1)"; + }; + Service = { + Type = "oneshot"; + # podman rootless requires "newuidmap" (the suid version, not the non-suid one from pkgs.shadow) + Environment = "PATH=/run/wrappers/bin"; + ExecStart = "${pkgs.podman}/bin/podman auto-update"; + ExecStartPost = "${pkgs.podman}/bin/podman image prune -f"; + TimeoutStartSec = "900s"; + TimeoutStopSec = "10s"; + }; + }; + systemd.user.timers.podman-auto-update = lib.mkIf cfg.autoUpdate.enable { + Unit = { + Description = "Podman auto-update timer"; + Documentation = "man:podman-auto-update(1)"; + }; + Timer = { + OnCalendar = cfg.autoUpdate.calendar; + Persistent = true; + }; + Install.WantedBy = [ "timers.target" ]; + }; + }; +} diff --git a/nixos-module.nix b/nixos-module.nix index 09e1621..a02b799 100644 --- a/nixos-module.nix +++ b/nixos-module.nix @@ -35,7 +35,15 @@ in { allObjects = (attrValues cfg.containers) ++ (attrValues cfg.networks); in { virtualisation.podman.enable = true; - environment.etc = mergeAttrsList ( + environment.etc = + # Ensure podman-user-generator is available for systemd user services. + { + "systemd/user-generators/podman-user-generator" = { + source = "${pkgs.podman}/lib/systemd/user-generators/podman-user-generator"; + target = "systemd/user-generators/podman-user-generator"; + }; + } + // mergeAttrsList ( map (p: { "containers/systemd/${p._configName}" = { text = p._configText; From 37595a78d5b7e8445fa295941092772cf8bd95a6 Mon Sep 17 00:00:00 2001 From: Casey Link Date: Thu, 11 Apr 2024 13:21:12 +0200 Subject: [PATCH 2/2] Add DNS* options --- container.nix | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/container.nix b/container.nix index a51fd30..40da4ee 100644 --- a/container.nix +++ b/container.nix @@ -45,6 +45,30 @@ let property = "ContainerName"; }; + dns = quadletUtils.mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "192.168.55.1" ]; + description = "--dns"; + property = "DNS"; + }; + + dnsSearch = quadletUtils.mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "foo.com" ]; + description = "--dns-search"; + property = "DNSSearch"; + }; + + dnsOption = quadletUtils.mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "ndots:1" ]; + description = "--dns-option"; + property = "DNSOption"; + }; + dropCapabilities = quadletUtils.mkOption { type = types.listOf types.str; default = [ ];