From 789671d6af1bf9c6d6e4e67b40340d859f7783c5 Mon Sep 17 00:00:00 2001 From: Bad Date: Sun, 12 Sep 2021 23:46:22 +0200 Subject: [PATCH] Add podman module --- users/modules/containers.nix | 123 +++++++++++++++++++++ users/modules/podman-dnsname.nix | 36 ++++++ users/modules/podman.nix | 182 +++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 users/modules/containers.nix create mode 100644 users/modules/podman-dnsname.nix create mode 100644 users/modules/podman.nix diff --git a/users/modules/containers.nix b/users/modules/containers.nix new file mode 100644 index 0000000..fccc606 --- /dev/null +++ b/users/modules/containers.nix @@ -0,0 +1,123 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.virtualisation.containers; + + inherit (lib) mkOption types; + + toml = pkgs.formats.toml { }; +in +{ + options.virtualisation.containers = { + + enable = + mkOption { + type = types.bool; + default = false; + description = '' + This option enables the common /etc/containers configuration module. + ''; + }; + + ociSeccompBpfHook.enable = mkOption { + type = types.bool; + default = false; + description = "Enable the OCI seccomp BPF hook"; + }; + + containersConf.settings = mkOption { + type = toml.type; + default = { }; + description = "containers.conf configuration"; + }; + + containersConf.cniPlugins = mkOption { + type = types.listOf types.package; + defaultText = '' + [ + pkgs.cni-plugins + ] + ''; + example = lib.literalExample '' + [ + pkgs.cniPlugins.dnsname + ] + ''; + description = '' + CNI plugins to install on the system. + ''; + }; + + registries = { + search = mkOption { + type = types.listOf types.str; + default = [ "docker.io" "quay.io" ]; + description = '' + List of repositories to search. + ''; + }; + + insecure = mkOption { + default = []; + type = types.listOf types.str; + description = '' + List of insecure repositories. + ''; + }; + + block = mkOption { + default = []; + type = types.listOf types.str; + description = '' + List of blocked repositories. + ''; + }; + }; + + policy = mkOption { + default = {}; + type = types.attrs; + example = lib.literalExample '' + { + default = [ { type = "insecureAcceptAnything"; } ]; + transports = { + docker-daemon = { + "" = [ { type = "insecureAcceptAnything"; } ]; + }; + }; + } + ''; + description = '' + Signature verification policy file. + If this option is empty the default policy file from + skopeo will be used. + ''; + }; + + }; + + config = lib.mkIf cfg.enable { + + virtualisation.containers.containersConf.cniPlugins = [ pkgs.cni-plugins ]; + + virtualisation.containers.containersConf.settings = { + network.cni_plugin_dirs = map (p: "${lib.getBin p}/bin") cfg.containersConf.cniPlugins; + engine = { + init_path = "${pkgs.catatonit}/bin/catatonit"; + } // lib.optionalAttrs cfg.ociSeccompBpfHook.enable { + hooks_dir = [ config.boot.kernelPackages.oci-seccomp-bpf-hook ]; + }; + }; + + xdg.configFile."containers/containers.conf".source = + toml.generate "containers.conf" cfg.containersConf.settings; + + xdg.configFile."containers/registries.conf".source = toml.generate "registries.conf" { + registries = lib.mapAttrs (n: v: { registries = v; }) cfg.registries; + }; + + xdg.configFile."containers/policy.json".source = + if cfg.policy != {} then pkgs.writeText "policy.json" (builtins.toJSON cfg.policy) + else "${pkgs.skopeo.src}/default-policy.json"; + }; + +} diff --git a/users/modules/podman-dnsname.nix b/users/modules/podman-dnsname.nix new file mode 100644 index 0000000..3df4955 --- /dev/null +++ b/users/modules/podman-dnsname.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib) + mkOption + mkIf + types + ; + + cfg = config.services.podman; + +in +{ + options = { + services.podman = { + + defaultNetwork.dnsname.enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable DNS resolution in the default podman network. + ''; + }; + + }; + }; + + config = { + virtualisation.containers.containersConf.cniPlugins = mkIf cfg.defaultNetwork.dnsname.enable [ pkgs.dnsname-cni ]; + services.podman.defaultNetwork.extraPlugins = + lib.optional cfg.defaultNetwork.dnsname.enable { + type = "dnsname"; + domainName = "dns.podman"; + capabilities.aliases = true; + }; + }; +} diff --git a/users/modules/podman.nix b/users/modules/podman.nix new file mode 100644 index 0000000..7d53f81 --- /dev/null +++ b/users/modules/podman.nix @@ -0,0 +1,182 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.podman; + toml = pkgs.formats.toml { }; + json = pkgs.formats.json { }; + + inherit (lib) mkOption types; + + podmanPackage = (pkgs.podman.override { inherit (cfg) extraPackages; }); + + # Provides a fake "docker" binary mapping to podman + dockerCompat = pkgs.runCommandNoCC "${podmanPackage.pname}-docker-compat-${podmanPackage.version}" + { + outputs = [ "out" "man" ]; + inherit (podmanPackage) meta; + } '' + mkdir -p $out/bin + ln -s ${podmanPackage}/bin/podman $out/bin/docker + + mkdir -p $man/share/man/man1 + for f in ${podmanPackage.man}/share/man/man1/*; do + basename=$(basename $f | sed s/podman/docker/g) + ln -s $f $man/share/man/man1/$basename + done + ''; + + net-conflist = pkgs.runCommand "87-podman-bridge.conflist" + { + nativeBuildInputs = [ pkgs.jq ]; + extraPlugins = builtins.toJSON cfg.defaultNetwork.extraPlugins; + jqScript = '' + . + { "plugins": (.plugins + $extraPlugins) } + ''; + } '' + jq <${cfg.package}/etc/cni/net.d/87-podman-bridge.conflist \ + --argjson extraPlugins "$extraPlugins" \ + "$jqScript" \ + >$out + ''; + +in +{ + imports = [ + ./podman-dnsname.nix + #./podman-network-socket.nix + (lib.mkRenamedOptionModule [ "virtualisation" "podman" "libpod" ] [ "virtualisation" "containers" "containersConf" ]) + ]; + + meta = { + maintainers = lib.teams.podman.members; + }; + + options.services.podman = { + + enable = + mkOption { + type = types.bool; + default = false; + description = '' + This option enables Podman, a daemonless container engine for + developing, managing, and running OCI Containers on your Linux System. + + It is a drop-in replacement for the docker command. + ''; + }; + + dockerSocket.enable = mkOption { + type = types.bool; + default = false; + description = '' + Make the Podman socket available in place of the Docker socket, so + Docker tools can find the Podman socket. + + Podman implements the Docker API. + ''; + }; + + dockerCompat = mkOption { + type = types.bool; + default = false; + description = '' + Create an alias mapping docker to podman. + ''; + }; + + enableNvidia = mkOption { + type = types.bool; + default = false; + description = '' + Enable use of NVidia GPUs from within podman containers. + ''; + }; + + extraPackages = mkOption { + type = with types; listOf package; + default = [ ]; + example = lib.literalExample '' + [ + pkgs.gvisor + ] + ''; + description = '' + Extra packages to be installed in the Podman wrapper. + ''; + }; + + package = lib.mkOption { + type = types.package; + default = podmanPackage; + internal = true; + description = '' + The final Podman package (including extra packages). + ''; + }; + + defaultNetwork.extraPlugins = lib.mkOption { + type = types.listOf json.type; + default = [ ]; + description = '' + Extra CNI plugin configurations to add to podman's default network. + ''; + }; + + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + home.packages = [ cfg.package ] + ++ lib.optional cfg.dockerCompat dockerCompat; + + xdg.configFile."cni/net.d/87-podman-bridge.conflist".source = net-conflist; + + virtualisation.containers = { + enable = true; # Enable common /etc/containers configuration + containersConf.settings = lib.optionalAttrs cfg.enableNvidia { + engine = { + conmon_env_vars = [ "PATH=${lib.makeBinPath [ pkgs.nvidia-podman ]}" ]; + runtimes.nvidia = [ "${pkgs.nvidia-podman}/bin/nvidia-container-runtime" ]; + }; + }; + }; + + systemd.user = { + + services.podman = { + Unit = { + Description = "Podman API Service"; + Requires = "podman.socket"; + After = "podman.socket"; + Documentation = "man:podman-system-service(1)"; + StartLimitIntervalSec = 0; + }; + Service = { + Type = "exec"; + KillMode = "process"; + Environment = "LOGGING=\" --log-level=info\""; + ExecStart = [ "" "${cfg.package}/bin/podman $LOGGING system service" ]; + }; + + Install = { + WantedBy = [ "multi-user.target" ]; + }; + }; + + sockets.podman = { + Unit = { + Description = "Podman API Socket"; + Documentation = "man:podman-system-service(1)"; + }; + Socket = { + ListenStream = "%t/podman/podman.sock"; + SocketMode = 0660; + }; + Install.WantedBy = [ "sockets.target" ]; + }; + + }; + } + (lib.mkIf cfg.dockerSocket.enable { + home.sessionVariables."DOCKER_HOST" = "unix:///run/user/$UID/podman/podman.sock"; }) + ]); + }