现在Docker越来越流行了,Compose用起来也非常的方便,之前图方便使用network就用host,这样服务完全暴露在公网上,最近研究了下bridge,感觉还不错。
参考:https://juejin.im/entry/5a79836df265da4e8c44ec8b
Docker 网桥网络工作原理
Docker 的网络实现主要会用到以下功能:
- Network Namespace: 用于隔离容器和宿主机之间地网络;
- Veth 设备对: 用于连接宿主机和容器, 每个容器都会有一对 Veth 设备, 一个在容器内, 一个在宿主机内;
- 网桥: 通过网桥可以很方便地管理宿主机上的多个 veth 设备, 同时实现不同容器之间地互联;
- Iptables/NetFilter: SNAT 以实现容器内对外网的访问; 实现容器地端口映射等;
- 路由
详细原理如下图所示 (转自这篇博客):

创建 Network Namespace
通过命令 sudo ip netns add ns1
即可创建名为 ns1 的 network namespace, 我们可以通过下面地命令查看当前系统中已有的 network namespace:
[ec2-user@ip-10-24-254-11 ~]$ sudo ls -1 /var/run/netns
ns1
Note: 我们可以通过命令 sudo ip netns del ns1
来删除之前创建地 network namespace.
创建 veth 设备对
通过下面的命令创建:
[ec2-user@ip-10-24-254-11 ~]$ sudo ip link add veth0 type veth peer name veth1
[ec2-user@ip-10-24-254-11 ~]$ ip addr show | grep veth
311: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
312: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
我们把 veth1 移动到 ns1 namespace 里: sudo ip link set veth1 netns ns1
. 现在我们在宿主机中就看不到 veth1 了:
[ec2-user@ip-10-24-254-11 ~]$ ip addr show | grep veth
312: veth0@if311: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
当我们切换到 ns1 就可以查看到 veth1 了:
[ec2-user@ip-10-24-254-11 ~]$ sudo ip netns exec ns1 bash
[root@ip-10-24-254-11 ec2-user]# ip addr show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
311: veth1@if312: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 3e:a0:ce:a7:8f:4c brd ff:ff:ff:ff:ff:ff link-netnsid 0
Note: 可以通过 sudo ip del link veth0
来删除这个设备对.
创建网桥并实现 veth1 和宿主机的互联
我们在系统默认 namespace 创建网桥 br-demo
, 并将 veth0 加入到网桥中:
[ec2-user@ip-10-24-254-11 ~]$ sudo brctl addbr br-demo
[ec2-user@ip-10-24-254-11 ~]$ sudo brctl addif br-demo veth0
[ec2-user@ip-10-24-254-11 ~]$ sudo brctl show | grep 'br-demo'
br-demo 8000.0aa51a826228 no veth0
我们给网桥添加 ip 地址: sudo ifconfig br-demo 172.8.0.1
. 同时命令启动虚拟网卡 veth0 sudo ip link set dev veth0 up
. 再登录进 ns1 namespace 给 veth1 设置 ip 地址:
[root@ip-10-24-254-11 ec2-user]# ifconfig veth1 172.8.0.8
这时我们便可以 ping 通 br-demo
的地址了:
[root@ip-10-24-254-11 ec2-user]# ping -c 1 172.8.0.1
PING 172.8.0.1 (172.8.0.1) 56(84) bytes of data.
64 bytes from 172.8.0.1: icmp_seq=1 ttl=255 time=0.044 ms
给 veth1 添加外网访问
在宿主机上编辑 iptables , 添加以下规则:
sudo iptables -t filter -A FORWARD -i br-demo ! -o br-demo -j ACCEPT
sudo iptables -t filter -A FORWARD -i br-demo -o br-demo -j ACCEPT
sudo iptables -t filter -A FORWARD -o br-demo -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 172.8.0.0/16 ! -o br-demo -j MASQUERADE
在 ns1 namespace 里测试是否可以连通外网:
[root@ip-10-24-254-11 ec2-user]# ping baidu.com -c1
PING baidu.com (111.13.101.208) 56(84) bytes of data.
64 bytes from 111.13.101.208: icmp_seq=1 ttl=39 time=258 ms
注意:若从ns1 尝试 ping到宿主机,发现ping不通
[root@localhost home]# ping baidu.com
ping: baidu.com: 未知的名称或服务
[root@localhost home]# ping 192.168.102.11
connect: 网络不可达
那就需要配置一下ns1 的网关为br-demo
sudo ip netns exec ns1 route add default gw 172.8.0.1
映射 ns1 内部端口到宿主机
我们现在 ns1 内部通过 node 启动一个简单地 http server:
[root@localhost home]# node app.js
Server started responding on port 3000.
在宿主机上我们可以通过 veth1 的 ip 地址访问这个服务:
[root@localhost home]# curl -I 172.8.0.8:3000/news/all
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Content-Type: application/json; charset=utf-8
Content-Length: 46
ETag: W/"2e-lldIrdSb4AORaEEyD6KoN+mIA9Q"
Date: Mon, 29 Apr 2019 09:37:50 GMT
Connection: keep-alive
从别的机器直接访问宿主机映射后的端口
把下面地规则加入到 iptalbe 里, 我们便可以通过宿主机的 3033 端口访问到这个 service 了:
[ec2-user@ip-10-24-254-11 ~]$ sudo iptables -t nat -A PREROUTING -p tcp -m tcp --dport 3033 -j DNAT --to-destination 172.8.0.8:3000
[ec2-user@ip-10-24-254-11 ~]$ sudo iptables -t filter -A FORWARD -p tcp -m tcp --dport 3000 -j ACCEPT
$ curl -I 192.168.102.253:3033/news/all
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 46 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
Content-Type: application/json; charset=utf-8
Content-Length: 46
ETag: W/"2e-lldIrdSb4AORaEEyD6KoN+mIA9Q"
Date: Mon, 29 Apr 2019 09:40:50 GMT
Connection: keep-alive
注意这里必须要在别地机器上访问宿主机的 3033 端口!
直接在宿主机上访问映射后的端口
添加如下两条 iptables 规则后即可直接在本机地址上访问:
[ec2-user@ip-10-24-254-11 ~]$ sudo iptables -t nat -A OUTPUT -p tcp -m tcp --dport 3033 -j DNAT --to-destination 172.8.0.8:3000
[ec2-user@ip-10-24-254-11 ~]$ sudo iptables -t nat -A POSTROUTING -p tcp -m tcp --dport 3000 -j MASQUERADE
[ec2-user@ip-10-24-254-11 ~]$ curl -I 127.0.0.1:3033
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.7.12
Date: Tue, 06 Feb 2018 02:33:42 GMT
Content-type: text/html; charset=UTF-8
Content-Length: 1718
至此,Docker网桥工作正常,通过bridge方式部署服务,可以做到更好的服务保护。
网友评论