Docker + nftables: example with Drone CI โ€“ Docker Runner

At this time, Docker isn’t compatible with nftables. This is how you can do with an example with Drone CI (Docker Runner).

Docker fix for nftables (systemd way)

We need to fix docker.service using a little fix to disable iptables and fix the IP range used by Docker

mkdir /etc/systemd/system/docker.service.d

cat << EOF > /etc/systemd/system/docker.service.d/nftables-fix.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=false --fixed-cidr=172.17.0.0/16
EOF

We need the first ExecStart without anything to cancel the official ExecStart for docker.service, I don’t replace this file.

nftables rules

I transposed rules from iptables to nftables, you can optimize it and I’d like to read it.

table ip nat {
     chain PREROUTING {
          fib daddr type local jump DOCKER
     }
     chain POSTROUTING {
          oifname != "docker0" ip saddr 172.17.0.0/16 masquerade
          ip saddr 172.17.0.2 ip daddr 172.17.0.2 tcp dport 3000 masquerade
     }
     chain OUTPUT {
          ip daddr != 127.0.0.0/8 fib daddr type local jump DOCKER
     }
     chain DOCKER {
          iifname "docker0" return
          iifname != "docker0" ip daddr 127.0.0.1 tcp dport 3000 dnat to 172.17.0.2:3000
     }
}

table ip filter {
     chain INPUT {
          iifname "docker0" accept
     }
     chain FORWARD {
          oifname "docker0" ct state established,related accept
          oifname "docker0" jump DOCKER
          iifname "docker0" oifname != "docker0" accept
          iifname "docker0" oifname "docker0" accept
          jump DOCKER-USER
          jump DOCKER-ISOLATION-STAGE-1
     }
     chain DOCKER-USER {
          return
     }
     chain DOCKER {
          iifname != "docker0" oifname "docker0" ip daddr 172.17.0.2 tcp dport 3000 accept
     }
     chain DOCKER-ISOLATION-STAGE-1 {
          iifname "docker0" oifname != "docker0" jump DOCKER-ISOLATION-STAGE-2
          return
     }
     chain DOCKER-ISOLATION-STAGE-2 {
          oifname "docker0" drop return
     }
}

How to start successfully the container

I use the easiest fix: fixed IP

docker run -d --ip 172.17.0.2 \
-v /var/run/docker.sock:/var/run/docker.sock \
-e DRONE_RPC_PROTO=https \
-e DRONE_RPC_HOST=drone.lina.local \
-e DRONE_RPC_SECRET=MY_RPC_SECRET \
-e DRONE_RUNNER_CAPACITY=12 \
-e DRONE_RUNNER_NAME=runner1 \
-p 127.0.0.1:3000:3000 \
--restart always \
--name runner \
drone/agent

Right now, you have your Docker Runner running with success

Conclusion

It’s strange to use fixed IP where Docker is for “automated” and “magic” deployment but it’s the only way to use it with nftables.

It’s a fix for now and I’m impatient to migrate from Docker to Podman (used to run Drone Server) but I need to wait, not my CI/CD.