在安裝docker時,會自動在host主機上創建三個網絡,用docker network ls
可以進行查看:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b271af4d6598 bridge bridge local
95f888208994 host host local
5705b1b4107d none null local
none網絡
none網絡就是什麼都沒有的網絡,掛在none網絡下面的容器除了了lo,沒有其他任何的網卡,在創建容器的時候可以通過--network=none
指定容器使用none網絡。
$ docker run -it --network=none busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
可以看到該容器只有一塊網卡lo,封閉意味着隔離,一些對安全性要求高並且不需要聯網的應用可以使用 none 網絡。
host網絡
連接到host網絡的容器共享host的網絡棧,容器的網絡配置跟host的完全相同:
$ docker run -it --network=host busybox
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:09:e3:78 brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
link/ether 02:42:9b:0d:23:8b brd ff:ff:ff:ff:ff:ff
31: vethb6ac730@if30: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
link/ether be:0d:67:bb:5f:9c brd ff:ff:ff:ff:ff:ff
33: veth5819fa7@if32: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
link/ether 8a:a7:7c:de:29:16 brd ff:ff:ff:ff:ff:ff
35: veth7c93491@if34: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
link/ether 9a:19:ce:26:aa:ab brd ff:ff:ff:ff:ff:ff
/ # hostname
ubuntu
容器中能看到host的所有網卡,連hostname也跟host一樣。
直接使用 Docker host 的網絡最大的好處就是性能,如果容器對網絡傳輸效率有較高要求,則可以選擇 host 網絡。當然不便之處就是犧牲一些靈活性,比如要考慮端口衝突問題,Docker host 上已經使用的端口就不能再用了。
Docker host 的另一個用途是讓容器可以直接配置 host 網路。比如某些跨 host 的網絡解決方案,其本身也是以容器方式運行的,這些方案需要對網絡進行配置,比如管理 iptables
bridge網絡
docker在安裝時會創建一個名爲docker0的linux bridge。如果容器啓動的時候不指定–network,那麼容器會默認掛在docker0上。
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02429b0d238b no
現在docker0上沒有任何網絡設備,我們創建一個容器看看。
root@ubuntu:~# docker run -d httpd
3f8da19c11f089cce5b3f85bc016f3403db0ad4af71a7abea0b696afd1886411
root@host1:~# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02429b0d238b no vethe631bd9
root@ubuntu:~# docker exec -it 3f8da19c11f0 bash
root@3f8da19c11f0:/usr/local/apache2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
52: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以看到一個新的網絡設備掛在在docker0上,vethe631bd9
就是新創建的httpd容器的虛擬網卡。看了容器內部的網卡爲eth0@if53
,爲什麼從外面看到的和容器內部看到的網卡不一樣呢?
實際上
vethe631bd9
和eth0@if53
是一對veth pair。veth pair是一種成對出現的網絡設備,可以理解爲一根網線的兩端,一端(eth0@if53
)在容器內,另一端(vethe631bd9
)掛在docker0上,其效果就是相當於(eth0@if53
)也掛在docker0上。
還看到eth0@if53
已經配置了IP爲172.17.0.2
,爲什麼是這個網段,我們通過docker network inspect bridge
看一下bridge網絡的配置:
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "b271af4d65980ecfa171fdad89636864ec076f45fb8c8558310916bedc7ecda0",
"Created": "2018-01-22T17:51:21.295766604+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
......
原理bridge網絡的Subnet(子網)是172.17.0.0/16
,Gateway(網關)是172.17.0.1
,這個網關就是docker0。
在容器啓動的過程中,docker會自動從172.17.0.0/16
中分配一個IP。
自定義容器網絡
docker提供了三種user-defined網絡驅動:bridge,overlay和macvlan。後兩種用於創建跨主機的網絡。
可以使用bridge驅動創建類似bridge的網絡:
$ docker network create --driver bridge my_net
5e9efda5449ba5a581e9fb91e3afbb1621bacd823b0ad08ef79b5d3cd368e1da
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
b271af4d6598 bridge bridge local
95f888208994 host host local
5e9efda5449b my_net bridge local
5705b1b4107d none null local
$ brctl show
bridge name bridge id STP enabled interfaces
br-5e9efda5449b 8000.02426b4ed3ee no
docker0 8000.02429b0d238b no vethe631bd9
這樣我們成功穿創建了一個my_net的網絡,新增加了一個網橋br-5e9efda5449b
,並且5e9efda5449b
是my_net網絡的短ID。
通過docker network inspect my_net
命令查看my_net網絡的配置信息:
$ docker network inspect my_net
[
{
"Name": "my_net",
"Id": "5e9efda5449ba5a581e9fb91e3afbb1621bacd823b0ad08ef79b5d3cd368e1da",
"Created": "2018-01-23T15:44:17.670486371+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
.......
docker自動爲my_net網絡分配了子網和網關。
同時我們也可以自己指定subnet和gateway,在創建網絡的時候加上--subnet
和--gateway
參數就可以了:
$ docker network create --driver bridge --subnet 172.19.0.0/24 --gateway 172.19.0.1 my_net2
1ded797aeede01408e2a70295e7b327a06233ac4e799b7da7e0913db1f41d8dd
$ brctl show
brctl show
bridge name bridge id STP enabled interfaces
br-1ded797aeede 8000.0242bfebcd26 no
$ ifconfig br-1ded797aeede
br-1ded797aeede Link encap:以太網 硬件地址 02:42:bf:eb:cd:26
inet 地址:172.19.0.1 廣播:172.19.0.255 掩碼:255.255.255.0
UP BROADCAST MULTICAST MTU:1500 躍點數:1
接收數據包:0 錯誤:0 丟棄:0 過載:0 幀數:0
發送數據包:0 錯誤:0 丟棄:0 過載:0 載波:0
碰撞:0 發送隊列長度:0
接收字節:0 (0.0 B) 發送字節:0 (0.0 B)
$ docker network inspect my_net2
[
{
"Name": "my_net2",
"Id": "1ded797aeede01408e2a70295e7b327a06233ac4e799b7da7e0913db1f41d8dd",
"Created": "2018-01-23T15:55:51.894463236+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/24",
"Gateway": "172.19.0.1"
}
......
到這裏,我們自己指定了網絡。my_net2對應的網橋是br-1ded797aeede
。
容器要使用新的網絡,可以用--network
指定:
$ docker run -it --network=my_net2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.2/24 brd 172.19.0.255 scope global eth0
valid_lft forever preferred_lft forever
容器分到的地址是172.19.0.2
,那麼能不能給容器指定一個靜態IP呢?通過--ip
參數就可以給容器指定靜態IP:
$ docker run -it --network=my_net2 --ip 172.19.0.6 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
58: eth0@if59: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:00:06 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.6/24 brd 172.19.0.255 scope global eth0
valid_lft forever preferred_lft forever
到這裏,我們給容器指定了靜態IP:172.19.0.6
注意:只有通過
--subnet
創建的網絡才能指定靜態IP
同主機網絡的通信
上面的兩個busybox容器都掛在my_net2上,我們測試以下能否互通:
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
56: eth0@if57: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.19.0.2/24 brd 172.19.0.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ping 172.19.0.6 -c 3
PING 172.19.0.6 (172.19.0.6): 56 data bytes
64 bytes from 172.19.0.6: seq=0 ttl=64 time=0.224 ms
64 bytes from 172.19.0.6: seq=1 ttl=64 time=0.192 ms
64 bytes from 172.19.0.6: seq=2 ttl=64 time=0.336 ms
--- 172.19.0.6 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.192/0.250/0.336 ms
同一網絡中的容器、網關之間都是互通的
不同網絡中的容器不能互通,通過docker network connect
命令可以實現:
$ docker network connect my_net2 3f8da19c11f0
$ docker exec -it 3f8da19c11f0 bash
root@3f8da19c11f0:/usr/local/apache2# ping 172.19.0.6 -c 3
PING 172.19.0.6 (172.19.0.6): 56 data bytes
64 bytes from 172.19.0.6: icmp_seq=0 ttl=64 time=0.162 ms
64 bytes from 172.19.0.6: icmp_seq=1 ttl=64 time=0.196 ms
64 bytes from 172.19.0.6: icmp_seq=2 ttl=64 time=0.160 ms
--- 172.19.0.6 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.160/0.173/0.196/0.000 ms
果然,能夠互通了