Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Openwrt 下 Docker 网络食用方法 #7

Open
lisaac opened this issue Mar 16, 2020 · 14 comments
Open

Openwrt 下 Docker 网络食用方法 #7

lisaac opened this issue Mar 16, 2020 · 14 comments

Comments

@lisaac
Copy link
Owner

lisaac commented Mar 16, 2020

Bridge 网络

Docker 使用 Bridge 网络时,会创建docker0 网桥,用于连接容器,然后 docker0 通过 NAT 转发访问外部网络,具体细节在这里就不赘述了。
当容器进行映射时,Docker 会自动添加 DNAT 进行转发,实现访问宿主机端口的时候,将流量转发到容器内部。

在普通宿主机中使用 Docker Bridge 网络没有任何问题,但是,如果宿主机是网关,或者 Openwrt 的时候,WAN 口也能轻松访问容器暴露出来的端口,带来很大的安全问题。

WAN 口访问的控制

所以核心问题是阻止 WAN 口访问,此前也有大佬 LEAN 采用阻止 Docker 操作 iptables的方案,这个方法简单粗暴,Docker 就不会添加 DNAT 转发,当然不存在端口暴露问题,但是带来的问题也有不少,有几率存在没有给 docker0SNAT 导致整个 bridge 网络下的容器都无法联网,实现下来还有其他一些奇奇怪怪的问题。

对于这种问题,Docker 官方的这篇文档给出了解决方案
下面就针对 Openwrt 来实现访问控制:

# 新建 DOCKER-MAN 自定义链
iptables -N DOCKER-MAN
# 挟持 DOCKER-USER 转到 DOCKER-MAN 自定义链
iptables -I DOCKER-USER -j DOCKER-MAN

# 若流量来自 br-lan 放行,目的是 `LAN` 口可以访问容暴露的端口
iptables -A DOCKER-MAN -i br-lan -o docker0 -j RETURN
# 阻止所有新建以及无效的连接。
iptables -A DOCKER-MAN -m conntrack --ctstate NEW,INVALID -o docker0 -j DROP
# 接受容器主动访问的流量,目的是容器能够联网。
iptables -A DOCKER-MAN -m conntrack --ctstate ESTABLISHED,RELATED -o docker0 -j RETURN
iptables -A DOCKER-MAN -j RETURN

这样一来,LAN 口是可以访问容器暴露的端口,对与其他接口,容器主动访问不受限制,而外面是无法直接访问容器的,做到了单项访问。

到这里,又有问题来了,如果我有一个容器比如 qBittorrent,暴露的端口就是希望从外部(公司)等管理的,这样一来就无法访问了,当然也有解决方案:

# 在 DOCKER-MAN 自定义链接加入对 172.17.0.9 (需要放行的容器ip) 的放行
iptables -I DOCKER-MAN -d 172.17.0.9 -o docker0 -j RETURN

这样一来,这个容器就可以被正常访问了

最后一个问题,Bridge 网络下面的 ip 地址不是固定的,每次重启 Docker daemon 都有可能改变容器的 ip
这样手动操作起来就相对比较麻烦了,所以在 luci-app-dockerman中加入了访问控制选项,可以轻松实现对容器的访问控制

Macvlan 网络

Macvlan 网络的真的是好处多多,有兴趣的同学自己翻阅资料查看,使用 macvlan 网络就基本和虚拟机的桥接模式类似,而且不存在 Bridge 网络的端口暴露的风险,在 Openwrt 下使用 macvlan 网络最大的问题就是无法上网的问题。

这里讲一个简单的方案,首先通过 Docker 新建 macvlan 网络

docker network create -d macvlan \
    --subnet=192.168.3.0/24 --gateway=92.168.3.1 \
    -o parent=br-lan \
    -o macvlan_mode=bridge \
    macnet

请注意这里的subnet不要和其他接口冲突(若要使用同网段后面会讲),parent使用br-lan,然后在 Openwrt 上创建 macvlan 设备

