默认网络

当安装Docker时,会自动创建三个网络。可以使用 docker network ls 命令列出网络

  1. [root@centos-01 ~]# docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. cdda3ae8795a bridge bridge local
  4. ed7ffc7437dd host host local
  5. 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 的虚拟网桥设备

  1. [root@centos-01 ~]# ip addr
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever
  8. 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  9. link/ether 00:0c:29:50:75:ae brd ff:ff:ff:ff:ff:ff
  10. inet 192.168.126.143/24 brd 192.168.126.255 scope global noprefixroute ens33
  11. valid_lft forever preferred_lft forever
  12. inet6 2409:8900:2b86:13cc:a958:4c6e:c162:309d/64 scope global noprefixroute dynamic
  13. valid_lft 3569sec preferred_lft 3569sec
  14. inet6 fe80::1f3a:afc1:82f6:3f66/64 scope link noprefixroute
  15. valid_lft forever preferred_lft forever
  16. 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
  17. link/ether 02:42:cb:f1:35:ea brd ff:ff:ff:ff:ff:ff
  18. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  19. valid_lft forever preferred_lft forever

docker0 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法通过ip地址直接寻址的,需要通过其他方式来使外部网络可以访问容器,一般会通过访问宿主机ip结合容器的端口(端口映射)进行容器的访问

image.png

实现步骤

  • Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为 veth0veth1veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方
  • Docker Daemonveth0 附加到 Docker Daemon 创建的 docker0网桥上。保证宿主机的网络报文可以发往 veth0
  • Docker Daemonveth1 添加到 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
    1. valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
    1. valid_lft forever preferred_lft forever

