准备工作
使用 OpenWrt 24.10 官网原版。安装 dockerd,docker-compose。OpenWrt 运行在网关模式,通过一个 LAN 接口访问网络和提供服务。
准备一个需要访问网络服务的容器用于测试,一个使用docker命令启动,一个使用docker-compose部署。
services:
runner:
image: gitea/act_runner:nightly
environment:
TZ: "Asia/Shanghai"
CONFIG_FILE: "/data/config.yaml"
GITEA_INSTANCE_URL: "http://192.168.88.5:3000"
GITEA_RUNNER_REGISTRATION_TOKEN: "$token$"
GITEA_RUNNER_NAME: "runner_wrt"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "./data:/data"
- "./cache:/root/.cache"启动容器
直接使用docker run启动一个容器进行测试,不出意外会连接超时。
docker run --rm nginx curl cip.ccdocker-compose部署后,查看容器的网络分配。如果没有特殊配置,docker-compose将会创建一个runner_default网络,并且绑定到一个物理网桥设备。
root@OpenWrt:~/runner# docker network ls
NETWORK ID NAME DRIVER SCOPE
414f35244088 bridge bridge local
bd99198961bd host host local
3b28231237bd none null local
7b65b7b260af runner_default bridge localdocker 服务启动后会自动创建一个docker0网桥设备,通过docker命令直接运行容器,容器会加入这个默认的网桥。如果通过docker-compose部署,则会创建一个独立的网桥设备。br-7b65b7b260af便是上述容器绑定的网桥设备。
root@OpenWrt:~/runner# ip link list
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br-lan state UP mode DEFAULT group default qlen 1000
link/ether e4:3a:6e:5f:d4:85 brd ff:ff:ff:ff:ff:ff
3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN mode DEFAULT group default qlen 1000
link/ether e4:3a:6e:5f:d4:86 brd ff:ff:ff:ff:ff:ff
4: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether e4:3a:6e:5f:d4:85 brd ff:ff:ff:ff:ff:ff
402: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:53:0a:95:11 brd ff:ff:ff:ff:ff:ff
407: br-7b65b7b260af: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:bd:9a:47:70 brd ff:ff:ff:ff:ff:ff由于这个容器需要连接 Gitea 服务器进行注册,没有网络访问就会抛出日常。查看日志确认连接失败。
runner-1 | Error: unavailable: dial tcp 192.168.88.5:3000: connect: connection refused分析原因,OpenWrt 不会自动将这些网桥设备加入防火墙区域,也不会做 NAT 转发,因此无法访问外部网络。
创建接口
在网络接口中添加一个接口docker0,不配置协议,绑定到设备docker0。在该接口防火墙设置中,创建/分配防火墙区域docker。
配置防火墙
在防火墙中,创建一个区域docker,并且将docker0加入到此区域。创建接口时已经自动创建,这一步可以忽略。
添加区域转发规则:
- lan => docker:接受入站数据,接受出战数据,接受区域内转发(外部网络可以访问容器服务)
- docker => lan:接受入站数据,接受出战数据,接受区域内转发(可以访问外部网络)
到此为止,通过docker命令直接运行的容器已经可以访问公网,以及外部网络可以访问容器服务。
处理动态网桥
由于每一次docker-compose部署,都会创建一个新的独立的网桥设备(如br-7b65b7b260af),也就需要重新为这些网桥设备配置防火墙。
我尝试了在compose.yaml中指定使用已有的bridge,错误指出只能连接到用户定义的网络。
networks:
default:
name: bridge
driver: bridge
external: true解决办法也很明显,只需要用户自定义一个网络即可。创建一个docker1网络,并且通过driver_opts绑定指定的网桥设备,便于配置防火墙规则。
docker network create -d bridge \
--opt "com.docker.network.bridge.name=docker1" \
docker1在网络接口中添加一个接口docker1,不配置协议,绑定到网桥设备docker1。在该接口防火墙设置中,创建/分配防火墙区域docker。防火墙规则之前已经配置完成,不再需要其他配置。
使用自定义网络
为需要访问公网的服务,在compose.yaml中声明使用外部的网络。
services:
runner:
image: gitea/act_runner:nightly
environment:
TZ: "Asia/Shanghai"
CONFIG_FILE: "/data/config.yaml"
GITEA_INSTANCE_URL: "http://192.168.88.5:3000"
GITEA_RUNNER_REGISTRATION_TOKEN: "$token$"
GITEA_RUNNER_NAME: "runner_wrt"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "./data:/data"
- "./cache:/root/.cache"
networks:
- default
networks:
default:
name: docker1
external: true重新部署后,查看日志输出,发现已经可以成功连接到 Gitea。
runner-1 | time="2025-11-08T12:08:27Z" level=info msg="runner: runner_wrt, with version: v0.2.12, with labels: [ubuntu-latest ubuntu-22.04 ubuntu-20.04], declare successfully" func="[func6]" file="[daemon.go:119]"最后,如果希望docker-compose自己创建网络,但是又不希望每次生成随机的网桥名称,可以这样配置。
networks:
default:
name: docker1
driver: bridge
driver_opts:
com.docker.network.bridge.name: docker1