ip link add link br-lan docker_mac0 type macvlan mode bridge
ip link set docker_mac0 up

接下来 Openwrt 中添加接口,你也可以在 luci 中添加

uci set network.docker_mac0=interface
uci set network.docker_mac0.ifname=docker_mac0
uci set network.docker_mac0.proto=static
uci set network.docker_mac0.ipaddr=192.168.3.1
uci set network.docker_mac0.netmask=255.255.255.0
uci commit network

将这个接口加入到防火墙中的 LAN zone

uci set firewall.@zone[0].network="br-lan docker_mac0"
uci commit firewall

至此,Docker macvlan 网络就可以正常使用了,这个步骤相对比较简单,但是网络重启或者 Openwrt 重启的时候就会失效,解决这个问题,已经在 luci-app-dockerman 实现,当创建 macvlan 网络时,dockerman 会自动做好这些工作,网络重启也会自动添加,删除网络,则会自动删除创建的 macvlan 网络。

Macvlan 进阶

有些老哥觉得用这个方案 macvlan 网络,使用的是与 LAN 不同的网段,访问容器会存在转发。
解决这个其实很简单,禁用 br-lan 的 DHCP, 同时开启 docker_mac0DHCP 就可以,这样路由器下的所有主机和容器内的所有主机都在同一个网段之下了。
所以,如果你开始就想用这个进阶方案的话,从创建 macvlan 网络的时候就应该规划好自己偏好的网段。

好了,分享就这么多,感谢捧场

@sxx1314
Copy link

sxx1314 commented Mar 25, 2020

用 luci-app-dockerman 创建了一个10.10.20.0/24 子网 自动生成了lan口 但是容器依旧无法ping通网关 也无法ping通114等外网地址

@lisaac
Copy link
Owner Author

lisaac commented Mar 25, 2020

@sxx1314
请麻烦给下宿主和容器中的
ip add
同时看下宿主的docker inspect macvlan网络名

@sxx1314
Copy link

sxx1314 commented Mar 26, 2020

宿主 ip add 里没有新建的lan接口信息
然后我手动尝试了一下添加
ip link add link br-lan docker_mac0 type macvlan mode mac0
提示
Error: argument of "mode" must be "private", "vepa", "bridge", "passthru" or "source", not "mac0"

@lisaac
Copy link
Owner Author

lisaac commented Mar 26, 2020

文章打字少打了一个bridge😂
type macvlan mode bridge

@Neustradamus
Copy link

I search files:

  • u-boot-ar7241-no-wps.bin
  • lg-napl-5000-no-wps-ubnt-v5.3.5.bin

Linked to:

@VergilGao
Copy link

正好解决了问题,看到这个文章,写下我的解决方案:
/etc/config/dockerd
把 option iptables '0' 设置为 0
docker现在在未指定network_mode=bridge 的情况下默认使用自定义网桥而不是默认网桥,自定义网桥也许会和内网冲突,所以手动建立一个网桥(我是用docker-compose的)

networks:
  docker1:
    name: br-docker
    ipam:
      driver: default
      config:
        - subnet: 172.24.199.0/24

我没用过默认网桥,因为默认网桥真的问题很多,比如不能指定IP,容器间不能通信隔离等等,所以我也就没有测试默认网桥下的方案,不过现在openwrt的默认配置会给默认网桥docker0创建一个防火墙区域,直接手写防火墙规则也是可以的。

@shuosiw
Copy link

shuosiw commented Oct 6, 2023

发现一个更简单的方式:

手动创建一个 docker bridge 指定桥接到 br-lan

docker network create -d bridge \
    --subnet=192.168.5.0/24 --gateway=192.168.5.1 \
    -o "com.docker.network.bridge.name"="br-lan" lanet

其中子网设置为 openwrt LAN 的子网,然后网关指定为 br-lan 网关,比如我的是 192.168.5.0/24

