Docker 容器和服务如此强大的原因之一是您可以将它们连接在一起,或者将它们连接到非 Docker 工作负载。
Docker容器和服务甚至不需要知道它们部署在Docker上,也不需要知道它们的同伴是否也是Docker的工作负载。
无论您的 Docker 主机运行 Linux、Windows 还是两者的混合,您都可以使用 Docker 以与平台无关的方式管理它们。
在网络方面,bridge网络是一种链路层设备,它在网段之间转发流量。bridge可以是在主机内核中运行的硬件设备或软件设备。
就Docker 而言,bridge网络使用软件bridge,它允许连接到同一bridge网络的容器进行通信,同时提供与未连接到该bridge网络的容器的隔离。Docker bridge驱动程序会自动在宿主机中安装规则,使不同bridge网络上的容器无法直接相互通信。
当你启动Docker时,一个默认的bridge网络(也称为bridge)会自动创建,新启动的容器会连接到它,除非另有说明。您还可以创建用户定义的自定义bridge网络。 用户自定义bridge网络优于默认的bridge网络。
规则:
1:默认bridge网络上的容器只能通过 IP 地址相互访问,除非您使用 –link 选项,该选项被视为旧版。在用户自定义bridge网络上,容器可以通过名称或别名相互解析。
2:所有没有指定–network的容器都连接到默认bridge网络
3:使用用户自定义的网络提供了一个范围网络,其中只有连接到该网络的容器才能进行通信。
4:可以使用 docker-compose 一起启动多个容器,并且 compose 文件可以定义共享变量。
常用命令列表
创建:docker network create network-name
删除:docker network rm network-name
连接:docker network connect network-name container-name
断开:docker network disconnect network-name container-name
帮助:docker network –help
查看当前网络列表
# % docker network ls
目前的话,我是用的laradock搭建的lnmp,所以会有三个laradock开头的网络,我们可以忽略。
除此以外我们还可以看到默认的bridge网络,以及host和none。后两者不是完全成熟的网络,而是用于启动一个直接连接到 Docker 守护进程主机的网络堆栈的容器,或者启动一个没有网络设备的容器。
案例1:默认bridge网络
我们先创建centos_1,centos_2 这两个容器
#% docker run -it –name centos_1 centos bash
Unable to find image ‘centos:latest’ locally
latest: Pulling from library/centos
a1d0c7532777: Pull complete
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
#% docker run -it –name centos_2 centos bash
# % docker container start centos_1
centos_1
# % docker container start centos_2
centos_2
我们看一下创建的两个容器是否启动成功
# % docker container ls
启动成功了。
我们再检查bridge网络连接了哪些容器
# % docker network inspect bridge
我们也可以看到centos1和centos2也是连接的默认bridge网络,并且它们的ip地址是172.17.0.2和172.17.0.3。
下面使用 docker attach 命令连接到 centos,attach就是在后台运行的意思。
zhoujun@MacBook-Pro laradock % docker attach centos_1
接下来我们看下IP地址
[root@5b2fcdb7aa53 /]# ip add show
接下来我们在centos_1进行ping命令
[root@5b2fcdb7aa53 /]# ping baidu.com
那我们ping一下centos_2看下,首先我们先ping name
[root@5b2fcdb7aa53 /]# ping centos_2
ping: centos_2: Name or service not known
[root@5b2fcdb7aa53 /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.164 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.180 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.191 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.144 ms
正好命中了第一条规则。接着我们把上面的两个容器删除掉。
# % docker container stop centos_1 centos_2
centos_1
centos_2
# % docker container rm centos_1 centos_2
centos_1
centos_2
那下面我们再来一个自定义bridge网络的案例
案例2:自定义brdige网络
本次我们将创建四个centos容器,分别是centos_1 centos_2 centos_3 centos4。centos_1 centos_2 centos_3加入自定义bridge,centos_3, centos_4连接到默认briage。
首先我们先创建一个自定义bridge
# % docker network create –driver bridge centos_net
910954230d9a4ed4322270dae55b74a27dcb170fd622b85b10ae17e84549abfb
# % docker network ls
我们从网络列表也能看到刚创建的bridge网络。
下面我们开始连接到centos_net
#% docker run -it –name centos_1 –network centos_net centos bash
#% docker run -it –name centos_2 –network centos_net centos bash
# % docker run -it –name centos_3 –network centos_net centos bash
#% docker run -it –name centos_4 centos bash
# % docker network connect bridge centos_3
下面我们看下centos_net和默认bridge有哪几个容器连接上了。
# % docker network inspect centos_net
# % docker network inspect bridge
按照我们上面的设计,效果图应该是这样
也就是centos1,centos_2,centos_3是能互相连接的。centos_4只能与centos_3互相连接。下面我们分别进入这四个容器看下效果。
登录centos_1:
# % docker container attach centos_1
[root@fe8b8ce09a94 /]# ping centos_2
PING centos_2 (172.21.0.3) 56(84) bytes of data.
64 bytes from centos_2.centos_net (172.21.0.3): icmp_seq=1 ttl=64 time=0.174 ms
64 bytes from centos_2.centos_net (172.21.0.3): icmp_seq=2 ttl=64 time=0.200 ms
[root@fe8b8ce09a94 /]# ping centos_3
PING centos_3 (172.21.0.4) 56(84) bytes of data.
64 bytes from centos_3.centos_net (172.21.0.4): icmp_seq=1 ttl=64 time=0.203 ms
64 bytes from centos_3.centos_net (172.21.0.4): icmp_seq=2 ttl=64 time=0.199 ms
[root@fe8b8ce09a94 /]# ping centos_4
ping: centos_4: Name or service not known
登录centos_2:
# % docker container attach centos_2
[root@61e26f164da7 /]# ping centos_1
PING centos_1 (172.21.0.2) 56(84) bytes of data.
64 bytes from centos_1.centos_net (172.21.0.2): icmp_seq=1 ttl=64 time=0.217 ms
64 bytes from centos_1.centos_net (172.21.0.2): icmp_seq=2 ttl=64 time=0.200 ms
[root@61e26f164da7 /]# ping centos_3
PING centos_3 (172.21.0.4) 56(84) bytes of data.
64 bytes from centos_3.centos_net (172.21.0.4): icmp_seq=1 ttl=64 time=0.149 ms
[root@61e26f164da7 /]# ping centos_4
ping: centos_4: Name or service not known
登录centos_3:
# % docker container attach centos_3
[root@9ff2e8501b63 /]# ping centos_1
PING centos_1 (172.21.0.2) 56(84) bytes of data.
64 bytes from centos_1.centos_net (172.21.0.2): icmp_seq=1 ttl=64 time=0.177 ms
64 bytes from centos_1.centos_net (172.21.0.2): icmp_seq=2 ttl=64 time=0.204 ms
[root@9ff2e8501b63 /]# ping centos_2
PING centos_2 (172.21.0.3) 56(84) bytes of data.
64 bytes from centos_2.centos_net (172.21.0.3): icmp_seq=1 ttl=64 time=0.079 m
[root@9ff2e8501b63 /]# ping centos_4
ping: centos_4: Name or service not known
按照上面的设计,centos_3是可以ping通cento_4呢,但为什么提示Name or service not known。原因出在规则1,也就是说默认bridge网络上的容器只能通过 IP 地址相互访问。那我们找到centos_4的ip地址是172.17.0.3。
[root@9ff2e8501b63 /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.157 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.142 ms
通过IP地址的形式终于成功了。
登录centos_4:
zhoujun@192 ~ % docker container attach centos_4
[root@d71708d9a615 /]# ping centos_3
bash: $’\345ping’: command not found
[root@d71708d9a615 /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.026 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.135 ms
至此,我们测试的效果跟上面的效果图一致。
端口映射
到此为止,我们知道桥接网络中的容器只能与位于相同网络中的容器进行通信。但是,可以使用端口映射(Port Mapping)来绕开这个限制。
桥接网络是基本的Docker网络类型,对于本地开发和小型应用来说也十分适用。桥接网络不可扩展,并且对外发布服务依赖于端口映射。
端口映射允许将某个容器端口映射到Docker主机端口上。对于配置中指定的Docker主机端口,任何发送到该端口的流量,都会被转发到容器。
下面我们就以nginx为例。
1:先创建一个bridge网络
# % docker network create nginx_net
46cd571fad3989702763680a2ec4f04a3863539f789e500379d70492f1a634e5
2:运行一个新的Web服务容器,并将容器80端口映射到Docker主机的8888端口。
# % docker container run -d –name web –network nginx_net –publish 8888:80 nginx
876090806aa8aa3383d79db4a8a3d15d1e331d3df9ae6e9488dad788d0d082e2
# % docker port web
80/tcp -> 0.0.0.0:8888
3:通过Web浏览器访问Docker主机8888端口,验证配置是否生效
外部系统现在可以通过Docker主机的TCP端口8888,来访问运行在bridge网络上的Nginx容器了。
端口映射工作原理大致如此,但这种方式比较笨重并且不能扩展。举个例子,在只有单一容器的情况下,它可以绑定到主机的任意端口。这意味着其他容器就不能再使用已经被Nginx容器占用的5000端口了。这也是单机桥接网络只适用于本地开发环境以及非常小的应用的原因。
参考资料
《深入浅出Docker》