When the docker-demon starts it adds a couple of rules to iptables.
When all rules are deleted via iptables -F
i have to stop and restart the docker demon to r
Docker in default configuration, when running in bridge
mode, does manipulate iptables
(a lot) unless you disable it (then you would have to configure your own NAT rules).
The default network-related configuration is probably following, although the config /etc/docker/daemon.json
might not exist (and as of now you can't print effective configuration):
{
"userland-proxy": true,
"iptables": true,
"ip-forward": true,
"ip-masq": true,
"ipv6": false
}
After Docker daemon starts, it injects following rules (in filter
):
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
In order to understand what Docker does, here is a list of Docker-generated iptables rules with a short explanation. If you flush iptables rules, while Docker daemon and some containers are running, you might break access to existing containers (but probably won't break anything, more about this below).
After service docker restart
all default rules are injected into firewall (you can check it by running iptables-save
or iptables -S
, iptables -S -t nat
). Assuming you want to keep your containers running and only generate missing NAT rules.
docker ps
gives us list of running containers:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
865569da8d36 nginx "nginx -g 'daemon of…" 17 hours ago Up 17 hours 0.0.0.0:4564->80/tcp, 0.0.0.0:32237->80/tcp jovial_sammet
And from docker inspect
we can obtain the port mapping
$ docker inspect -f '{{.NetworkSettings.Ports}}' 865569da8d36
map[80/tcp:[{0.0.0.0 4564} {0.0.0.0 32237}]]
now we need just the internal IP address of Docker container:
$ docker inspect -f '{{.NetworkSettings.IPAddress}}' 865569da8d36
172.17.0.2
Now using some bash/jq we can generate the dynamic iptables rules:
$ bash docker_iptables --noop
iptables -A DOCKER -d 172.17.0.2
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 4564 -j DNAT --to-destination 172.17.0.2:80
iptables -A DOCKER -d 172.17.0.2
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 32237 -j DNAT --to-destination 172.17.0.2:80
So the answer to the question is: No, not without stopping all containers. But the rules can be re-added manually (NOTE: this script doesn't cover all Docker functionality, e.g. if you're exposing some service running in other network than Docker container).
When you start Docker container with exposed ports (-p
):
docker run --rm -d -p 32237:80 -p 4564:80 nginx
Docker spins up also docker-proxy
. What's that?
$ netstat -tulpn | grep docker-proxy
tcp 0 0 0.0.0.0:32237 0.0.0.0:* LISTEN 20487/docker-proxy
tcp 0 0 0.0.0.0:4564 0.0.0.0:* LISTEN 20479/docker-proxy
The Linux kernel does not allow the routing of loopback traffic, and therefore it's not possible to apply netfilter NAT rules to packets originating from 127.0.0.0/8. docker-proxy is generally considered as an inelegant solution to such problems.
When you restore iptables without Docker rules, the container ports might be still available via docker-proxy
. However this might bring some performance issues in networking, as docker-proxy
won't be as fast as kernel's netfilter.