Docker 中的网络功能介绍
Docker 允许通过外部访问容器或容器互联的方式来提供网络服务
1) 外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -p或 -P参数来指定端口映射
运行容器时如果使用-P,Docker 会随机映射一个在49000-49900区间内的端口到内部容器开放的网络端口。
比如下面的容器,就随机选取了本地的32768端口映射到了容器中正开放的5000端口,此时访问本机的 32768 端口即可访问容器内 web 应用提供的界面
userdeMacBook-Pro:~ user$ docker run -d -P --name web -v /webapp training/webapp python app.py
Unable to find image 'training/webapp:latest' locally
latest: Pulling from training/webapp
e190868d63f8: Pull complete
909cd34c6fd7: Pull complete
0b9bfabab7c1: Pull complete
a3ed95caeb02: Pull complete
10bbbc0fc0ff: Pull complete
fca59b508e9f: Pull complete
e7ae2541b15b: Pull complete
9dd97ef58ce9: Pull complete
a4c1b0cb7af7: Pull complete
Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d
Status: Downloaded newer image for training/webapp:latest
1ad71e9d38081c38dcd355fd7a438cd9f94503e8bc28e99a48c0738b51e7efef userdeMacBook-Pro:~ user$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ad71e9d3808 training/webapp "python app.py" minutes ago Up minutes 0.0.0.0:->/tcp web
在浏览器中访问http://localhost:32768:
然后可以通过 docker logs 命令来查看浏览器访问应用的信息:
userdeMacBook-Pro:~ user$ docker logs web
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
172.17.0.1 - - [/Dec/ ::] "GET / HTTP/1.1" -
172.17.0.1 - - [/Dec/ ::] "GET /favicon.ico HTTP/1.1" -
-p(小写的)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个 容器。
支持的格式有:
- ip地址:主机端口:容器端口
- ip地址::容器端口
- 主机端口:容器端口
1》 映射所有接口地址
使用主机端口:容器端口格式,本地的 5000 端口可以映射到容器的 5000 端 口,如:
sudo docker run -d -p : training/webapp python app.py
此时默认会绑定本地所有接口上的所有ip地址
2》映射到指定地址的指定端口
使用 ip地址:主机端口:容器端口格式指定映射使用一个特定地址,比如 localhost 地址 127.0.0.1
docker run -d -p 127.0.0.1:: training/webapp python app.py
3》映射到指定地址的任意端口
使用ip地址::容器端口格式绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口:
docker run -d -p 127.0.0.1:: training/webapp python app.py
还可以使用 udp 标记来指定 udp 端口
docker run -d -p 127.0.0.1::/udp training/webapp python app.py
查看映射端口配置——docker port
查看当前映射的端口配置,也可以查看到绑定的地址
userdeMacBook-Pro:~ user$ docker port web
0.0.0.0:
⚠️:
容器有自己的内部网络和 ip 地址(使用 docker inspect可以获取所有的变量,Docker 还可以有一个可变的网络配置。)
-p 标记可以多次使用来绑定多个端口,如:
docker run -d -p : -p : training/webapp python app.py
2)容器互联
容器的连接(linking)系统是除了端口映射外,另一种跟容器中应用交互的方式。
该系统会在源和接收容器之间创建一个隧道,接收容器可以看到源容器指定的信息。
1》自定义容器命名——使用 --name参数
连接系统依据容器的名称来执行。因此,首先需要自定义一个好记的容器命名
当创建容器的时候,系统默认会分配一个名字。
但是自定义命名容器有2个好处:
- 自定义的命名,比较好记,比如一个web应用容器我们可以给它起名叫web
- 当要连接其他容器时候,可以作为一个有用的参考点,比如连接web容器到db 容器
docker run -d -P --name web training/webapp python app.py
可以使用docker ps -l查看,也可以使用 docker inspect来查看容器的名字
userdeMacBook-Pro:~ user$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1ad71e9d3808 training/webapp "python app.py" About an hour ago Up About an hour 0.0.0.0:->/tcp web
userdeMacBook-Pro:~ user$ docker inspect -f "{{ .Name }}" 1ad71e9d3808
/web
注意:容器的名称是唯一的。如果已经命名了一个叫 web 的容器,当你要再次使用 web 这个名称的时候,需要先用docker rm来删除之前创建的同名容器。
在执行 docker run的时候如果添加 -rm 标记,则容器在终止后会立刻删除。
⚠️-rm 和 -d(后台运行)参数不能同时使用。
2》 容器互联——使用 --link参数
格式: --link name:alias
其中 name是要链接的容器的名称, alias是这个连接的别名
先创建一个新的数据库容器db:
userdeMacBook-Pro:~ user$ docker run -d --name db training/postgres
Unable to find image 'training/postgres:latest' locally
latest: Pulling from training/postgres
a3ed95caeb02: Pull complete
6e71c809542e: Pull complete
2978d9af87ba: Pull complete
e1bca35b062f: Pull complete
500b6decf741: Pull complete
74b14ef2151f: Pull complete
7afd5ed3826e: Pull complete
3c69bb244f5e: Pull complete
d86f9ec5aedf: Pull complete
010fabf20157: Pull complete
Digest: sha256:a945dc6dcfbc8d009c3d972931608344b76c2870ce796da00a827bd50791907e
Status: Downloaded newer image for training/postgres:latest
2fca948912dcfd40849d1f2080db69bed0f51a9b1c1a10ceba7e3bf7d0960e5f
删除之前创建的 web 容器:
userdeMacBook-Pro:~ user$ docker rm -f web
web
然后创建一个新的 web 容器,并将它连接到 db 容器:
userdeMacBook-Pro:~ user$ docker run -d -P --name web --link db:db training/webapp python app.py
d734bf29ad945f25e65e451d5d207b007a24004002dbaa722b28e02fb46ed51e
此时,db 容器和 web 容器成功建立了互联关系
使用 docker ps来查看容器的连接:
userdeMacBook-Pro:~ user$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d734bf29ad94 training/webapp "python app.py" seconds ago Up seconds 0.0.0.0:->/tcp web
2fca948912dc training/postgres "su postgres -c '/us…" seconds ago Up seconds /tcp db
这样子就不用像上面一样需要使用-p 或 -P映射端口了。
Docker 通过 2 种方式为容器公开连接信息:
- 环境变量
- 更新 /etc/hosts文件
首先是环境变量方式:
使用 env 命令来查看 web 容器的环境变量:
userdeMacBook-Pro:~ user$ docker run --rm --name web --link db:db training/webapp env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=994146340f40
DB_PORT=tcp://172.17.0.3:5432
DB_PORT_5432_TCP=tcp://172.17.0.3:5432
DB_PORT_5432_TCP_ADDR=172.17.0.3
DB_PORT_5432_TCP_PORT=
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web/db
DB_ENV_PG_VERSION=9.3
HOME=/root
其中 DB_ 开头的环境变量是供 web 容器连接 db 容器使用,前缀采用大写的连接别名。
然后更新 /etc/hosts文件方式,Docker 添加了host信息到父容器的 /etc 的文件。下面是父容器 web的 hosts文件:
userdeMacBook-Pro:~ user$ docker run -t -i --rm --link db:db training/webapp /bin/bash
root@36078e6ba58f:/opt/webapp# cat /etc/hosts
127.0.0.1 localhost
:: localhost ip6-localhost ip6-loopback
fe00:: ip6-localnet
ff00:: ip6-mcastprefix
ff02:: ip6-allnodes
ff02:: ip6-allrouters
172.17.0.3 db 2fca948912dc //db容器的 容器名和ID
172.17.0.2 36078e6ba58f //web容器的ID
可以在 web 容器中安装 ping 命令来测试跟db容器的连通:
root@36078e6ba58f:/opt/webapp# apt-get install -yqq inetutils-ping
(Reading database ... files and directories currently installed.)
Removing ubuntu-minimal (1.325) ...
Removing iputils-ping (:-4ubuntu1.) ...
Selecting previously unselected package inetutils-ping.
(Reading database ... files and directories currently installed.)
Preparing to unpack .../inetutils-ping_2%3a1.9.2-1_amd64.deb ...
Unpacking inetutils-ping (:1.9.-) ...
Setting up inetutils-ping (:1.9.-) ...
root@36078e6ba58f:/opt/webapp# ping db
PING db (172.17.0.3): data bytes
bytes from 172.17.0.3: icmp_seq= ttl= time=0.099 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.120 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.063 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.202 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.101 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.133 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.129 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.104 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.129 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.130 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.128 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.128 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.063 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.130 ms
bytes from 172.17.0.3: icmp_seq= ttl= time=0.130 ms
^C--- db ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max/stddev = 0.063/0.119/0.202/0.032 ms
用 ping 来测试db容器,它会解析成 172.17.0.3。 *注意:官方的 ubuntu 镜像 默认没有安装 ping,需要自行安装
用户可以链接多个父容器到子容器,比如可以链接多个 web 到 db 容器上
3) 高级网络配置
1》默认网络
docker network命令使用
1.首先查看docker network命令怎么使用
userdeMBP:~ user$ docker network --help Usage: docker network COMMAND Manage networks Commands:
connect Connect a container to a network 将容器连接到网络上,默认连接的是bridge网络
create Create a network 创建一个网络,使用--driver参数指定网络类型
disconnect Disconnect a container from a network 断开容器连接的网络
inspect Display detailed information on one or more networks 展示一个或多个网络的详细信息
ls List networks 列举现有的所有网络
prune Remove all unused networks 移除所有不再使用的网络
rm Remove one or more networks 移除一个或多个网络 Run 'docker network COMMAND --help' for more information on a command.
2.然后查看目前的网络情况,初始时是默认有下面的三类网络的
userdeMBP:~ user$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5a8633141529 bridge bridge local
78c9cc883ccc host host local
454aa19cf801 none null local
当 Docker 启动时,会自动在主机上创建一个虚拟网桥,实际上是 Linux 的一个 bridge(即这上面的bridge网络),可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。
none网络——即什么都没有的网络
打开两个连接了默认bridge网络的ubuntu容器和一个连接了none网络的ubuntu容器,然后查看它们的ip配置信息,并ping本地主机看能否连通:
当你想要实现一些对安全要求比较高并且不需要联网的操作时,就可以使用none网络
上图可见,如果你使用的是bridge网络,你是可以ping通你现在的主机的网络的;如果你是none网络,你是无法连接网络的
比如你有些容器的作用时生成密钥文件等操作时,使用none网络就能保证密钥文件的安全行,不会被窃取
host网络
打开了一个连接了host网络的ubuntu容器,然后查看其ip信息
userdeMBP:~ user$ docker run -it --network=host --name=ubuntu3 ubuntu:14.04 /bin/bash
root@linuxkit-:/# ip addr
: lo: <LOOPBACK,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN group default qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ brd 127.255.255.255 scope host lo
valid_lft forever preferred_lft forever
inet6 ::/ scope host
valid_lft forever preferred_lft forever
: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc pfifo_fast state UP group default qlen
link/ether ::::: brd ff:ff:ff:ff:ff:ff
inet 192.168.65.3/ brd 192.168.65.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80:::ff:fe00:/ scope link
valid_lft forever preferred_lft forever
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: ip6tnl0@NONE: <NOARP> mtu qdisc noop state DOWN group default qlen
link/tunnel6 :: brd ::
: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
link/ether ::c4:a0:b5:3e brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/ brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80:::c4ff:fea0:b53e/ scope link
valid_lft forever preferred_lft forever
: veth4a027b0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue master docker0 state UP group default
link/ether :2b:b2:b1:de: brd ff:ff:ff:ff:ff:ff
inet6 fe80::942b:b2ff:feb1:de52/ scope link
valid_lft forever preferred_lft forever
: veth3406c1a@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue master docker0 state UP group default
link/ether ba::0c::c0:9e brd ff:ff:ff:ff:ff:ff
inet6 fe80::b880:cff:fe67:c09e/ scope link
valid_lft forever preferred_lft forever
: vethcee69e2@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue master docker0 state UP group default
link/ether ::1e:7b::0c brd ff:ff:ff:ff:ff:ff
inet6 fe80:::1eff:fe7b:10c/ scope link
valid_lft forever preferred_lft forever
(参考https://blog.csdn.net/liukuan73/article/details/51603074)
因为docker使用了Linux的Namespace技术来进行资源的隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等
使用bridge网络时,一个容器会分配一个独立的Network Namespace。但是如果使用的是host网络,容器将不会获得一个独立的Network Namespace,而是与宿主机公用一个Network Namespace。在这种情况下,容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。容器可以和宿主机一样,使用宿主机的eth0,实现和外界的通信。换言之,容器的IP地址即为宿主机eth0的IP地址
因此上面开启的容器使用ip addr命令时,发现得到的信息都是宿主机上的信息。因此当外界想要访问该容器时,直接访问宿主机的IP和容器开放的端口即可,不需要任何的NAT转换,就像直接运行在宿主机一样。
⚠️但是容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的
host网络其实是bridge网络的一种补充,但是也有不足的地方:
- 容器网络环境隔离性弱化,即容器不再拥有隔离、独立的网络栈
- 由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用
- 容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以bridge网络模式容器的端口映射
同时查看host网络此时的详细信息:
userdeMacBook-Pro:~ user$ docker network inspect 78c9cc883ccc
[
{
"Name": "host",
"Id": "78c9cc883ccc186865ab14c31f7d3ebafecd725e2524a7ab3bb550fb91a73705",
"Created": "2018-07-21T02:08:33.191948595Z",
"Scope": "local",
"Driver": "host",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"084fd2f2927a18f8c6003f7ee70e5fef80e6ffca6246f75d8ada71c5be76a8bf": {
"Name": "ubuntu3", //即上面连接了host网络的容器
"EndpointID": "a57a350fb83a4c45d276eefaf29c0ef13278af2cfbfa3a6a7c9f36a1430f07cb",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"3c3f1551282d8f983faf974d96e366262d133da662108c43506e6dcb16902b4c": {
"Name": "k8s_POD_etcd-docker-for-desktop_kube-system_1f439806cd68459343e83b51b9f719eb_0",
"EndpointID": "6c2f76ff13c3ebe545a1c3f36d864d9525aadaebced72270abb88fe92aaed69e",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"636bc1e866ed8f215261e30a522feeb91b2a8417be0a4f55324a013e7efadfcf": {
"Name": "k8s_POD_kube-controller-manager-docker-for-desktop_kube-system_ac5424d04b6928ef15ca302888630c4e_0",
"EndpointID": "25234b9025957c835fc0669334affd6a74bc03d9b679e50b2fe713cbfe1c9f8c",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"7a58a9d0aa01abb785392264a8c5406593d4fa2b6749f27094b4f80b939e1ab4": {
"Name": "k8s_POD_kube-scheduler-docker-for-desktop_kube-system_ea66a171667ec4aaf1b274428a42a7cf_0",
"EndpointID": "3a83f9b42be6f8b0a68e440b839aff4326d4d524590f5471ed6882560bb9658d",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
},
"f9d84fe15fe1591d15d76fad2162285426aef4a700ed78c54b28c4a71b19c28c": {
"Name": "k8s_POD_kube-apiserver-docker-for-desktop_kube-system_f10287b5cba0247140caeedc2e1fd602_0",
"EndpointID": "3b43272e8ab15a3fe91d1c04cae74af2ce560b8431aaa3027bfe81b7e41fa531",
"MacAddress": "",
"IPv4Address": "",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
bridge网络
Docker 会随机分配一个本地未占用的私有网段(在 RFC1918 中定义)中的一 个地址给 docker0接口。比如典型的 172.17.42.1,掩码为255.255.0.0。此后启动的容器内的网口也会自动分配一个同一网段( 172.17.0.0/16 )的地址。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即eth0 ——下面打开的容器查看IP信息时的eth0;
userdeMBP:~ user$ docker run -it ubuntu:14.04 /bin/bash
root@481d94d59f9f:/# ifconfig
eth0 Link encap:Ethernet HWaddr ::ac:::
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (508.0 B) TX bytes: (0.0 B) lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (0.0 B) TX bytes: (0.0 B) root@481d94d59f9f:/# ping 10.240.203.84
PING 10.240.203.84 (10.240.203.84) () bytes of data.
bytes from 10.240.203.84: icmp_seq= ttl= time=0.647 ms
bytes from 10.240.203.84: icmp_seq= ttl= time=0.513 ms
bytes from 10.240.203.84: icmp_seq= ttl= time=0.674 ms
^C
--- 10.240.203.84 ping statistics ---
packets transmitted, received, % packet loss, time 2043ms
rtt min/avg/max/mdev = 0.513/0.611/0.674/0.073 ms
root@481d94d59f9f:/# ping ww.baidu.com
PING ps_other.a.shifen.com (123.125.114.144) () bytes of data.
bytes from 123.125.114.144: icmp_seq= ttl= time=46.3 ms
bytes from 123.125.114.144: icmp_seq= ttl= time=48.1 ms
bytes from 123.125.114.144: icmp_seq= ttl= time=47.1 ms
^C
--- ps_other.a.shifen.com ping statistics ---
packets transmitted, received, % packet loss, time 2000ms
rtt min/avg/max/mdev = 46.341/47.210/48.168/0.748 ms
可以ping通本地主机网络可外部网络
另一端在本地并被挂载到docker0网桥,名称以 veth开头(例如vethAQI2QT)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间一个虚拟共享网络。
因为我使用的是mac系统,为了使用Linux的命令来查看网桥信息,可以在刚刚使用--network=host的容器上进行查看:
root@linuxkit-:/# brctl show //没有安装brctl
bash: brctl: command not found root@linuxkit-:/# apt-get install bridge-utils
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package brctl-utils //没有找到这个包,可能需要更新下源 root@linuxkit-:/# apt-get update //更新源
Ign http://archive.ubuntu.com trusty InRelease
Get: http://archive.ubuntu.com trusty-updates InRelease [65.9 kB]
...
Get: http://archive.ubuntu.com trusty/multiverse amd64 Packages [169 kB]
Fetched 13.3 MB in 52s ( kB/s)
Reading package lists... Done root@linuxkit-:/# apt-get install bridge-utils //然后重新下载即可
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
bridge-utils
upgraded, newly installed, to remove and not upgraded.
...
然后就可以查看网桥信息了
root@linuxkit-:/# brctl show
bridge name bridge id STP enabled interfaces
docker0 .0242c4a0b53e no veth3406c1a
veth4a027b0
vethcee69e2
可以看见挂载到docker0网桥这边的接口为veth3406c1a、veth4a027b0和vethcee69e2
查看默认使用的bridge网络,如果在开启容器时没有制定,一般就会默认使用的是bridge网络。因为docker的桥接网络使用虚拟网桥,bridge网络用于同一主机上的docker容器相互通信,连接到同一个网桥的docker容器可以相互通信
userdeMacBook-Pro:~ user$ docker network inspect a782ffdae16f
[
{
"Name": "bridge",
"Id": "a782ffdae16f9c3dbfec0a992a9a6d605429c657263dc83f33c71ad499f5e2b8",
"Created": "2018-12-19T01:34:27.308734153Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"481d94d59f9f363fd3b00f09b793c9d7e1d90169626a7170f4d1012949c9ace4": {
"Name": "wonderful_matsumoto",
"EndpointID": "9dd9be72550d24135202f430dfeea0fb0132d52089045c933a5bfb6fd5ddb779",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"876cdcff687d83e5ea85d3c2eb16d01aac62bfd3e5051e5e65f0fd49230d7333": {
"Name": "ubuntu2",
"EndpointID": "9c16f983ff075f1499dcc1de4ead5ac77097829a68ff868a328e90e336660e29",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
},
"b4a512f0230fa598e7e40171e0597ea6db0740105449314a1a3767dcaa4a0edb": {
"Name": "registry",
"EndpointID": "b164dd37f23eac13364f1378642c5e8b88b783ea48fbbce26017ab02b33b542e",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",//说明这个是默认的bridge网络
"com.docker.network.bridge.enable_icc": "true",//说明支持容器间互相通信
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",//默认网桥的名字为docker0
"com.docker.network.driver.mtu": ""
},
"Labels": {}
}
]
//上面可见为开启的三个容器分别分配了172.17.0.0/16网段下的地址
userdeMacBook-Pro:~ user$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
084fd2f2927a ubuntu:14.04 "/bin/bash" About an hour ago Up About an hour ubuntu3
876cdcff687d ubuntu:14.04 "/bin/bash" About an hour ago Up About an hour ubuntu2
e6ba811ecb6a ubuntu:14.04 "/bin/bash" About an hour ago Up About an hour thirsty_germain
481d94d59f9f ubuntu:14.04 "/bin/bash" About an hour ago Up About an hour wonderful_matsumoto
b4a512f0230f registry "/entrypoint.sh /etc…" days ago Up hours 0.0.0.0:->/tcp registry
- 默认桥接网络中的容器只能通过IP地址访问其他容器(除非使用遗留的-link指令连接两个容器),而自定义桥接网络提供DNS解析,可以通过容器的名字或是别名访问其他容器
- 容器可以*的进入或是退出自定义桥接(bridge)网络,如果想要退出默认桥接(bridge)网络,需要先停止容器的运行,然后重新创建该容器,并指定需要连接的其他网络
- 如果更改了默认桥接网络的网络配置,需要重新启动docker,并且由于默认桥接网络只有一个,因此所有容器的网络配置都是一样的,而用户自定义网络可以在创建时指定网络配置(例如默认网关、MTU等),不需要重启docker,灵活性更高
- 在默认桥接网络中,可以通过--link参数连接两个容器来共享环境变量,用户自定义网络中无法使用这种方式,但是docker提供了更好的方式:
1.多个容器可以使用docker volume(这是docker存储数据的一种方式,以后会介绍)挂载到同一个文件,在文件中指明环境变量,从而实现所容器的环境变量共享
2.多个容器可以使用同一个docker-compose.yml(与docker service有关)文件启动 ,可以在该文件中定义共享环境变量
3.可以使用swarm services,并且通过 secrets 和 configs (这两个还没看)实现环境变量共享
从上图可见,基本上就相当于打开了别名为ubuntu10的ubuntu8容器,两者的IP地址是完全一样的,连主机名都是一样的。当然,ubuntu10容器也是开启了的:
userdeMBP:~ user$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3b854b76e02e ubuntu:14.04 "/bin/bash" 2 minutes ago Up 2 minutes ubuntu10
f07c50c1c6ee ubuntu:14.04 "/bin/bash" 27 minutes ago Up 27 minutes ubuntu8
userdeMacBook-Pro:~ user$ docker network ls //查看当前的网络
NETWORK ID NAME DRIVER SCOPE
a782ffdae16f bridge bridge local
78c9cc883ccc host host local
454aa19cf801 none null local
userdeMacBook-Pro:~ user$ docker network create --driver bridge myNetwork1 //新添加一个bridge网络,名字叫myNetwork1
f16ae5c303c68f25e63ff80c09a3289fcf1785c1bc86a3baabeef6687035cf0b
userdeMacBook-Pro:~ user$ docker network ls //查看得到新的网络myNetwork1
NETWORK ID NAME DRIVER SCOPE
a782ffdae16f bridge bridge local
78c9cc883ccc host host local
f16ae5c303c6 myNetwork1 bridge local
454aa19cf801 none null local
root@linuxkit-:/# brctl show
bridge name bridge id STP enabled interfaces
br-f16ae5c303c6 .0242751521cb no //这个就是新生成的bridge网络,还没有连接容器,所以interfaces为空
docker0 .0242c4a0b53e no veth3406c1a
veth4a027b0
vethcee69e2
root@linuxkit-:/# ip addr
...
: br-f16ae5c303c6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu qdisc noqueue state DOWN group default
link/ether :::::cb brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/ brd 172.18.255.255 scope global br-f16ae5c303c6 //可以看见其被自动分配的网段为172.18.0.1/16
valid_lft forever preferred_lft forever
网桥名称br-f16ae5c303c6 即 br-networkId
使用docker network inspect命令查看生成的network信息:
userdeMacBook-Pro:~ user$ docker network inspect f16ae5c303c6
[
{
"Name": "myNetwork1",
"Id": "f16ae5c303c68f25e63ff80c09a3289fcf1785c1bc86a3baabeef6687035cf0b",
"Created": "2018-12-19T03:56:51.09420804Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16", //自动分配的网段和网关
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
userdeMacBook-Pro:~ user$ docker network create --driver bridge --subnet 172.20.11.0/ --gateway 172.20.11.1 myNetwork2
9dc30b4c7e392ad993540f19638653e62b4cff8af4944d8ab29b7b88c467331d
userdeMacBook-Pro:~ user$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a782ffdae16f bridge bridge local
78c9cc883ccc host host local
f16ae5c303c6 myNetwork1 bridge local
9dc30b4c7e39 myNetwork2 bridge local
454aa19cf801 none null local
userdeMacBook-Pro:~ user$ docker network inspect 9dc30b4c7e39
[
{
"Name": "myNetwork2",
"Id": "9dc30b4c7e392ad993540f19638653e62b4cff8af4944d8ab29b7b88c467331d",
"Created": "2018-12-19T04:13:47.531039833Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.11.0/24",
"Gateway": "172.20.11.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
userdeMacBook-Pro:~ user$
指明了网段为172.20.11.0/24,网关为172.20.11.1
root@linuxkit-:/# ifconfig br-9dc30b4c7e39
br-9dc30b4c7e39 Link encap:Ethernet HWaddr :::f9:5d:
inet addr:172.20.11.1 Bcast:172.20.11.255 Mask:255.255.255.0
UP BROADCAST MULTICAST MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (0.0 B) TX bytes: (0.0 B)
这样我们在启动容器的时候就能够使用上面自定义的bridge网络了:
userdeMacBook-Pro:~ user$ docker run -it --name=ubuntu4 --network=myNetwork2 ubuntu:14.04 /bin/bash
root@57fb8937e663:/# ifconfig
eth0 Link encap:Ethernet HWaddr ::ac::0b:
inet addr:172.20.11.2 Bcast:172.20.11.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (1.1 KB) TX bytes: (0.0 B) lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (0.0 B) TX bytes: (0.0 B) root@57fb8937e663:/#
可见的确是在172.20.11.0/24网段下
上面的容器的IP地址都是动态分配的,如果用户想要实现指定静态的IP地址的话,可以使用--ip参数:
userdeMacBook-Pro:~ user$ docker run -it --name=ubuntu5 --network=myNetwork2 --ip=172.20.11.8 ubuntu:14.04 /bin/bash
root@9e11c1b9e90d:/# ifconfig
eth0 Link encap:Ethernet HWaddr ::ac::0b:
inet addr:172.20.11.8 Bcast:172.20.11.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (508.0 B) TX bytes: (0.0 B) lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU: Metric:
RX packets: errors: dropped: overruns: frame:
TX packets: errors: dropped: overruns: carrier:
collisions: txqueuelen:
RX bytes: (0.0 B) TX bytes: (0.0 B)
指定了静态地址172.20.11.8
⚠️只有当连接的网络指定了--subnet时,相应的容器开启时才能够使用--ip参数
root@9e11c1b9e90d:/# ping -c 172.20.11.1
PING 172.20.11.1 (172.20.11.1) () bytes of data.
bytes from 172.20.11.1: icmp_seq= ttl= time=0.092 ms
bytes from 172.20.11.1: icmp_seq= ttl= time=0.101 ms
bytes from 172.20.11.1: icmp_seq= ttl= time=0.090 ms --- 172.20.11.1 ping statistics ---
packets transmitted, received, % packet loss, time 2049ms
rtt min/avg/max/mdev = 0.090/0.094/0.101/0.009 ms
那如果我们去ping默认bridge网络下的ubuntu容器,发现是不能够ping通的:
root@9e11c1b9e90d:/# ping -c 172.17.0.4
PING 172.17.0.4 (172.17.0.4) () bytes of data. --- 172.17.0.4 ping statistics ---
packets transmitted, received, % packet loss, time 2068ms
root@linuxkit-:/# ip r //查看本地主机上的路由表信息
...
172.17.0.0/ dev docker0 proto kernel scope link src 172.17.0.1
172.20.11.0/24 dev br-9dc30b4c7e39 proto kernel scope link src 172.20.11.1
...
然后再查看本地系统是否开启了转发支持:
root@linuxkit-:/# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = //开启了
然后再查看防火墙iptables,需要重新使用--privileged参数的--network=host的容器:
userdeMBP:~ user$ docker run -it --privileged --network=host --name=ubuntu6 ubuntu:14.04 /bin/bash
root@linuxkit-:/# ip r
...
172.17.0.0/ dev docker0 proto kernel scope link src 172.17.0.1
172.20.11.0/ dev br-9dc30b4c7e39 proto kernel scope link src 172.20.11.1
... root@linuxkit-:/# iptables-save //需要安装iptables
bash: iptables-save: command not found root@linuxkit-:/# apt-get install iptables
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package iptables //需要更新源 root@linuxkit-:/# apt-get update //更新源
Ign http://archive.ubuntu.com trusty InRelease
...
Get: http://archive.ubuntu.com trusty/multiverse amd64 Packages [169 kB]
Fetched 13.3 MB in 50s ( kB/s)
Reading package lists... Done root@linuxkit-:/# apt-get install iptables //然后就能够成功安装了
Reading package lists... Done
...
Setting up libnfnetlink0:amd64 (1.0.-) ...
Setting up libxtables10 (1.4.-1ubuntu1) ...
Setting up iptables (1.4.-1ubuntu1) ...
Processing triggers for libc-bin (2.19-0ubuntu6.) ... root@linuxkit-:/# iptables-save //查看得到此时的防火墙规则
...
-A DOCKER -d 172.17.0.2/ ! -i docker0 -o docker0 -p tcp -m tcp --dport -j ACCEPT
-A DOCKER-ISOLATION-STAGE- -i br-9dc30b4c7e39 ! -o br-9dc30b4c7e39 -j DOCKER-ISOLATION-STAGE-
-A DOCKER-ISOLATION-STAGE- -i br-f16ae5c303c6 ! -o br-f16ae5c303c6 -j DOCKER-ISOLATION-STAGE-
-A DOCKER-ISOLATION-STAGE- -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-
-A DOCKER-ISOLATION-STAGE- -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o br-9dc30b4c7e39 -j DROP
-A DOCKER-ISOLATION-STAGE- -o br-f16ae5c303c6 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE- -j RETURN
-A DOCKER-USER -j RETURN
-A KUBE-FIREWALL -m comment --comment "kubernetes firewall for dropping marked packets" -m mark --mark 0x8000/0x8000 -j DROP
COMMIT
# Completed on Wed Dec ::
从这两句:
-A DOCKER-ISOLATION-STAGE- -o br-9dc30b4c7e39 -j DROP
-A DOCKER-ISOLATION-STAGE- -o docker0 -j DROP
可知iptables DROP 掉了网桥 docker0 与 br-9dc30b4c7e39 之间双向的流量
从规则的命名 DOCKER-ISOLATION
可知 docker 在设计上就是要隔离不同的 netwrok
那我们要如何让两者通信呢?
方法就是然后容器ubuntu5,即网络为 br-9dc30b4c7e39的容器添加一个新网卡,方法就是连接上docker0的bridge网络:
一开始它的网卡情况如下所示:
root@9e11c1b9e90d:/# ip a
: lo: <LOOPBACK,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN group default qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ scope host lo
valid_lft forever preferred_lft forever
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: ip6tnl0@NONE: <NOARP> mtu qdisc noop state DOWN group default qlen
link/tunnel6 :: brd ::
: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
link/ether ::ac::0b: brd ff:ff:ff:ff:ff:ff
inet 172.20.11.8/ brd 172.20.11.255 scope global eth0
valid_lft forever preferred_lft forever
然后为该容器添加bridge网络:
userdeMacBook-Pro:~ user$ docker network connect bridge 9e11c1b9e90d
然后我们就能够看见它多了一个网卡,地址为172.17.0.5/
root@9e11c1b9e90d:/# ip a
: lo: <LOOPBACK,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN group default qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ scope host lo
valid_lft forever preferred_lft forever
: tunl0@NONE: <NOARP> mtu qdisc noop state DOWN group default qlen
link/ipip 0.0.0.0 brd 0.0.0.0
: ip6tnl0@NONE: <NOARP> mtu qdisc noop state DOWN group default qlen
link/tunnel6 :: brd ::
: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
link/ether ::ac::0b: brd ff:ff:ff:ff:ff:ff
inet 172.20.11.8/ brd 172.20.11.255 scope global eth0
valid_lft forever preferred_lft forever
: eth1@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP group default
link/ether ::ac::: brd ff:ff:ff:ff:ff:ff
inet 172.17.0.5/ brd 172.17.255.255 scope global eth1
valid_lft forever preferred_lft forever
然后再次尝试ping ubuntu5的容器,发现能够成功ping通了:
root@9e11c1b9e90d:/# ping -c 172.17.0.4
PING 172.17.0.4 (172.17.0.4) () bytes of data.
bytes from 172.17.0.4: icmp_seq= ttl= time=0.133 ms
bytes from 172.17.0.4: icmp_seq= ttl= time=0.110 ms
bytes from 172.17.0.4: icmp_seq= ttl= time=0.165 ms --- 172.17.0.4 ping statistics ---
packets transmitted, received, % packet loss, time 2108ms
rtt min/avg/max/mdev = 0.110/0.136/0.165/0.022 ms
如果你想要解除上面ubuntu5的bridge网络连接:
userdeMacBook-Pro:~ user$ docker network disconnect bridge 9e11c1b9e90d