image

然后就可以在 dockerman 里面启动容器指定使用这个网桥,也支持指定 IP:

image

这样启动后,就可以正常使用了,能够达到预期目的:

  1. 与 LAN 处于相同子网
  2. 每个容器独立 IP,且能够指定 IP
  3. 与其他接入 openwrt 的设备保持一致,也就是可以按需去做端口映射来暴露公网

@harrison-guo-chn
Copy link

博主你好,我在使用dockerman创建macvlan给容器使用时遇到无法与宿主机通讯的问题。
具体步骤如下,我的家庭网络为192.168.5.*,openwrt为192.168.5.1,
我在网络界面创建macvlan接口,父网卡br-lan,模式桥接,创建macvlan接口打钩,子网192.168.5.0/24,网关192.168.5.9,ip范围和排除ip留空,创建
创建之后在openwrt网络接口能看到docker macvlan接口,防火墙里面能看到和br-lan一起绑定的,
但是就是无法与宿主机通讯,导致容器无网络。
设置步骤完全参考esir之前的视频完成,
https://youtu.be/jXMgAz_GQxI?si=gCoflU65Pd_CaQa6

有尝试过网管设置为其他地址,无用

@shuosiw
Copy link

shuosiw commented Dec 1, 2023

尝试过 openwrt 配置 macvlan 给 docker 用,好像在 openwrt 下 macvlan 无法与宿主同网段。如果你只是想同网段,可以参考我上面的方案,重新创建一个 bridge 就行了

@ahfncj
Copy link

ahfncj commented Jan 26, 2024

发现一个更简单的方式:

手动创建一个 docker bridge 指定桥接到 br-lan

docker network create -d bridge \
    --subnet=192.168.5.0/24 --gateway=192.168.5.1 \
    -o "com.docker.network.bridge.name"="br-lan" lanet

其中子网设置为 openwrt LAN 的子网,然后网关指定为 br-lan 网关,比如我的是 192.168.5.0/24

image 然后就可以在 dockerman 里面启动容器指定使用这个网桥,也支持指定 IP: image 这样启动后,就可以正常使用了,能够达到预期目的:
  1. 与 LAN 处于相同子网
  2. 每个容器独立 IP,且能够指定 IP
  3. 与其他接入 openwrt 的设备保持一致,也就是可以按需去做端口映射来暴露公网

按照你的方法搞定了 谢谢大佬

@trader7z
Copy link

trader7z commented Apr 5, 2024

太感谢了

@chouchouxsl
Copy link

docker会将容器内的端口暴露给所有的网卡 而且op默认允许操作 iptables 建议直接关掉 然后用端口转发特定的服务 安全些 把 option iptables '1' 改成 0 再重启dockerd

config globals 'globals'
       option alt_config_file '/etc/docker/daemon.json'
        option data_root '/opt/docker/'
        option log_level 'warn'
        option iptables '1'  # 改成0

@shuosiw
Copy link

shuosiw commented Aug 27, 2024

发现一个更简单的方式:

手动创建一个 docker bridge 指定桥接到 br-lan

docker network create -d bridge \
    --subnet=192.168.5.0/24 --gateway=192.168.5.1 \
    -o "com.docker.network.bridge.name"="br-lan" lanet

其中子网设置为 openwrt LAN 的子网,然后网关指定为 br-lan 网关,比如我的是 192.168.5.0/24

image 然后就可以在 dockerman 里面启动容器指定使用这个网桥,也支持指定 IP: image 这样启动后,就可以正常使用了,能够达到预期目的:
  1. 与 LAN 处于相同子网
  2. 每个容器独立 IP,且能够指定 IP
  3. 与其他接入 openwrt 的设备保持一致,也就是可以按需去做端口映射来暴露公网

整理了一篇文档:openwrt 自定义网桥

@VergilGao
Copy link

经过我的不懈努力,最终放弃 docker 转投 podman 了 (笑

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants