默认网络
当安装Docker时,会自动创建三个网络。可以使用 docker network ls
命令列出网络
[root@centos-01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
cdda3ae8795a bridge bridge local
ed7ffc7437dd host host local
fa66bc1a17f4 none null local
四种网络模式
在使用 docker run
创建Docker容器时,可以用 --network
选项指定容器的网络模式,Docker有以下4种网络模式:
--net=host
:容器和宿主机共享Network namespace
--net=none
:容器有独立的Network namespace
,但并没有对其进行任何网络设置,如分配veth pair
和网桥连接,配置IP等--net=bridge
:默认设置--net=container:name_Or_id
:容器和另外一个容器共享Network namespace
Bridge
该模式是在启动docker服务后默认的网络模式,当 Docker 启动时,Docker使用Linux桥接(参考《Linux虚拟网络技术》),在宿主机虚拟一个Docker容器网桥**docker0**
,Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP
,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP
当创建一个 Docker 容器的时候,同时会创建一个 veth pair
接口(当数据包发送到一个接口时,另外一个接口也可以接收相同的数据包)。这对接口一端在容器内,即 eth0
;另一端在本地并被挂载到 docker0
网桥,名称以 veth
开头。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker 就创建了在主机和所有容器之间的一个虚拟共享网络。
在安装和启动docker服务之后即可查看到这个 docker0
的虚拟网桥设备
[root@centos-01 ~]# ip addr
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:50:75:ae brd ff:ff:ff:ff:ff:ff
inet 192.168.126.143/24 brd 192.168.126.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 2409:8900:2b86:13cc:a958:4c6e:c162:309d/64 scope global noprefixroute dynamic
valid_lft 3569sec preferred_lft 3569sec
inet6 fe80::1f3a:afc1:82f6:3f66/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:cb:f1:35:ea brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
docker0 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法通过ip地址直接寻址的,需要通过其他方式来使外部网络可以访问容器,一般会通过访问宿主机ip结合容器的端口(端口映射)进行容器的访问
实现步骤
Docker Daemon
利用veth pair
技术,在宿主机上创建两个虚拟网络接口设备,假设为veth0
和veth1
。veth pair
技术的特性可以保证无论哪一个veth
接收到网络报文,都会将报文传输给另一方Docker Daemon
将veth0
附加到 Docker Daemon 创建的 docker0网桥上。保证宿主机的网络报文可以发往veth0
Docker Daemon
将veth1
添加到 Docker Container 所属的namespace
下,并被改名为eth0
。保证宿主机的网络报文若发往veth0
则立即会被eth0
接收,实现宿主机到Docker Container网络的联通;同时也保证容器单独使用eth0
,实现容器网络环境的隔离
缺陷
- 该模式下容器不具有一个
公有IP
,就是说和宿主机的eth0
不处于同一个网段。导致的结果是在宿主机以外不能直接和容器进行通信 - 虽然
NAT模式
经过中间处理实现了这一点,但是NAT模式
仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器内部服务的访问者需要使用服务发现获知服务的外部端口等 - 另外
NAT模式
由于是在三层网络上的实现手段,所以肯定会影响网络传输效率测试
1):查看本机网络 ```bash [root@centos-01 ~]# ip addr 1: lo: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
inet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
valid_lft forever preferred_lft forever
2: ens33:
3: docker0:
**2):创建容器并查看IP**
```bash
[root@centos-01 ~]# docker run -d --name nginx nginx
8afe1080ba992614f96b6868dbbcab463e37c98f8d3fa729245d48c2e6a1e3fe
[root@centos-01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8afe1080ba99 nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 80/tcp nginx
[root@centos-01 ~]# docker inspect nginx
查看IP发现其ip为 172.17.0.2
,当容器桥接 docker0
后,会自动分配 ip
地址,之后的IP地址递增
3):查看网桥和端口连接
[root@centos-01 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242cbf135ea no veth3a98010
一个新的网络接口 veth3a98010
被挂到了 docker0
上, veth3a98010
就是新创建容器的虚拟网卡
4):查看 **veth pair**
配置
[root@centos-01 ~]# ip addr
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:50:75:ae brd ff:ff:ff:ff:ff:ff
inet 192.168.126.143/24 brd 192.168.126.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 2409:8900:2b86:13cc:a958:4c6e:c162:309d/64 scope global noprefixroute dynamic
valid_lft 3520sec preferred_lft 3520sec
inet6 fe80::1f3a:afc1:82f6:3f66/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:cb:f1:35:ea brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:cbff:fef1:35ea/64 scope link
valid_lft forever preferred_lft forever
21: veth3a98010@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 16:ea:7d:ca:a3:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::14ea:7dff:feca:a307/64 scope link
valid_lft forever preferred_lft forever
[root@centos-01 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242cbf135ea no veth3a98010
[root@centos-01 ~]# docker exec -it nginx /bin/bash
root@8afe1080ba99:/# cat /sys/class/net/eth0/iflink
21
注:
veth
设备是成双成对出现的,一端是容器内部命名为eth0,一端是加入到网桥并命名的vethxxx
(通常命名为veth),它们组成了一个数据传输通道,一端进一端出,veth设备连接了两个网络设备并实现了数据通信;在bridge模式下,连在同一网桥上的容器可以相互通信(若出于安全考虑,也可以禁止它们之间通信,方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通信)
Host
如果启动容器时使用的是host模式,那么容器将不会获得一个独立的 Network Namespace(网络命名空间)
,而是和宿主机系统共用一个 Network Namespace
。这意味着容器不会虚拟出自己的网卡以及配置自己的ip等,而是使用宿主机的ip以及端口。不过在其他方面例如文件系统、进程列表等还是与之隔离的。使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行 NAT
,host最大的优势就是网络性能比较好,但是已经使用的端口就不能再用了,网络的隔离性不好。
介绍
- host网络模式需要在容器创建时指定
--network=host
- host 模式可以直接使用宿主机的IP地址与外界进行通信,若宿主机的
eth0
是一个公有 IP,那么容器也拥有这个公有IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行NAT
转换 - host模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性
缺陷
- 容器网络环境隔离性的弱化。即容器不再拥有隔离、独立的网络栈
- 使用 host 模式的容器虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用
- 容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以
bridge
网络模式容器的端口映射测试
```shell [root@centos-01 ~]# docker run -d —network=host —name nginx nginx ba0eb1c89ab6b505619db9b6789074db397a9f729ce18aeb82543986971b83d1
[root@centos-01 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ba0eb1c89ab6 nginx “/docker-entrypoint.…” 3 seconds ago Up 2 seconds nginx
注意
- 不需要添加 `-p` 参数,因为它使用的就是主机的IP和端口,添加 `-p` 参数后,反而会出现以下警告
` WARNING: Published ports are discarded when using host network mode`
- 宿主机的ip路由转发功能一定要打开,否则所创建的容器无法联网
`echo 1 > /proc/sys/net/ipv4/ip_forward`
> host模式端口占用模式是你的容器占用你主机上当前所监听的端口(官网描述为publish)。比如这里nginx占用80端口,那么用host模式启动的时候,主机上的80端口会被nginx占用,这时其他的容器就不能再指定80端口,但可以指定其他端口,所以说一台主机上可以运行多个host模式的容器,只要彼此监听的端口不一样就行
```shell
[root@centos-01 ~]# curl 192.168.126.143:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Container
Container模式
与 Host模式
类似,指定新创建的容器和已经存在的一个容器共享一个 Network Namespace
。新建的容器不会创建自己的网卡等相关操作,而是和与指定的容器共享这些资源。除了网络方面,其文件系统、进程列表等都是隔离的。
注:它并没有改善容器与宿主机以外世界通信的情况(和桥接模式一样,不能连接宿主机以外的其他设备)
[root@centos-01 ~]# docker run -d --name nginx --network=container:ba0eb1c89ab6b50 nginx
None
Docker容器拥有自己的 Network Namespace
,但不会对Docker容器进行任何的网络配置。这表明这个Docker容器没有网卡、IP、路由等信息。需要自己为Docker容器添加网卡、配置IP等。这种方式网络的隔离性最为彻底,即表明关闭了容器的网络功能,也无法访问这个容器。
[root@centos-01 ~]# docker run -d --name nginx --network=none nginx