1. 默认网络

当你安装了docker,自动创建了3个网络,可以使用docker network命令来查看

dd@ubuntu04:~$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
61848f3f9e62        bridge              bridge              local
6211ead1d40a        host                host                local
47771891e708        none                null                local

1.1 bridge网络

根据上篇所述,默认情况下,新建的docker会连接到docker0这个网桥上

dd@ubuntu04:~$ ip addr show docker0

3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 02:42:bc:71:fe:b6 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
dd@ubuntu04:~$ brctl show docker0

bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242bc71feb6	no		

启动并运行一个容器

dd@ubuntu04:~$ docker run -itd --name dd-test01 ubuntu:18.04 /bin/bash
ce65c0e400e0a7f6b6f10b62d3359ea0ac59abbb6e4ba8f7c938d420b27e65bf
dd@ubuntu04:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
ce65c0e400e0        ubuntu:18.04        "/bin/bash"         37 seconds ago      Up 33 seconds                           dd-test01

进入容器

dd@ubuntu04:~$ docker exec -it dd-tes01 /bin/bash

查看ip 信息

root@ce65c0e400e0:/# ifconfig

报错:

bash: ifconfig: command not found

解决:

root@ce65c0e400e0:/# apt-get update
root@ce65c0e400e0:/# apt-get install net-tools

查看ip

