Allow startup with no kernel support for ip6_tables#47918
Allow startup with no kernel support for ip6_tables#47918thaJeztah merged 1 commit intomoby:masterfrom
Conversation
| if version == iptables.IPv4 { | ||
| return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err) | ||
| } | ||
| // Log this error, but don't return it - config.EnableIP6Tables is now true by default, |
There was a problem hiding this comment.
Can it still be disabled? If not, then it looks like we have a check above that would never have to be checked;
moby/libnetwork/drivers/bridge/setup_ip_tables_linux.go
Lines 40 to 42 in f3f20c3
Given that that check is present, and that there's a config for it, would it make sense to disable that config if we cannot support it?
There was a problem hiding this comment.
Thinking here; given that we have an option to disable the features, would it make life easier on us to disable that feature if we cannot support it, so that we don't have to perform special handling in other places 🤔
There was a problem hiding this comment.
Yes, the default has changed to enable ip6tables by default (and to make it non-experimental). But "ip6tables": false in daemon config works.
Now the default is to have IPv6 firewall rules, so that only mapped ports are exposed - I think it'd be quite bad to just give up on ip6tables if they don't work. Particularly in the DinD case, where the host is IPv6-enabled but just doesn't have the kernel module loaded, containers would silently end up with no firewall.
So, I think it's better to require that ip6tables works, or is explicitly disabled. If ip6tables is broken and IPv6 isn't used, or IPv6 isn't available on the host, behaviour will be unchanged - IPv4 will just work. With this PR, it's only when trying to use ip6tables that an error will be raised.
In the DinD case - if the host's moby is >=27.0, it'll also have ip6tables enabled and the kernel module will be loaded before the DinD starts. The issue only arises when the host has an old moby (or ip6tables explicitly disabled). That may hit people in the 27.0 release, if they pick up a 27.0-based DinD image and haven't upgraded their host.
But, the change to enabling ip6tables by default is probably going to be significant for more people. Anyone who's using IPv6 and expecting the container to be wide-open with no port mapping will have to change their config (either to disable ip6tables, or to -p the ports they want open - and maybe to opt for direct routing / no-NAT by using -o com.docker.network.bridge.gateway_mode_ipv6=routed when creating the network).
So, we have some docs work to do, and 27.0's release note will have to highlight these changes.
There was a problem hiding this comment.
In the DinD case - if the host's moby is >=27.0, it'll also have ip6tables enabled and the kernel module will be loaded before the DinD starts. The issue only arises when the host has an old moby (or ip6tables explicitly disabled). That may hit people in the 27.0 release, if they pick up a 27.0-based DinD image and haven't upgraded their host.
I can't reproduce this on Debian that's using nftables now, so I must have made a mistake when testing it the other day.
The outer docker starts normally with ip6tables enabled. But, the ip6_tables module needed by a dev container isn't loaded.
So, ip6tables works on the host, but a modprobe ip6_tables is still needed to make it work in the dev container (and, presumably, for any DinD that's using legacy iptables).
I'm wondering if we should try a modprobe ip6_tables if we fail to create ip6 chains (or, the ip link show ip6_tables trick that @tianon mentioned on the ticket, the dev container at-least doesn't currently have a modprobe) ... but I'm not sure if that'd get us into a mess with bad mixes of nftables/xtables. Perhaps it's better to expect the user to do the modprobe, or explicitly disable ip6tables for the inner-docker.
We may also need to add ip6_tables to dockerd-rootless-setuptool.sh.
There was a problem hiding this comment.
DinD on an nftables host ...
- a container image that uses nftables doesn't need the
ip6_tablesmodule. - a container image that uses xtables, does need a
modprobe ip6_tables- this doesn't affect the docker official image, it's always nftables-based alpine.
- it does affect our dev container (which has no
modprobe, butip link show ip6_tablesmagically works).
DinD on an iptables host ...
ip6_tablesdoes need to be loaded- it will be already, if the outer docker has ip6tables enabled (it's the new docker, or it's explicitly enabled)
- otherwise, it'll need to be modprobe'd
- so, the official image's
dockerd-entrypoint.shwill need an update for moby 27.0 (cc @tianon)
- so, the official image's
(rootless seems to be ok as it's on the host - I've not looked at dind-rootless, but guess it needs the same treatment as dind.)
So - we're probably ok ... there may be other DinD cases like our dev container where a modprobe is needed, we'll have to make sure that's documented.
| if version == iptables.IPv4 { | ||
| return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err) | ||
| } |
There was a problem hiding this comment.
This is policy. It doesn't belong in low-level code. Return an error which could be asserted on using errors.As or errors.Is, and lift the decision on how to handle failure into the caller func (*driver) configure.
There was a problem hiding this comment.
As there's nothing really special about setting up the first of the chains, if any of them fail none will be left intact, I just moved all the logic up into driver.configure.
Before "ip6tables" was enabled by default, dockerd would start normally when: - the kernel had no IPv6 support, or - docker is running as docker-in-docker, and the host doesn't have kernel module 'ip6_tables' loaded. Now, the bridge driver will try to set up its ip6tables chains and it'll fail. By not treating that as an error, the daemon will start and IPv4 will work normally. A subsequent attempt to create an IPv6 network will fail with an error about ip6tables. At that point, the user's options are: - set "ip6tables":false in daemon config - in the DinD case, "modprobe ip6_tables" on the host, or start dockerd on the host with ip6tables enabled (causing the kernel module load). Signed-off-by: Rob Murray <[email protected]>
7491fe9 to
837b3f9
Compare
- What I did
Before #47747 enabled "ip6tables" by default, dockerd would start normally when:
Now, the bridge driver will try to set up its ip6tables chains and it'll fail. By not treating that as an error, the daemon will start and IPv4 will work normally.
A subsequent attempt to create an IPv6 network will fail with an error about ip6tables. At that point, the user's options are to set
"ip6tables":falsein daemon config. Or, in the DinD case,"modprobe ip6_tables".- How I did it
After failing to set up the first of the IPv6 iptables chains, log the error but continue,
- How to verify it
Reproduced the problem on a Debian host with IPv6 disabled in its kernel, and on a Debian host using nftables but with
CONFIG_IP6_NF_IPTABLES=m.With this change, dockerd started normally and IPv4 networks containers worked.
In the DinD case, creating a network failed with:
After a
modprobe ip6_tableson the host, reloading the daemon (rather than restarting) leads to a different error, this time because the chains aren't set up - dockerd needs a restart at that point:With
ip6_tablesnot loaded on the host, disablingip6tablesvia daemon.json worked normally.On the host with no kernel support for IPv6, the error on trying to create an IPv6 network is unchanged - it's unrelated to ip6tables:
- Description for the changelog