quadlet-nix

repository·main·Indexed 18 days ago

https://github.com/seiarotg/quadlet-nix

A declarative Nix interface for managing Podman resources via Quadlet. It allows for the management of containers, networks, pods, and volumes within NixOS and Home Manager configurations, supporting both rootful and rootless resources, Podman auto-update, and cross-referencing between resources using Nix syntax.

Tokens
2.7K
Snippets
7
Records
10
Agent score
13%

What's inside quadlet-nix

  1. Overview of quadlet-nix

    main

    quadlet-nix is a tool for managing Podman resources (containers, networks, pods, volumes, etc.) on NixOS using Quadlet. It maps Quadlet options directly into the Nix language, allowing for declarative management of Podman resources within your Nix configuration.

    Key features include:

    • Support for both rootful and rootless resources (via Home Manager).
    • Declarative update and deletion of networks.
    • Support for Podman auto-update.
    • Cross-referencing between resources using Nix language syntax.
    • Full support for Quadlet options with proper typing and escaping.
  2. Compare quadlet-nix with other Podman management tools

    main

    When choosing how to manage Podman on NixOS, consider these comparisons:

    ToolProsCons
    quadlet-nixFull Quadlet support, rootful & rootless, declarative networks/pods, Nix cross-referencing.
    NixOS virtualisation.oci-containersPart of NixOS, supports Docker, rootless support.Limited options, lacks support for networks/pods.
    arionSupports Docker.More indirection, limited options, incompatible with podman auto-update.
    Vanilla Podman QuadletLeast indirection.Requires manual setup, not integrated with Nix configuration.
    Home Manager services.podmanPart of Home Manager.Lacks rootful container support.
    compose2nixSupports Docker.Requires manual regeneration, less maintainable Nix files, lacks rootless support.
  3. Configure Rootful containers with quadlet-nix

    main

    To run containers as root, add quadlet-nix.nixosModules.quadlet to your NixOS system modules. You can define containers, networks, and pods within the virtualisation.quadlet option. Use the .ref attribute to create dependencies between components (e.g., linking a container to a network or a pod).

    # flake.nix snippet
    modules = [
        ./configuration.nix
        quadlet-nix.nixosModules.quadlet
    ];
    
    # configuration.nix snippet
    virtualisation.quadlet = let
        inherit (config.virtualisation.quadlet) networks pods;
    in {
        containers = {
            nginx.containerConfig.image = "docker.io/library/nginx:latest";
            nginx.containerConfig.networks = [ "podman" networks.internal.ref ];
            nginx.containerConfig.pod = pods.foo.ref;
            nginx.serviceConfig.TimeoutStartSec = "60";
        };
        networks = {
            internal.networkConfig.subnets = [ "10.0.123.1/24" ];
        };
        pods = {
            foo = { };
        };
    };
  4. Build containers from Containerfiles or Git repositories

    main

    You can trigger container builds via quadlet-nix using two methods:

    1. Inlined Containerfile: Use pkgs.writeText to create a Containerfile and assign its outPath to builds.<name>.buildConfig.file.
    2. Git Repository: Use builtins.fetchGit to retrieve a repository and assign it to builds.<name>.buildConfig.workdir. Alternatively, use Podman's native git integration by setting workdir to a git URL (requires git to be in the build service PATH).

    Reference the build using containers.<name>.containerConfig.image = builds.<name>.ref;.

    # Inlined Containerfile
    virtualisation.quadlet = let
        inherit (config.virtualisation.quadlet) builds;
        containerfile = pkgs.writeText "Containerfile" ''
          FROM docker.io/library/nginx:latest
          # ...
        '';
    in {
        containers.nginx.containerConfig.image = builds.nginx.ref;
        builds.nginx.buildConfig.file = containerfile.outPath;
    };
    
    # Git repository
    virtualisation.quadlet = let
        inherit (config.virtuallet) builds;
        src = builtins.fetchGit {
          url = "https://github.com/alpinelinux/docker-alpine.git";
          rev = "4dc13cbc7caffe03c98aa99f28e27c2fb6f7e74d";
        };
    in {
        containers.example.containerConfig = {
          image = builds.alpine.ref;
          entrypoint = "/bin/sh";
          exec = "-c 'echo 123'";
        };
        builds.alpine.buildConfig = {
          tag = "alpine:3.22";
          workdir = "${src}/x86_64";
        };
    };
  5. Configure Rootless containers via Home Manager

    main

    For rootless containers managed by Home Manager, follow these requirements:

    1. In your NixOS configuration, enable the module: virtualisation.quadlet.enable = true.
    2. Enable user linger = true to allow containers to start before user login.
    3. Set autoSubUidGidRange = true for the user to support rootless containers with multiple users.
    4. In Home Manager, import inputs.quadlet-nix.homeManagerModules.quadlet.

    Container configurations can include autoStart, serviceConfig (for systemd settings), and containerConfig (for Podman settings like image, publishPorts, and userns).

    # NixOS configuration
    virtualisation.quadlet.enable = true;
    users.users.alice = {
        linger = true;
        autoSubUidGidRange = true;
    };
    
    # Home Manager configuration
    home-manager.users.alice = { pkgs, config, ... }: {
        imports = [ inputs.quadlet-nix.homeManagerModules.quadlet ];
        virtualisation.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";
                };
            };
        };
    };
  6. Configure Podman DNS and Firewall

    main

    To ensure Podman DNS works, you must enable it and allow UDP port 53 through your firewall.

    For the default network: Set virtualisation.podman.defaultNetwork.settings.dns_enabled = true;.

    For custom Quadlet networks: Podman DNS is enabled by default. You must manually allow UDP port 53 on the specific interface assigned to that network. For example, if networkConfig.interfaceName = "br-foo";, you must add networking.firewall.interfaces.br-foo.allowedUDPPorts = [ 53 ];.

    # Default network setup
    virtualisation.podman.defaultNetwork.settings.dns_enabled = true;
    
    # Custom network setup
    virtualisation.quadlet.networks.foo.networkConfig.interfaceName = "br-foo";
    networking.firewall.interfaces.br-foo.allowedUDPPorts = [ 53 ];
  7. Configure Volumes in quadlet-nix

    main

    Define volumes using the virtualisation.quadlet.volumes attribute. You can then reference these volumes in your container configuration using the .ref syntax within the containerConfig.volumes list.

    virtualisation.quadlet = let
        inherit (config.virtualisation.quadlet) volumes;
    in {
        containers.nginx.containerConfig.image = "docker.io/library/nginx:latest";
        containers.nginx.containerConfig.volumes = [
            "${volumes.nginx-config.ref}:/etc/nginx"
        ];
        volumes.nginx-config.volumeConfig = {
            type = "bind";
            device = "/path/to/host/directory";
        };
    };
  8. Use raw Quadlet files via rawConfig

    main

    If you prefer writing standard Quadlet files instead of using Nix options, use the rawConfig attribute.

    Warning: Using rawConfig causes all other options (except autoStart) to be ignored for that specific component.

    virtualisation.quadlet.containers.nginx.rawConfig = ''
        [Container]
        Image=docker.io/library/nginx:latest
        Network=podman
        Network=${networks.internal.ref}
        Pod=${pods.foo.ref}
        [Service]
        TimeoutStartSec=60
    '';
  9. Debug and access container logs via systemd

    main

    Because quadlet-nix manages containers via systemd, containers that crash may be deleted by Podman, making podman ps -a or podman logs ineffective.

    Instead, use systemd tools to inspect status and logs:

    • Status: systemctl status <service name>
    • Logs: journalctl -u <service name>

    Service Naming Convention: Use the names defined in your Nix configuration:

    • Container: <container name>
    • Network: <network name>-network
    • Pod: <pod name>-pod