Switch over to nix flakes and introduce podman pods #26
					 3 changed files with 229 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -14,6 +14,8 @@
 | 
			
		|||
          system = "x86_64-linux";
 | 
			
		||||
 | 
			
		||||
          modules = [
 | 
			
		||||
            (import ./modules)
 | 
			
		||||
 | 
			
		||||
            (import ./configuration)
 | 
			
		||||
            (import ./configuration/linode.nix)
 | 
			
		||||
            (import ./configuration/hardware-configuration.nix)
 | 
			
		||||
| 
						 | 
				
			
			@ -25,6 +27,8 @@
 | 
			
		|||
          system = "x86_64-linux";
 | 
			
		||||
 | 
			
		||||
          modules = [
 | 
			
		||||
            (import ./modules)
 | 
			
		||||
 | 
			
		||||
            (import ./configuration)
 | 
			
		||||
            ({ ... }: {
 | 
			
		||||
              users.users.tlater.password = "insecure";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								modules/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								modules/default.nix
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
{ ... }:
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  imports = [ ./virtualisation/pods.nix ];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								modules/virtualisation/pods.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								modules/virtualisation/pods.nix
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,220 @@
 | 
			
		|||
{ lib, config, options, ... }:
 | 
			
		||||
 | 
			
		||||
with lib;
 | 
			
		||||
 | 
			
		||||
let
 | 
			
		||||
  cfg = config.virtualisation.pods;
 | 
			
		||||
  list-to-args = arg: list:
 | 
			
		||||
    concatStringsSep " " (map (e: "--${arg}=${escapeShellArg e}") list);
 | 
			
		||||
  possibly-unset-arg = arg: val:
 | 
			
		||||
    (optionalString (val != null) "--${arg}=${escapeShellArg val}");
 | 
			
		||||
 | 
			
		||||
  mkPod = name: pod: rec {
 | 
			
		||||
    path = [ config.virtualisation.podman.package ];
 | 
			
		||||
 | 
			
		||||
    wants = [ "network.target" ];
 | 
			
		||||
    after = [ "network-online.target" ];
 | 
			
		||||
    wantedBy = [ "multi-user.target" "default.target" ];
 | 
			
		||||
 | 
			
		||||
    environment.PODMAN_SYSTEMD_UNIT = "%n";
 | 
			
		||||
 | 
			
		||||
    preStart = concatStringsSep " " [
 | 
			
		||||
      "mkdir -p /run/podman/pods/ ;"
 | 
			
		||||
      "podman pod create"
 | 
			
		||||
      "--infra-conmon-pidfile=${escapeShellArg "/run/podman/pods/${name}.pid"}"
 | 
			
		||||
      "--name=${escapeShellArg name}"
 | 
			
		||||
      "--replace"
 | 
			
		||||
      (list-to-args "add-host" pod.added-hosts)
 | 
			
		||||
      (possibly-unset-arg "cgroup-parent" pod.cgroup-parent)
 | 
			
		||||
      (list-to-args "dns" pod.dns)
 | 
			
		||||
      (list-to-args "dns-opt" pod.dns-opt)
 | 
			
		||||
      (list-to-args "dns-search" pod.dns-search)
 | 
			
		||||
      (possibly-unset-arg "hostname" pod.hostname)
 | 
			
		||||
      (possibly-unset-arg "infra" pod.infra)
 | 
			
		||||
      (possibly-unset-arg "infra-command" pod.infra-command)
 | 
			
		||||
      (possibly-unset-arg "infra-image" pod.infra-image)
 | 
			
		||||
      (possibly-unset-arg "ip" pod.ip)
 | 
			
		||||
      (possibly-unset-arg "mac-address" pod.mac-address)
 | 
			
		||||
      (possibly-unset-arg "network" pod.network)
 | 
			
		||||
      (possibly-unset-arg "network-alias" pod.network-alias)
 | 
			
		||||
      (possibly-unset-arg "no-hosts" pod.no-hosts)
 | 
			
		||||
      (list-to-args "publish" pod.publish)
 | 
			
		||||
      (list-to-args "share" pod.share)
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    script = "podman pod start ${escapeShellArg name}";
 | 
			
		||||
    preStop = "podman pod stop ${escapeShellArg name}";
 | 
			
		||||
    # `podman generate systemd` generates a second stop after the
 | 
			
		||||
    # first; not sure why but clearly it's recommended.
 | 
			
		||||
    postStop = preStop;
 | 
			
		||||
 | 
			
		||||
    serviceConfig = rec {
 | 
			
		||||
      Type = "forking";
 | 
			
		||||
      TimeoutStopSec = 70;
 | 
			
		||||
      Restart = "on-failure";
 | 
			
		||||
      PIDFile = "/run/podman/pods/${name}.pid";
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
in {
 | 
			
		||||
  options.virtualisation.pods = mkOption {
 | 
			
		||||
    type = with types;
 | 
			
		||||
      attrsOf (submodule {
 | 
			
		||||
        options = {
 | 
			
		||||
          added-hosts = mkOption {
 | 
			
		||||
            type = listOf str;
 | 
			
		||||
            default = [ ];
 | 
			
		||||
            description =
 | 
			
		||||
              "Additional hosts to add to /etc/hosts for each container.";
 | 
			
		||||
            example = literalExample ''
 | 
			
		||||
              [ "database:10.0.0.1" ]
 | 
			
		||||
            '';
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          cgroup-parent = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description =
 | 
			
		||||
              "The cgroups path under which the pod cgroup will be created.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          dns = mkOption {
 | 
			
		||||
            type = listOf str;
 | 
			
		||||
            default = [ ];
 | 
			
		||||
            description = "The dns servers to set in /etc/resolv.conf.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          dns-opt = mkOption {
 | 
			
		||||
            type = listOf str;
 | 
			
		||||
            default = [ ];
 | 
			
		||||
            description = "dns options to set in /etc/resolv.conf.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          dns-search = mkOption {
 | 
			
		||||
            type = listOf str;
 | 
			
		||||
            default = [ ];
 | 
			
		||||
            description = "Search domains to set in /etc/resolv.conf.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          hostname = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "The pod hostname.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          infra = mkOption {
 | 
			
		||||
            type = nullOr bool;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "Whether to create the infra container for the pod.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          infra-command = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "The command to run in the infra container.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          infra-image = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "The image to use for the infra container.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          ip = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "A static IP address for the pod network.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          # TODO: set up label file stuff.
 | 
			
		||||
          #
 | 
			
		||||
          # labels = mkOption {};
 | 
			
		||||
 | 
			
		||||
          mac-address = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "A static mac address for the pod network.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          network = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "Network configuration for the pod.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          network-alias = mkOption {
 | 
			
		||||
            type = nullOr str;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "DNS alias for the pod.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          no-hosts = mkOption {
 | 
			
		||||
            type = nullOr bool;
 | 
			
		||||
            default = null;
 | 
			
		||||
            description = "Whether to disable /etc/hosts creation for the pod.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          publish = mkOption {
 | 
			
		||||
            type = listOf str;
 | 
			
		||||
            default = [ ];
 | 
			
		||||
            description = "List of ports to publish from the pod.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          share = mkOption {
 | 
			
		||||
            type = listOf str;
 | 
			
		||||
            default = [ ];
 | 
			
		||||
            description = "List of kernel namespaces to share.";
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          containers = options.virtualisation.oci-containers.containers;
 | 
			
		||||
        };
 | 
			
		||||
      });
 | 
			
		||||
    default = { };
 | 
			
		||||
    description = "Podman pods to run as systemd services.";
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  config = let
 | 
			
		||||
    # Merge a list of attribute sets together
 | 
			
		||||
    #
 | 
			
		||||
    # TODO: See if there's a generic version for this somewhere in the
 | 
			
		||||
    # pkgs lib?
 | 
			
		||||
    mergeAttrs = attrList: foldr (a: b: a // b) { } attrList;
 | 
			
		||||
 | 
			
		||||
    # Create services for all defined pods
 | 
			
		||||
    pod-services = mapAttrs' (n: v: nameValuePair "pod-${n}" (mkPod n v)) cfg;
 | 
			
		||||
 | 
			
		||||
    # Override the systemd-specific settings of containers defined in
 | 
			
		||||
    # pods.
 | 
			
		||||
    #
 | 
			
		||||
    # I.e., make a systemd unit dependency on the pod service.
 | 
			
		||||
    pod-container-services = mergeAttrs (mapAttrsToList (pname: pod:
 | 
			
		||||
      mapAttrs' (cname: container:
 | 
			
		||||
        nameValuePair "podman-${pname}-${cname}" rec {
 | 
			
		||||
          after = [ "pod-${pname}.service" ];
 | 
			
		||||
          requires = after;
 | 
			
		||||
        }) pod.containers) cfg);
 | 
			
		||||
 | 
			
		||||
    # Override the oci-container settings for containers defined in pods.
 | 
			
		||||
    #
 | 
			
		||||
    # I.e., set the --pod=podname setting, and update the dependsOn so
 | 
			
		||||
    # it points to containers in the same pod.
 | 
			
		||||
    podifyContainer = container: podname:
 | 
			
		||||
      container // {
 | 
			
		||||
        dependsOn =
 | 
			
		||||
          map (dependency: "${podname}-${dependency}") container.dependsOn;
 | 
			
		||||
        extraOptions = container.extraOptions ++ [ "--pod=${podname}" ];
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
  in lib.mkIf (cfg != { }) {
 | 
			
		||||
    virtualisation.podman.enable = true;
 | 
			
		||||
    virtualisation.oci-containers.backend = "podman";
 | 
			
		||||
 | 
			
		||||
    systemd.services = pod-services // pod-container-services;
 | 
			
		||||
 | 
			
		||||
    virtualisation.oci-containers.containers = mergeAttrs (mapAttrsToList
 | 
			
		||||
      (pname: pod:
 | 
			
		||||
        mapAttrs' (cname: container:
 | 
			
		||||
          nameValuePair "${pname}-${cname}" (podifyContainer container pname))
 | 
			
		||||
        pod.containers) cfg);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue