准备工作

使用 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.cc

docker-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    local

docker 服务启动后会自动创建一个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
最后修改:2025 年 11 月 08 日
如果觉得我的文章对你有用,请随意赞赏