podman: 5.8.9 -> 6.1.4 (#566901)

This commit is contained in:
Sefa Eyeoglu
2026-10-26 15:16:17 +00:00
committed by GitHub
10 changed files with 376 additions and 186 deletions

View File

@@ -294,6 +294,30 @@
Deployments running the server and worker in the same network namespace must also set at least the worker
`AUTHENTIK_LISTEN__HTTP` address so that the server and worker do not bind to the same address.
- `podman` has been updated to Podman 6.
- BoltDB support was dropped. Podman has been automatically migrating to SQLite since 5.8.0 on system reboots.
- `iptables` support was dropped, Podman now unconditionally uses its `nftables` backend.
This has the side effect that DNS in custom networks no longer works for rootful containers without a corresponding firewall rule when using the `iptables` or `nftables` firewall backend.
The `firewalld` backend is not affected.
`virtualisation.podman.dns` has been introduced to allow DNS traffic configuration.
Network interfaces whose name starts with `podman` are allowed by default.
If you have custom podman networks with non-default interface names, add them to `virtualisation.podman.dns.interfaces`.
- `netavark` is now the only supported networking backend.
- `slirp4netns` is no longer supported for rootless networking, `pasta` is now the default and only available option.
Existing containers using `slirp4netns` must be migrated using `podman system migrate`.
- Configuration was rewritten and now follows the [UAPI.6 Configuration Files Specification](https://uapi-group.org/specifications/specs/configuration_files_specification/).
See https://github.com/podman-container-tools/podman/blob/v6.0.0/contrib/design-docs/config-file-parsing.md.
Configuration files are now split into common, rootful and rootless versions.
`virtualisation.containers` was updated to support the new configuration format.
Configurations which set `graphroot` or `runroot` must move these from the common configuration to the rootful config
because rootless podman reads this configuration now as well.
- Upgrading with `nixos-rebuild boot` and rebooting is recommended, to complete the BoltDB migration and drop stale iptables rules.
- See upstream release notes: https://github.com/podman-container-tools/podman/blob/v6.1.2/RELEASE_NOTES.md#600
- `qt.platformTheme` no longer supports the `gtk2` option as GTK 2 had reached end-of-life and will be removed in Nixpkgs.
- `pkgs.php` now points to PHP 8.5

View File

@@ -9,21 +9,65 @@ let
inherit (lib) literalExpression mkOption types;
oldRegistriesOptionsUsed = lib.any (x: x != [ ]) (
with cfg.registries;
[
search
insecure
block
]
);
toml = pkgs.formats.toml { };
json = pkgs.formats.json { };
mkOptions = file: {
rootless.settings = mkOption {
type = toml.type;
default = { };
description = "rootless ${file} configuration";
};
rootful.settings = mkOption {
type = toml.type;
default = { };
description = "rootful ${file} configuration";
};
settings = mkOption {
type = toml.type;
default = { };
description = "base ${file} configuration";
};
};
in
{
meta = {
teams = [ lib.teams.podman ];
};
imports = [
(lib.mkRemovedOptionModule [
"virtualisation"
"containers"
"containersConf"
"cniPlugins"
] "Podman 6.0 removed support for CNI networking.")
(lib.mkRemovedOptionModule
[
"virtualisation"
"containers"
"registries"
"search"
]
"Podman 6.0 dropped support for the deprecated V1 registry.conf format. Migrate to virtualisation.containers.registries.settings."
)
(lib.mkRemovedOptionModule
[
"virtualisation"
"containers"
"registries"
"insecure"
]
"Podman 6.0 dropped support for the deprecated V1 registry.conf format. Migrate to virtualisation.containers.registries.settings."
)
(lib.mkRemovedOptionModule
[
"virtualisation"
"containers"
"registries"
"block"
]
"Podman 6.0 dropped support for the deprecated V1 registry.conf format. Migrate to virtualisation.containers.registries.settings."
)
];
options.virtualisation.containers = {
@@ -41,90 +85,33 @@ in
description = "Enable the OCI seccomp BPF hook";
};
containersConf.settings = mkOption {
shortnames.enable = mkOption {
type = types.bool;
default = true;
description = ''
Enable the usage of a collection of common aliases for fully qualified images.
See https://github.com/containers/shortnames.
'';
};
containersConf = mkOptions "containers.conf";
storage = mkOptions "storage.conf";
registries.settings = mkOption {
type = toml.type;
default = { };
description = "containers.conf configuration";
};
containersConf.cniPlugins = mkOption {
type = types.listOf types.package;
defaultText = literalExpression ''
[
pkgs.cni-plugins
]
'';
example = literalExpression ''
[
pkgs.cniPlugins.dnsname
]
'';
description = ''
CNI plugins to install on the system.
registries.conf configuration.
Examine [containers-registries.conf(5)] for more information about the format.
[containers-registries.conf(5)]: https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md
'';
};
storage.settings = mkOption {
type = toml.type;
description = "storage.conf configuration";
};
registries = {
# TODO: remove those options in 26.11
search = mkOption {
visible = false;
type = types.listOf types.str;
default = [ ];
description = ''
List of repositories to search.
Deprecated, examine {option}`virtualisation.containers.registries.settings` instead.
'';
};
insecure = mkOption {
default = [ ];
visible = false;
type = types.listOf types.str;
description = ''
List of insecure repositories.
Deprecated, examine {option}`virtualisation.containers.registries.settings` instead.
'';
};
block = mkOption {
default = [ ];
visible = false;
type = types.listOf types.str;
description = ''
List of blocked repositories.
Deprecated, examine {option}`virtualisation.containers.registries.settings` instead.
'';
};
settings = mkOption {
type = toml.type;
default = {
registry = [
{ location = "docker.io"; }
{ location = "quay.io"; }
];
};
description = ''
repositories.conf configuration.
Examine [containers-registries.conf(5)] for more information about the format.
[containers-registries.conf(5)]: https://github.com/containers/image/blob/main/docs/containers-registries.conf.5.md
'';
};
};
policy = mkOption {
default = { };
type = types.attrs;
type = json.type;
example = literalExpression ''
{
default = [ { type = "insecureAcceptAnything"; } ];
@@ -144,49 +131,83 @@ in
};
config = lib.mkIf cfg.enable {
warnings = lib.optional oldRegistriesOptionsUsed "the options virtualisation.containers.registries.search / insecure / block are deprecated. See virtualisation.containers.registries.settings instead.";
config =
let
dropIn =
name: scope: settings:
let
path = "${name}${lib.optionalString (scope != "") ".${scope}"}.conf";
filename = if scope == "" then "00-nixos.conf" else "10-nixos-${scope}.conf";
in
lib.optionalAttrs (settings != { }) {
"containers/${path}.d/${filename}".source = toml.generate path settings;
};
in
lib.mkIf cfg.enable {
assertions =
let
attr = name: default: lib.attrByPath [ "network" name ] default cfg.containersConf.settings;
in
[
{
assertion = (attr "default_rootless_network_cmd" "pasta") == "pasta";
message = "Podman 6.0 only supports pasta for rootless networking.";
}
{
assertion = (attr "firewall_driver" "nftables") != "iptables";
message = "Podman 6.0 no longer supports iptables as a firewall driver. Use nftables instead.";
}
{
assertion = (attr "network_backend" "netavark") == "netavark";
message = "Podman 6.0 no longer supports network backends other than netavark.";
}
];
virtualisation.containers.registries.settings = lib.mkIf oldRegistriesOptionsUsed {
registries = {
block.registries = cfg.registries.block;
insecure.registries = cfg.registries.insecure;
search.registries = cfg.registries.search;
warnings =
lib.optional (lib.hasAttrByPath [ "storage" "graphroot" ] cfg.storage.settings) ''
virtualisation.containers.storage.settings.storage.graphroot now applies to both rootful and rootless podman and will likely not work as intended.
Use virtualisation.containers.storage.{rootful,rootless}.settings.storage.graphroot instead.
''
++ lib.optional (lib.hasAttrByPath [ "storage" "runroot" ] cfg.storage.settings) ''
virtualisation.containers.storage.settings.storage.runroot now applies to both rootful and rootless podman and will likely not work as intended.
Use virtualisation.containers.storage.{rootful,rootless}.settings.storage.runroot instead.
'';
virtualisation.containers = {
containersConf.settings = {
engine = lib.mkIf cfg.ociSeccompBpfHook.enable {
hooks_dir = [ config.boot.kernelPackages.oci-seccomp-bpf-hook ];
};
containers = {
default_sysctls = lib.mkDefault [ "net.ipv4.ping_group_range=0 0" ];
};
};
storage = {
settings.storage = {
driver = lib.mkDefault "overlay";
options.overlay.mountopt = lib.mkDefault "nodev";
};
};
};
environment.etc = lib.mkMerge [
(dropIn "containers" "" cfg.containersConf.settings)
(dropIn "containers" "rootful" cfg.containersConf.rootful.settings)
(dropIn "containers" "rootless" cfg.containersConf.rootless.settings)
(dropIn "storage" "" cfg.storage.settings)
(dropIn "storage" "rootful" cfg.storage.rootful.settings)
(dropIn "storage" "rootless" cfg.storage.rootless.settings)
(dropIn "registries" "" cfg.registries.settings)
{
"containers/policy.json".source =
if cfg.policy != { } then
json.generate "policy.json" cfg.policy
else
"${pkgs.skopeo.policy}/default-policy.json";
}
(lib.mkIf cfg.shortnames.enable {
"containers/registries.conf.d/000-shortnames.conf".source = pkgs.containers-shortnames.shortnames;
})
];
};
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 ];
};
};
virtualisation.containers.storage.settings.storage = {
driver = lib.mkDefault "overlay";
graphroot = lib.mkDefault "/var/lib/containers/storage";
runroot = lib.mkDefault "/run/containers/storage";
};
environment.etc = {
"containers/containers.conf".source = toml.generate "containers.conf" cfg.containersConf.settings;
"containers/storage.conf".source = toml.generate "storage.conf" cfg.storage.settings;
"containers/registries.conf".source = toml.generate "registries.conf" cfg.registries.settings;
"containers/policy.json".source =
if cfg.policy != { } then
pkgs.writeText "policy.json" (builtins.toJSON cfg.policy)
else
"${pkgs.skopeo.policy}/default-policy.json";
};
};
}

View File

@@ -183,20 +183,7 @@ in
config.systemd.package # To allow systemd-based container healthchecks
]
++ lib.optional (config.boot.supportedFilesystems.zfs or false) config.boot.zfs.package;
extraRuntimes =
cfg.extraRuntimes
++
lib.optionals
(
config.virtualisation.containers.containersConf.settings.network.default_rootless_network_cmd or ""
== "slirp4netns"
)
(
with pkgs;
[
slirp4netns
]
);
inherit (cfg) extraRuntimes;
};
};
@@ -209,6 +196,28 @@ in
'';
};
dns = {
openFirewall = lib.mkOption {
type = lib.types.bool;
default = config.networking.firewall.backend != "firewalld";
defaultText = lib.literalExpression ''
config.networking.firewall.backend != "firewalld"
'';
description = ''
Whether to allow DNS (port 53) from all network interfaces configured in {option}`virtualisation.podman.dns.interfaces` to aardvark-dns.
'';
};
interfaces = lib.mkOption {
type = lib.types.listOf lib.types.nonEmptyStr;
default = [ ];
description = ''
List of network interfaces which should have DNS (port 53) traffic allowed.
Auto-named interfaces (`podman0`, `podman1`, ...) are allowed by default.
Add custom podman networks with an explicitly set interface name here.
'';
};
};
};
config =
@@ -235,6 +244,8 @@ in
// cfg.defaultNetwork.settings
);
inherit (networkConfig) dns_enabled network_interface;
isFirewallD = config.networking.firewall.backend == "firewalld";
isNftables = config.networking.firewall.backend == "nftables";
in
lib.mkIf cfg.enable {
warnings = lib.optionals cfg.enableNvidia [
@@ -251,19 +262,22 @@ in
};
# containers cannot reach aardvark-dns otherwise
networking.firewall = lib.mkIf (config.networking.firewall.backend != "firewalld") {
interfaces.${network_interface}.allowedUDPPorts = lib.mkIf dns_enabled [ 53 ];
};
networking.firewall.interfaces = lib.mkIf cfg.dns.openFirewall (
lib.genAttrs cfg.dns.interfaces (_: {
allowedUDPPorts = [ 53 ];
allowedTCPPorts = [ 53 ];
})
);
virtualisation.containers = {
enable = true; # Enable common /etc/containers configuration
containersConf.settings = {
network = {
network_backend = "netavark";
firewall_driver = lib.mkIf config.networking.nftables.enable "nftables";
};
};
};
virtualisation.podman.dns.interfaces =
lib.mkIf (!isFirewallD)
# Add `network_interface` if it doesn't match the wildcard.
(
lib.optional (dns_enabled && (!lib.hasPrefix "podman" network_interface)) network_interface
++ lib.singleton (if isNftables then "podman*" else "podman+")
);
virtualisation.containers.enable = true;
systemd.packages = [ cfg.package ];
@@ -339,6 +353,13 @@ in
The options virtualisation.podman.dockerSocket.enable and virtualisation.docker.enable conflict, because only one can serve the socket.
'';
}
{
assertion = cfg.dns.openFirewall -> !isFirewallD;
message = ''
The option `virtualisation.podman.dns.openFirewall` cannot be used with the `firewalld` firewall backend.
The `firewalld` backend is not affected by the DNS firewall issue the option is built for.
'';
}
];
};
}