2: ens33: 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: 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

  1. **2):创建容器并查看IP**
  2. ```bash
  3. [root@centos-01 ~]# docker run -d --name nginx nginx
  4. 8afe1080ba992614f96b6868dbbcab463e37c98f8d3fa729245d48c2e6a1e3fe
  5. [root@centos-01 ~]# docker ps -a
  6. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  7. 8afe1080ba99 nginx "/docker-entrypoint.…" 3 seconds ago Up 2 seconds 80/tcp nginx
  8. [root@centos-01 ~]# docker inspect nginx

image.png
查看IP发现其ip为 172.17.0.2 ,当容器桥接 docker0 后,会自动分配 ip 地址,之后的IP地址递增
3):查看网桥和端口连接

  1. [root@centos-01 ~]# brctl show
  2. bridge name bridge id STP enabled interfaces
  3. docker0 8000.0242cbf135ea no veth3a98010

一个新的网络接口 veth3a98010 被挂到了 docker0 上, veth3a98010 就是新创建容器的虚拟网卡
4):查看 **veth pair** 配置

  1. [root@centos-01 ~]# ip addr
  2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4. inet 127.0.0.1/8 scope host lo
  5. valid_lft forever preferred_lft forever
  6. inet6 ::1/128 scope host
  7. valid_lft forever preferred_lft forever
  8. 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  9. link/ether 00:0c:29:50:75:ae brd ff:ff:ff:ff:ff:ff
  10. inet 192.168.126.143/24 brd 192.168.126.255 scope global noprefixroute ens33
  11. valid_lft forever preferred_lft forever
  12. inet6 2409:8900:2b86:13cc:a958:4c6e:c162:309d/64 scope global noprefixroute dynamic
  13. valid_lft 3520sec preferred_lft 3520sec
  14. inet6 fe80::1f3a:afc1:82f6:3f66/64 scope link noprefixroute
  15. valid_lft forever preferred_lft forever
  16. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  17. link/ether 02:42:cb:f1:35:ea brd ff:ff:ff:ff:ff:ff
  18. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  19. valid_lft forever preferred_lft forever
  20. inet6 fe80::42:cbff:fef1:35ea/64 scope link
  21. valid_lft forever preferred_lft forever
  22. 21: veth3a98010@if20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
  23. link/ether 16:ea:7d:ca:a3:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  24. inet6 fe80::14ea:7dff:feca:a307/64 scope link
  25. valid_lft forever preferred_lft forever
  26. [root@centos-01 ~]# brctl show
  27. bridge name bridge id STP enabled interfaces
  28. docker0 8000.0242cbf135ea no veth3a98010
  29. [root@centos-01 ~]# docker exec -it nginx /bin/bash
  30. root@8afe1080ba99:/# cat /sys/class/net/eth0/iflink
  31. 21

veth 设备是成双成对出现的,一端是容器内部命名为eth0,一端是加入到网桥并命名的 vethxxx (通常命名为veth),它们组成了一个数据传输通道,一端进一端出,veth设备连接了两个网络设备并实现了数据通信;在bridge模式下,连在同一网桥上的容器可以相互通信(若出于安全考虑,也可以禁止它们之间通信,方法是在DOCKER_OPTS变量中设置–icc=false,这样只有使用–link才能使两个容器通信)

Host

如果启动容器时使用的是host模式,那么容器将不会获得一个独立的 Network Namespace(网络命名空间) ,而是和宿主机系统共用一个 Network Namespace 。这意味着容器不会虚拟出自己的网卡以及配置自己的ip等,而是使用宿主机的ip以及端口。不过在其他方面例如文件系统、进程列表等还是与之隔离的。使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行 NAT ,host最大的优势就是网络性能比较好,但是已经使用的端口就不能再用了,网络的隔离性不好。
image.png

介绍

  • 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

  1. 注意
  2. - 不需要添加 `-p` 参数,因为它使用的就是主机的IP和端口,添加 `-p` 参数后,反而会出现以下警告
  3. ` WARNING: Published ports are discarded when using host network mode`
  4. - 宿主机的ip路由转发功能一定要打开,否则所创建的容器无法联网
  5. `echo 1 > /proc/sys/net/ipv4/ip_forward`
  6. > host模式端口占用模式是你的容器占用你主机上当前所监听的端口(官网描述为publish)。比如这里nginx占用80端口,那么用host模式启动的时候,主机上的80端口会被nginx占用,这时其他的容器就不能再指定80端口,但可以指定其他端口,所以说一台主机上可以运行多个host模式的容器,只要彼此监听的端口不一样就行
  7. ```shell
  8. [root@centos-01 ~]# curl 192.168.126.143:80
  9. <!DOCTYPE html>
  10. <html>
  11. <head>
  12. <title>Welcome to nginx!</title>
  13. <style>
  14. body {
  15. width: 35em;
  16. margin: 0 auto;
  17. font-family: Tahoma, Verdana, Arial, sans-serif;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <h1>Welcome to nginx!</h1>
  23. <p>If you see this page, the nginx web server is successfully installed and
  24. working. Further configuration is required.</p>
  25. <p>For online documentation and support please refer to
  26. <a href="http://nginx.org/">nginx.org</a>.<br/>
  27. Commercial support is available at
  28. <a href="http://nginx.com/">nginx.com</a>.</p>
  29. <p><em>Thank you for using nginx.</em></p>
  30. </body>
  31. </html>

Container

Container模式Host模式 类似,指定新创建的容器和已经存在的一个容器共享一个 Network Namespace 。新建的容器不会创建自己的网卡等相关操作,而是和与指定的容器共享这些资源。除了网络方面,其文件系统、进程列表等都是隔离的。
image.png

注:它并没有改善容器与宿主机以外世界通信的情况(和桥接模式一样,不能连接宿主机以外的其他设备)

  1. [root@centos-01 ~]# docker run -d --name nginx --network=container:ba0eb1c89ab6b50 nginx

None

Docker容器拥有自己的 Network Namespace ,但不会对Docker容器进行任何的网络配置。这表明这个Docker容器没有网卡、IP、路由等信息。需要自己为Docker容器添加网卡、配置IP等。这种方式网络的隔离性最为彻底,即表明关闭了容器的网络功能,也无法访问这个容器。

  1. [root@centos-01 ~]# docker run -d --name nginx --network=none nginx

参考