root@ce65c0e400e0:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 2008  bytes 18182532 (18.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1853  bytes 104451 (104.4 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

查看网关:

root@ce65c0e400e0:/# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

可以看到test1容器已经获取了一个地址172.17.0.2,和主机的docker0接口地址在同一网络,并将主机的docker0接口地址设置为了网关。

在物理主机上,查看网桥docker0,可以看到已经多了一个接口

dd@ubuntu04:~$ brctl show docker0
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242bc71feb6	no		veth891c3fa

Docker 容器默认使用 bridge 模式的网络特点如下:

  • 使用一个 linux bridge,默认为 docker0
  • 使用 veth 对,一头在容器的网络 namespace 中,一头在 docker0 上
  • 该模式下Docker Container不具有一个公有IP,因为宿主机的IP地址与vethpair的 IP地址不在同一个网段内
  • Docker采用 NAT 方式,将容器内部的服务监听的端口与宿主机的某一个端口port进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部
  • 外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port
  • NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
  • 容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过NAT建立通信

效果是这样的:
在这里插入图片描述

示意图如下:
在这里插入图片描述
在物理主机上查看iptables的nat表,可以看到在POSTROUTING链中做了地址伪装:MASQUERADE动作,这样容器就可以通过源地址转换NAT访问外部网络了。

dd@ubuntu04:~$ sudo iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 78 packets, 6004 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    4  1781 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 44 packets, 3501 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 430 packets, 32478 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 430 packets, 32478 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    9   553 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           

可以使用docker network inspect bridge命令来查看bridge网络情况:

dd@ubuntu04:~$  docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "61848f3f9e629985880ed98d0293d14b20169e31ef9ed25ffe165439c915042a",
        "Created": "2020-05-07T10:15:11.014764859Z",
        "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": {
            "ce65c0e400e0a7f6b6f10b62d3359ea0ac59abbb6e4ba8f7c938d420b27e65bf": {
                "Name": "dd-test01",
                "EndpointID": "14e910d3cc8fbae5820e2a5c1418bffe9d46434ba1688209113ca8323d8b5e3e",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "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",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

1.2 none网络模式

网络模式为 none,即不为Docker容器构造任何网络环境,不会为容器创建网络接口,一旦Docker容器采用了none网络模式,那么容器内部就只能使用loopback网络设备,不会再有其他的网络资源。Docker Container的none网络模式意味着不给该容器创建任何网络环境,容器只能使用127.0.0.1的本机网络。

启动一个容器,设为none网络

dd@ubuntu04:~$ docker run -itd --name dd-test02 --network none ubuntu:18.04 /bin/bash
7ae6efef02cfd25bd82c31c94322edfb34c007a741497c85f96e33cbe0cda1b1

进入容器,查看网络情况,发现由于none模式无法联网,导致ipconfig命令无法使用,正好可以复习下前面的命令,我们把bridge模式下的容器导出为image,再以此image创建none模式的container

dd@ubuntu04:~$ docker export ce65c0e400e0 > dd-ubuntu02.tar
dd@ubuntu04:~$ cat dd-ubuntu02.tar | docker import - dd/ubuntu:test
sha256:c332c9fe03b398405c72bc3214a86395853c20c969532074752487ac6d8cb232
dd@ubuntu04:~$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
dd/ubuntu           test                c332c9fe03b3        6 minutes ago       92.3MB
dd/centos           6.7                 c6519f975a25        12 hours ago        191MB
dd/centos           dev                 c6519f975a25        12 hours ago        191MB
dd/ubuntu           v2                  5b51178018cd        13 hours ago        137MB
dd/ubuntu           v1                  63cf4e1dfe43        13 hours ago        73.9MB
ubuntu              latest              1d622ef86b13        13 days ago         73.9MB
ubuntu              18.04               c3c304cb4f22        13 days ago         64.2MB
httpd               latest              b2c2ab6dcf2e        2 weeks ago         166MB
ubuntu              14.04               6e4f1fe62ff1        4 months ago        197MB
centos              6.7                 9f1de3c6ad53        13 months ago       191MB
ubuntu              15.10               9b9cb95443b5        3 years ago         137MB
training/webapp     latest              6fae60ef3446        4 years ago         349MB
ubuntu              13.10               7f020f7bf345        5 years ago         185MB

dd@ubuntu04:~$ docker run -itd --network none --name dd-test03 dd/ubuntu:test /bin/bash
2d85c15b3bd8a52c2c9974f4020aa4f4c3ed01d8c5d841fa52b58b44d658d112
dd@ubuntu04:~$ docker exec -it dd-test03 /bin/bash
root@2d85c15b3bd8:/# ifconfig

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@2d85c15b3bd8:/# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

root@2d85c15b3bd8:/# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters

1.3 host网络模式

Host模式并没有为容器创建一个隔离的网络环境。而之所以称之为host模式,是因为该模式下的Docker 容器会和host宿主机共享同一个网络namespace,故Docker Container可以和宿主机一样,使用宿主机的eth0,实现和外界的通信。换言之,Docker Container的IP地址即为宿主机 eth0的IP地址。
其特点包括:

  • 这种模式下的容器没有隔离的 network namespace
  • 容器的 IP 地址同 Docker host 的 IP 地址
  • 需要注意容器中服务的端口号不能与 Docker host 上已经使用的端口号相冲突
  • host 模式能够和其它模式共存

示意图:
在这里插入图片描述
例如,我们在ubuntu04 的机器上用 host 模式启动一个含有 web 应用的Docker容器,监听 tcp 80 端口。当我们在容器中执行任何类似 ifconfig 命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用192.168.31.204:80 即可,不用任何 NAT 转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

启动容器前,查看物理主机的httpd进程

root@2d85c15b3bd8:/# pgrep httpd
root@2d85c15b3bd8:/# 

启动一个容器

dd@ubuntu04:~$ docker run -itd --name dd-net-host --network host dd/ubuntu:test /bin/bash
a96b5b451de7d7df306ff4902f16afb8748fb4e0db808163ba07351088a945fc

进入容器,查看基本信息

dd@ubuntu04:~$ docker exec -it dd-nt-host /bin/bash
root@ubuntu04:/# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:0a:fd:54:16  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.31.204  netmask 255.255.255.0  broadcast 192.168.31.255
        inet6 fe80::20c:29ff:fed0:84b3  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:d0:84:b3  txqueuelen 1000  (Ethernet)
        RX packets 701  bytes 80060 (80.0 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 402  bytes 51006 (51.0 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 183  bytes 13887 (13.8 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 183  bytes 13887 (13.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@ubuntu04:/# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.31.2    0.0.0.0         UG    0      0        0 ens33
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.31.0    0.0.0.0         255.255.255.0   U     0      0        0 ens33

安装httpd服务,报错:

root@ubuntu04:/# apt-get install httpd
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Package httpd is a virtual package provided by:
  nginx-light 1.14.0-0ubuntu1.7
  nginx-full 1.14.0-0ubuntu1.7
  nginx-extras 1.14.0-0ubuntu1.7
  lighttpd 1.4.45-1ubuntu3.18.04
  nginx-core 1.14.0-0ubuntu1.7
  apache2 2.4.29-1ubuntu4.13
  yaws 2.0.4+dfsg-2
  webfs 1.21+ds1-12
  tntnet 2.2.1-3build1
  mini-httpd 1.23-1.2build1
  micro-httpd 20051212-15.1
  ebhttpd 1:1.0.dfsg.1-4.3build1
  aolserver4-daemon 4.5.1-18.1
  aolserver4-core 4.5.1-18.1
You should explicitly select one to install.

E: Package 'httpd' has no installation candidate

改装apache2

root@ubuntu04:/# apt-get install apache2
#启动apache2
root@ubuntu04:/# /etc/init.d/apache2 start
root@ubuntu04:/# echo "dd test docker host network" > /var/www/html/index.html
root@ubuntu04:/# exit

退出容器,查看apache2进程

dd@ubuntu04:~$ pgrep apache2
2807
2810
2811

访问主机的80端口,可以访问到容器中的网站服务:
在这里插入图片描述

1.4 container 模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
Container 网络模式是 Docker 中一种较为特别的网络的模式。这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此之外其他的容器存在网络隔离。

注意:因为此时两个容器要共享一个network namespace,因此需要注意端口冲突情况,否则第二个容器将无法被启动。

示意图:
在这里插入图片描述
运行一个容器:查看容器的IP

dd@ubuntu04:~$ docker run -itd --name dd-nt-container01  dd/ubuntu:test /bin/bash
b7de375ff9f423768a70f8eebe9bb93525fb12d8d99f47850da765ebacc6d005

dd@ubuntu04:~$ docker exec -it dd-nt-container01 /bin/bash
root@b7de375ff9f4:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 18  bytes 1452 (1.4 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@b7de375ff9f4:/# exit              

启动另外一个容器,使用dd-nt-container01容器的网络

dd@ubuntu04:~$ docker run -itd --name dd-nt-container02 --network container:dd-nt-container01  dd/ubuntu:test /bin/bash
cfe50ae62a35d5b1d0b9b36ce6180690e024ccd68a1d03925f6c96a199191f8f

进入容器dd-nt-container02,查看网络情况,可以看到两个容器地址信息相同,是共享的

dd@ubuntu04:~$ docker exec -it dd-nt-container02 /bin/bash
root@b7de375ff9f4:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 21  bytes 1662 (1.6 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

2. 用户定义网络(User-defined networks)

用户也可以自定义自己的网络。建议使用用户定义的桥接网络来控制容器之间彼此通信,并启用容器名称和IP地址的自动DNS解析,docker默认提供了用于创建这些网络的默认网络驱动程序,可以创建:

  • bridge network
  • overlay network
  • MACVLAN network
  • network plugin
  • remote network
    可以根据需要创建尽可能多的网络,并且可以在任何给定的时间将容器连接到0个或多个网络。此外,还可以在不重新启动容器的情况下连接和断开网络中的运行容器。当容器连接到多个网络时,它的外部连接是通过第一个非内部网络提供的。

2.2 新建网络(bridge networks)

下面先创建一个新的 Docker 网络。

dd@ubuntu04:~$ docker network create -d bridge dd-test-net
dd@ubuntu04:~$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
db7104d5ad7e        bridge              bridge              local
74a4ffa1c72e        dd-test-net         bridge              local
6211ead1d40a        host                host                local
47771891e708        none                null                local

参数说明:

  • -d:参数指定 Docker 网络类型,有 bridge、overlay。
  • 其中 overlay 网络类型用于 Swarm mode,在本节中你可以忽略它。

2.3 连接容器

运行一个容器并连接到新建的 dd-test-net 网络:

dd@ubuntu04:~$  docker run -itd --name test1 --network dd-test-net ubuntu /bin/bash

再运行一个容器并加入到 dd-test-net 网络:

dd@ubuntu04:~$  docker run -itd --name test2 --network dd-test-net ubuntu /bin/bash

查看容器

dd@ubuntu04:~$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
133b92b9a360        ubuntu              "/bin/bash"         2 minutes ago       Up 2 minutes                            test2
ba1dc600a19b        ubuntu              "/bin/bash"         2 minutes ago       Up 2 minutes                            test1
cfe50ae62a35        dd/ubuntu:test      "/bin/bash"         13 minutes ago      Up 13 minutes                           dd-nt-container02
b7de375ff9f4        dd/ubuntu:test      "/bin/bash"         15 minutes ago      Up 14 minutes                           dd-nt-container01
733e69a6a919        dd/ubuntu:test      "/bin/bash"         37 minutes ago      Up 37 minutes                           dd-nt-host

下面通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。
如果 test1、test2 容器内中无 ping 命令,则在容器内执行以下命令安装 ping

test1:

dd@ubuntu04:~$ docker exec -it test1 /bin/bash
root@ba1dc600a19b:/# ping 
bash: ping: command not found
root@ba1dc600a19b:/# apt-get update
root@ba1dc600a19b:/# apt install iputils-ping
root@ba1dc600a19b:/# ping test2
PING test2 (172.18.0.3) 56(84) bytes of data.
64 bytes from test2.dd-test-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.196 ms
64 bytes from test2.dd-test-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.094 ms
64 bytes from test2.dd-test-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.055 ms
64 bytes from test2.dd-test-net (172.18.0.3): icmp_seq=4 ttl=64 time=0.067 ms

test2:

dd@ubuntu04:~$ docker exec -it test2 /bin/bash
root@ba1dc600a19b:/# ping 
bash: ping: command not found
root@ba1dc600a19b:/# apt-get update
root@ba1dc600a19b:/# apt install iputils-ping
root@ba1dc600a19b:/# ping test1
PING test2 (172.18.0.3) 56(84) bytes of data.
64 bytes from test1.dd-test-net (172.18.0.2): icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from test1.dd-test-net (172.18.0.2): icmp_seq=2 ttl=64 time=0.080 ms
64 bytes from test1.dd-test-net (172.18.0.2): icmp_seq=3 ttl=64 time=0.061 ms
64 bytes from test1.dd-test-net (172.18.0.2): icmp_seq=4 ttl=64 time=0.128 ms

这样,test1 容器和 test2 容器建立了互联关系。

查看网络情况:

dd@ubuntu04:~$ docker network inspect dd-test-net
[
    {
        "Name": "dd-test-net",
        "Id": "74a4ffa1c72e8da7f19bf921a97f3c1ac8fd5c74dce3c386c67f21d68dce0470",
        "Created": "2020-05-07T15:17:21.854079137Z",
        "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": {
            "133b92b9a36053c7dd14003a2d1c2bf709b75ce7f01a46dba484f8118dcf5803": {
                "Name": "test2",
                "EndpointID": "743cc1fdbb4dd0edbcc5f8003bedc934c66cb563374373399f8b7ee5355b28f8",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            },
            "ba1dc600a19b428d23bfc3031a454bdd6641fd1be2335d79e555a31bb956ff45": {
                "Name": "test1",
                "EndpointID": "71f41de3865893a3ea300490f2899d4ad6013bb99d38a12a9085234a243cd12b",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

如果有多个容器之间需要互相连接,推荐使用 Docker Compose,后面会介绍
需要注意创建的网络中的容器必须在同一个HOST主机上,网络中的每个容器都可以立即与网络中的其他容器通信。然而,网络本身将容器与外部网络隔离开来。

在这里插入图片描述
在用户定义的网桥网络中,不支持linking。可以在这个网络中公开和发布容器端口,也就是expose and publish
在这里插入图片描述
如果你想在单一主机上运行一个相对小的网络,使用桥接网络是有效果的。
然而你想创建一个大网络,可以通过overlay 网络来实现。

3. 外部访问容器

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或 -p 参数来指定端口映射。
当使用–P(大写)标记时,Docker 会随机映射一个随机的端口到内部容器开放的网络端口。

注:-P使用时需要指定–expose选项或dockerfile中用expose指令容器要暴露的端口,指定需要对外提供服务的端口

从docker hub下载一个httpd镜像

dd@ubuntu04:~$ docker pull httpd
dd@ubuntu04:~$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
dd/ubuntu           test                c332c9fe03b3        2 hours ago         92.3MB
dd/centos           6.7                 c6519f975a25        14 hours ago        191MB
dd/centos           dev                 c6519f975a25        14 hours ago        191MB
dd/ubuntu           v2                  5b51178018cd        14 hours ago        137MB
dd/ubuntu           v1                  63cf4e1dfe43        15 hours ago        73.9MB
ubuntu              latest              1d622ef86b13        13 days ago         73.9MB
ubuntu              18.04               c3c304cb4f22        13 days ago         64.2MB
httpd               latest              b2c2ab6dcf2e        2 weeks ago         166MB
ubuntu              14.04               6e4f1fe62ff1        4 months ago        197MB
centos              6.7                 9f1de3c6ad53        13 months ago       191MB
ubuntu              15.10               9b9cb95443b5        3 years ago         137MB
training/webapp     latest              6fae60ef3446        4 years ago         349MB
ubuntu              13.10               7f020f7bf345        5 years ago         185MB

3.1 -P

使用这个下载的镜像启动一个容器:

dd@ubuntu04:~$ docker run -d -P --name dd-web-test01 httpd
dd@ubuntu04:~$ docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
d181fd5b896b        httpd               "httpd-foreground"   9 seconds ago       Up 7 seconds        0.0.0.0:32768->80/tcp   dd-web-test01
133b92b9a360        ubuntu              "/bin/bash"          30 minutes ago      Up 30 minutes                               test2
ba1dc600a19b        ubuntu              "/bin/bash"          30 minutes ago      Up 30 minutes                               test1
cfe50ae62a35        dd/ubuntu:test      "/bin/bash"          41 minutes ago      Up 41 minutes                               dd-nt-container02
b7de375ff9f4        dd/ubuntu:test      "/bin/bash"          42 minutes ago      Up 42 minutes                               dd-nt-container01
733e69a6a919        dd/ubuntu:test      "/bin/bash"          About an hour ago   Up About an hour                            dd-nt-host

可以看到容器的80端口被随机映射到主机的32768端口
访问主机IP地址的32768端口,就可以访问到容器的httpd服务
在这里插入图片描述

3.2 -p

-p(小写)则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有ip:hostPort:containerPort | ip::containerPort |
hostPort:containerPort

3.2.1 hostPort:containerPort

注意:

  • 容器有自己的内部网络和 ip 地址(使用 docker inspect 可以获取所有的变量。)
  • -p 标记可以多次使用来绑定多个端口
dd@ubuntu04:~$ docker run -d -p 8000:80 --name dd-web-test02 httpd
18b2ff2e1448aa2af0868fb3671f2ea0247229b1f74b5aaecd42f3eaa3dcf31c
dd@ubuntu04:~$ docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
18b2ff2e1448        httpd               "httpd-foreground"   11 seconds ago      Up 10 seconds       0.0.0.0:8000->80/tcp    dd-web-test02
d181fd5b896b        httpd               "httpd-foreground"   6 minutes ago       Up 6 minutes        0.0.0.0:32768->80/tcp   dd-web-test01
133b92b9a360        ubuntu              "/bin/bash"          36 minutes ago      Up 36 minutes                               test2
ba1dc600a19b        ubuntu              "/bin/bash"          37 minutes ago      Up 37 minutes                               test1
cfe50ae62a35        dd/ubuntu:test      "/bin/bash"          47 minutes ago      Up 47 minutes                               dd-nt-container02
b7de375ff9f4        dd/ubuntu:test      "/bin/bash"          49 minutes ago      Up 49 minutes                               dd-nt-container01
733e69a6a919        dd/ubuntu:test      "/bin/bash"          About an hour ago   Up About an hour                            dd-nt-host

可以看到主机的8000端口已经和容器dd-web-test002的80端口做了映射
访问主机的8000端口
在这里插入图片描述

3.2.2 ip:hostPort:containerPort

映射到指定地址的指定端口
可以使用 ip:hostPort:containerPort 格式,指定映射使用一个特定地址,比如宿主机网卡
配置的一个地址192.168.31.204

dd@ubuntu04:~$ docker run -d -p 192.168.31.204:18000:80 --name dd-web-test03 httpd
a6f4f1fcf8e535c4c6c6150a44282ff6c3913f42fcaaf117dc56e4c5c2dbdb58
dd@ubuntu04:~$ docker ps 
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                          NAMES
a6f4f1fcf8e5        httpd               "httpd-foreground"   39 seconds ago      Up 38 seconds       192.168.31.204:18000->80/tcp   dd-web-test03
18b2ff2e1448        httpd               "httpd-foreground"   7 minutes ago       Up 7 minutes        0.0.0.0:8000->80/tcp           dd-web-test02
d181fd5b896b        httpd               "httpd-foreground"   13 minutes ago      Up 13 minutes       0.0.0.0:32768->80/tcp          dd-web-test01
133b92b9a360        ubuntu              "/bin/bash"          43 minutes ago      Up 43 minutes                                      test2
ba1dc600a19b        ubuntu              "/bin/bash"          44 minutes ago      Up 44 minutes                                      test1
cfe50ae62a35        dd/ubuntu:test      "/bin/bash"          54 minutes ago      Up 54 minutes                                      dd-nt-container02
b7de375ff9f4        dd/ubuntu:test      "/bin/bash"          56 minutes ago      Up 56 minutes                                      dd-nt-container01
733e69a6a919        dd/ubuntu:test      "/bin/bash"          About an hour ago   Up About an hour                                   dd-nt-host

3.2.3 ip::containerPort

使用 ip::containerPort 绑定192.168.31.204的任意端口到容器的80端口,本地主机会自动分配一个口。这里就不再掩饰

注:还可以使用 udp 标记来指定 udp 端口

dd@ubuntu04:~$ docker run -d -p 192.168.31.204::80/udp --name dd-web-test04 httpd
df4d8a3e3ac16d4e5474fe110fe340ec2edc4f0d8dd997404ed81181dc326a70
dd@ubuntu04:~$ docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                                  NAMES
df4d8a3e3ac1        httpd               "httpd-foreground"   7 seconds ago       Up 6 seconds        80/tcp, 192.168.31.204:32768->80/udp   dd-web-test04
a6f4f1fcf8e5        httpd               "httpd-foreground"   3 minutes ago       Up 3 minutes        192.168.31.204:18000->80/tcp           dd-web-test03
18b2ff2e1448        httpd               "httpd-foreground"   10 minutes ago      Up 10 minutes       0.0.0.0:8000->80/tcp                   dd-web-test02
d181fd5b896b        httpd               "httpd-foreground"   16 minutes ago      Up 16 minutes       0.0.0.0:32768->80/tcp                  dd-web-test01
133b92b9a360        ubuntu              "/bin/bash"          46 minutes ago      Up 46 minutes                                              test2
ba1dc600a19b        ubuntu              "/bin/bash"          47 minutes ago      Up 47 minutes                                              test1
cfe50ae62a35        dd/ubuntu:test      "/bin/bash"          57 minutes ago      Up 57 minutes                                              dd-nt-container02
b7de375ff9f4        dd/ubuntu:test      "/bin/bash"          59 minutes ago      Up 59 minutes                                              dd-nt-container01
733e69a6a919        dd/ubuntu:test      "/bin/bash"          About an hour ago   Up About an hour                                           dd-nt-host

查看映射端口配置
使用 docker port 来查看当前映射的端口配置,也可以查看到绑定的地址

dd@ubuntu04:~$ docker port dd-web-test04
80/udp -> 192.168.31.204:32768

3.3 端口映射与iptables

docker端口映射实质上是在iptables 的nat表中添加了DNAT规则

dd@ubuntu04:~$ sudo iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   27  1693 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 6 packets, 441 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 6 packets, 441 bytes)
 pkts bytes target     prot opt in     out     source               destination         
   14   866 MASQUERADE  all  --  *      !br-74a4ffa1c72e  172.18.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.3           172.17.0.3           tcp dpt:80
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.4           172.17.0.4           tcp dpt:80
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.5           172.17.0.5           tcp dpt:80
    0     0 MASQUERADE  udp  --  *      *       172.17.0.6           172.17.0.6           udp dpt:80

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     all  --  br-74a4ffa1c72e *       0.0.0.0/0            0.0.0.0/0           
    0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
    4   240 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:32768 to:172.17.0.3:80
    2   120 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8000 to:172.17.0.4:80
    0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            192.168.31.204       tcp dpt:18000 to:172.17.0.5:80
    0     0 DNAT       udp  --  !docker0 *       0.0.0.0/0            192.168.31.204       udp dpt:32768 to:172.17.0.6:80

4. 参考文献

[1] docker 网络配置
[2] Docker系列之七:Docker网络
[3] Docker基础 :网络配置详解
[4] Docker 学习 | 第六篇:容器网络配置
[5] Docker的网络配置
[6] 使用 Docker 容器网络
[7] docker 之网络配置
[8] Docker网络详解
[9] docker网络模型之—Container模式
[10] Ubuntu下apache2启动、停止、重启、配置
[11] Ubuntu16.04安装httpd
[12] Ubuntu下解决ifconfig command not found的办法

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