View File

@@ -1487,6 +1487,7 @@ in
plotinus = runTest ./plotinus.nix;
pocket-id = runTest ./pocket-id.nix;
podman = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./podman/default.nix { };
podman-dns = runTest ./podman/dns.nix;
podman-tls-ghostunnel = handleTestOn [
"aarch64-linux"
"x86_64-linux"

View File

@@ -47,13 +47,6 @@ import ../make-test-python.nix (
isNormalUser = true;
};
};
dns =
{ pkgs, ... }:
{
virtualisation.podman.enable = true;
virtualisation.podman.defaultNetwork.settings.dns_enabled = true;
};
docker =
{ pkgs, ... }:
{
@@ -74,6 +67,14 @@ import ../make-test-python.nix (
isNormalUser = true;
};
};
docker_compat =
{ pkgs, ... }:
{
virtualisation.podman = {
enable = true;
dockerCompat = true;
};
};
};
testScript = ''
@@ -88,8 +89,8 @@ import ../make-test-python.nix (
rootful.wait_for_unit("sockets.target")
rootful_norunc.wait_for_unit("sockets.target")
rootless.wait_for_unit("sockets.target")
dns.wait_for_unit("sockets.target")
docker.wait_for_unit("sockets.target")
docker_compat.wait_for_unit("sockets.target")
start_all()
with subtest("Run container as root with runc"):
@@ -212,18 +213,6 @@ import ../make-test-python.nix (
)
rootful.succeed("podman rm journald")
with subtest("aardvark-dns"):
dns.succeed("tar cv --files-from /dev/null | podman import - scratchimg")
dns.succeed(
"podman run -d --name=webserver -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin -w ${pkgs.writeTextDir "index.html" "<h1>Testing</h1>"} scratchimg ${pkgs.python3}/bin/python -m http.server 8000"
)
dns.succeed("podman ps | grep webserver")
dns.wait_until_succeeds(
"podman run --rm --name=client -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg ${pkgs.curl}/bin/curl http://webserver:8000 | grep Testing"
)
dns.succeed("podman stop webserver")
dns.succeed("podman rm webserver")
with subtest("A podman member can use the docker cli"):
docker.succeed(su_cmd("docker version"))
@@ -251,6 +240,15 @@ import ../make-test-python.nix (
rootless.wait_until_succeeds(su_cmd("podman ps | grep quadlet"), timeout=20)
rootless.systemctl("stop quadlet", "alice")
with subtest("Docker compat works"):
docker_compat.succeed("tar cv --files-from /dev/null | docker import - scratchimg")
docker_compat.succeed(
"docker run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin localhost/scratchimg /bin/sleep 10"
)
docker_compat.succeed("docker ps | grep sleeping")
docker_compat.succeed("podman ps | grep sleeping")
docker_compat.succeed("docker stop sleeping")
docker_compat.succeed("docker rm sleeping")
# TODO: add docker-compose test
'';

View File

@@ -0,0 +1,78 @@
{ pkgs, lib, ... }:
{
name = "podman-dns";
meta = {
maintainers = lib.teams.podman.members;
};
nodes = {
dns_iptables = {
virtualisation.podman = {
enable = true;
defaultNetwork.settings.dns_enabled = true;
dns.interfaces = [ "custom" ];
};
networking.firewall.backend = "iptables";
};
dns_nftables = {
virtualisation.podman = {
enable = true;
defaultNetwork.settings.dns_enabled = true;
dns.interfaces = [ "custom" ];
};
networking.firewall.backend = "nftables";
networking.nftables.enable = true;
};
dns_firewalld = {
virtualisation.podman = {
enable = true;
defaultNetwork.settings.dns_enabled = true;
};
networking.firewall.backend = "firewalld";
services.firewalld.enable = true;
networking.nftables.enable = true;
};
};
testScript = ''
start_all()
def test_podman(node, network = None, interface = None):
network_arg = ""
if network is not None:
network_arg = f"--network={network}"
if interface is None:
node.succeed(f"podman network create {network}")
else:
node.succeed(f"podman network create {network} --interface-name {interface}")
node.succeed(
f"podman run -d {network_arg} --name=webserver -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin -w ${pkgs.writeTextDir "index.html" "<h1>Testing</h1>"} scratchimg ${pkgs.python3}/bin/python -m http.server 8000"
)
node.succeed("podman ps | grep webserver")
node.wait_until_succeeds(
f"podman run --rm {network_arg} --name=client -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg ${pkgs.curl}/bin/curl http://webserver:8000 | grep Testing"
)
node.succeed("podman stop webserver")
node.succeed("podman rm webserver")
if network is not None:
node.succeed(f"podman network rm {network}")
for node in machines:
node.succeed("tar cv --files-from /dev/null | podman import - scratchimg")
with subtest(f"aardvark-dns on node {node.name} in the default network"):
test_podman(node, None)
with subtest(f"aardvark-dns on node {node.name} in a custom network"):
test_podman(node, "custom", "custom")
with subtest(f"aardvark-dns on node {node.name} in an auto-named network"):
test_podman(node, "auto", None)
'';
}

View File

@@ -9,10 +9,9 @@
runc, # Default container runtime
crun, # Container runtime (default with cgroups v2 for podman/buildah)
conmon, # Container runtime monitor
slirp4netns, # User-mode networking for unprivileged namespaces
fuse-overlayfs, # CoW for images, much faster than default vfs
util-linuxMinimal, # nsenter
iptables,
nftables,
aardvark-dns,
netavark,
passt,
@@ -26,10 +25,9 @@ let
runc
crun
conmon
slirp4netns
fuse-overlayfs
util-linuxMinimal
iptables
nftables
]
++ extraPackages
);

