The fix introduced in PR #1637 (v2.17.0) for iptables-legacy failures on Ubuntu 26.04 uses a hardcoded VERSION_CODENAME check to decide whether to use iptables-nft vs iptables-legacy. This only handles Ubuntu 26.04 (resolute), but the same failure occurs on any Ubuntu/Debian container image running on a host kernel where the ip_tables module is not loaded, for example, AlmaLinux 9 or Fedora 41+ hosts.
Steps to Reproduce
- Host OS: AlmaLinux 9 (or Fedora 41+): kernel does not load
ip_tables by default
- Devcontainer base image:
mcr.microsoft.com/devcontainers/base:ubuntu-24.04 (codename: noble)
- Feature:
ghcr.io/devcontainers/features/docker-in-docker:2 (v2.17.0 / v3.x)
Starting the devcontainer results in:
failed to start daemon: Error initializing network controller: error obtaining controller instance:
failed to register "bridge" driver: failed to create NAT chain DOCKER: iptables failed:
iptables --wait -t nat -N DOCKER: iptables v1.8.10 (legacy): can't initialize iptables table `nat':
Table does not exist (do you need to insmod?)
Confirming manually inside the container:
$ iptables-legacy -nL
iptables v1.8.10 (legacy): can't initialize iptables table `filter': Table does not exist (do you need to insmod?)
# exits with code 3
$ type iptables-legacy
iptables-legacy is hashed (/usr/sbin/iptables-legacy)
# exits with code 0 <- binary exists, but kernel module is absent
Root Cause
In PR #1637, the initial fix correctly used a runtime -nL probe to verify whether iptables-legacy actually works before switching alternatives. However, this probe was removed because install.sh runs at image build time, when kernel modules are not accessible, so the probe would always fail during build.
The replacement logic uses a hardcoded codename allowlist:
case "${VERSION_CODENAME}" in
resolute) use_nft=true ;;
esac
This only catches Ubuntu 26.04 (resolute). On Ubuntu 24.04 (noble) and any other non-resolute image the script falls through to:
elif type iptables-legacy > /dev/null 2>&1; then
update-alternatives --set iptables /usr/sbin/iptables-legacy
Since type iptables-legacy succeeds (the binary exists), iptables-legacy is set as the default, even though the host kernel does not have ip_tables loaded. The failure only manifests at container runtime when dockerd tries to create the NAT chain.
This is the same underlying problem described in issue #1235 (Fedora/RHEL hosts), which also remains unresolved by the v2.17.0 fix.
Proposed Fix
The iptables alternatives selection logic should be moved from install.sh (build-time) to docker-init.sh (the runtime entrypoint script). At runtime, the -nL probe works correctly and can detect the actual kernel capability:
# In docker-init.sh, before starting dockerd:
if type iptables-legacy > /dev/null 2>&1 && iptables-legacy -nL > /dev/null 2>&1; then
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
elif type iptables-nft > /dev/null 2>&1; then
update-alternatives --set iptables /usr/sbin/iptables-nft
update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
fi
This approach is host-kernel-agnostic and does not require maintaining a hardcoded list of codenames.
Environment
|
|
| Host OS |
AlmaLinux 9 |
| Container OS |
Ubuntu 24.04.3 LTS (noble) |
| Feature version |
ghcr.io/devcontainers/features/docker-in-docker:2 (v2.17.0 / v3.x) |
| Docker version |
29.4.3-1 |
| iptables version |
v1.8.10 (legacy) |
Related Issues / PRs
The fix introduced in PR #1637 (v2.17.0) for iptables-legacy failures on Ubuntu 26.04 uses a hardcoded
VERSION_CODENAMEcheck to decide whether to useiptables-nftvsiptables-legacy. This only handles Ubuntu 26.04 (resolute), but the same failure occurs on any Ubuntu/Debian container image running on a host kernel where theip_tablesmodule is not loaded, for example, AlmaLinux 9 or Fedora 41+ hosts.Steps to Reproduce
ip_tablesby defaultmcr.microsoft.com/devcontainers/base:ubuntu-24.04(codename:noble)ghcr.io/devcontainers/features/docker-in-docker:2(v2.17.0 / v3.x)Starting the devcontainer results in:
Confirming manually inside the container:
Root Cause
In PR #1637, the initial fix correctly used a runtime
-nLprobe to verify whetheriptables-legacyactually works before switching alternatives. However, this probe was removed becauseinstall.shruns at image build time, when kernel modules are not accessible, so the probe would always fail during build.The replacement logic uses a hardcoded codename allowlist:
This only catches Ubuntu 26.04 (
resolute). On Ubuntu 24.04 (noble) and any other non-resoluteimage the script falls through to:Since
type iptables-legacysucceeds (the binary exists),iptables-legacyis set as the default, even though the host kernel does not haveip_tablesloaded. The failure only manifests at container runtime whendockerdtries to create the NAT chain.This is the same underlying problem described in issue #1235 (Fedora/RHEL hosts), which also remains unresolved by the v2.17.0 fix.
Proposed Fix
The iptables alternatives selection logic should be moved from
install.sh(build-time) todocker-init.sh(the runtime entrypoint script). At runtime, the-nLprobe works correctly and can detect the actual kernel capability:This approach is host-kernel-agnostic and does not require maintaining a hardcoded list of codenames.
Environment
noble)ghcr.io/devcontainers/features/docker-in-docker:2(v2.17.0 / v3.x)Related Issues / PRs