View File

@@ -0,0 +1,42 @@
{
lib,
stdenvNoCC,
fetchFromGitHub,
nix-update-script,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "containers-shortnames";
version = "2025.03.19";
__structuredAttrs = true;
strictDeps = true;
src = fetchFromGitHub {
owner = "containers";
repo = "shortnames";
tag = "v${finalAttrs.version}";
hash = "sha256-Rq1mMZFo8Eyqxcp+SBa/zrE7OZfbjblfAGPBumjuikk=";
};
installPhase = ''
runHook preInstall
install -Dm644 shortnames.conf $out/share/containers/registries.conf.d/000-shortnames.conf
runHook postInstall
'';
passthru = {
updateScript = nix-update-script { };
shortnames = "${finalAttrs.finalPackage}/share/containers/registries.conf.d/000-shortnames.conf";
};
meta = {
description = "Registry alias names for shortnames to fully specified container image names";
homepage = "https://github.com/containers/shortnames";
license = lib.licenses.asl20;
teams = [ lib.teams.podman ];
maintainers = [ lib.maintainers.marie ];
};
})

View File

@@ -11,16 +11,16 @@
rustPlatform.buildRustPackage (finalAttrs: {
pname = "netavark";
version = "1.17.2";
version = "2.1.0";
src = fetchFromGitHub {
owner = "containers";
repo = "netavark";
rev = "v${finalAttrs.version}";
hash = "sha256-FdJNcHYK6Jc1dNqcUr5Ne8dv1dzlHRhcjoldiihrov8=";
hash = "sha256-nTmbPKTIne4iIrX5KPWTkFc+SD1Th9/sOciAzThin9M=";
};
cargoHash = "sha256-wp/1lWc3OfNQt74m8DtpuFO/Mf07+M7numq2FMEkeGo=";
cargoHash = "sha256-6ZYVQVLm9b71s5FPgTSzDmscEVLE9ZxKCg+4R+0hkUk=";
nativeBuildInputs = [
installShellFiles

View File

@@ -26,7 +26,6 @@
fuse-overlayfs,
util-linuxMinimal,
nftables,
iptables,
iproute2,
catatonit,
gvproxy,
@@ -38,19 +37,20 @@
writableTmpDirAsHomeHook,
coreutils,
runtimeShell,
fetchpatch,
}:
let
systemdLibs' = systemdLibs.override { withCompression = true; };
in
buildGoModule (finalAttrs: {
pname = "podman";
version = "5.8.9";
version = "6.1.4";
src = fetchFromGitHub {
owner = "podman-container-tools";
repo = "podman";
tag = "v${finalAttrs.version}";
hash = "sha256-nIWwG5QyIent0vJtEm8zDQLbqfTZmD4oKMbf2N5r2wA=";
hash = "sha256-RTPxNoKRqFGDFEYHUwPbsNAAZqNfBXbetfphxrwn6eM=";
};
patches = [
@@ -60,6 +60,13 @@ buildGoModule (finalAttrs: {
# we intentionally don't build and install the helper so we shouldn't display messages to users about it
./rm-podman-mac-helper-msg.patch
# Fix `podman completion` in the build sandbox
# https://github.com/podman-container-tools/podman/pull/29832
(fetchpatch {
name = "fix-podman-completion.patch";
url = "https://github.com/podman-container-tools/podman/commit/7cef788844bdaae01ca672a55698d40428644eb4.patch";
hash = "sha256-CAECXYRFyOF4aIc9qIZQceiz5vE/gFGyitjPI48IhYU=";
})
];
vendorHash = null;
@@ -151,9 +158,10 @@ buildGoModule (finalAttrs: {
passthru = {
tests = lib.optionalAttrs stdenv.hostPlatform.isLinux {
inherit (nixosTests) podman;
# related modules
inherit (nixosTests)
podman
podman-dns
podman-tls-ghostunnel
;
oci-containers-podman = nixosTests.oci-containers.podman;
@@ -165,7 +173,6 @@ buildGoModule (finalAttrs: {
lib.optionals stdenv.hostPlatform.isLinux [
fuse-overlayfs
util-linuxMinimal
iptables
iproute2
nftables
]
@@ -184,7 +191,7 @@ buildGoModule (finalAttrs: {
]
++ lib.optionals stdenv.hostPlatform.isLinux [
aardvark-dns # dns
catatonit # added here for the pause image and also set in `containersConf` for `init_path`
catatonit # added here for the pause image
netavark # networking
passt # rootless networking
conmon # runtime monitor