Docker 中的网络模式早先是 3 种,后来又加了 1 种,一共是 4 种。这里,我们只涉及、介绍使用其中 2 种网络模式:bridge 模式和 host 模式。
- bridge 是驱动( Driver )类型为 bridge 的默认网络;
- host 是驱动( Driver )类型为 host 的默认网络。
不同的网络模式的背后,存在一个驱动( Driver )的概念。
你可以通过下述命令查看 Docker 当前的网络情况:
[root@localhost ~]#docker network ls
如果愿意,你可以任意创建驱动( Driver )类型为 bridge 或 host ( 以及其它 2 种类型 )的网络。
一、bridge 网络
提示:这种模式下,容器和宿主机的地位是平等的
在驱动类型是 bridge 的网络( 默认网络为 bridge )中,容器和宿主机都连接到了一个叫作「网桥」的东西上,这正是「bridge 网络」这个称呼的由来。
说明:
这里涉及到的『网桥』的概念其实和我们使用 docker 并没有多大的关系,我们后续的 docker 的命令的使用中不会直接面对这个概念,所以,我们不过多地展开了。
这里,大家对它有一个基本的认识就足够了:正因为设备( 多个容器和宿主机 )连上了同一个网桥,所以,它们才在一个“局域网”中。也正因为如此,它们的( 虚拟 )IP 的前半部分一定是一样的,即,它们在同一个网段中。
这种模式下,每一个容器都有专属于自己的 IP 。例如,172.23.0.3
。
你可以通过以下命令查看某个容器的 IP 地址:
# 查看指定容器的 IP
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名
示例:查看tomcat1容器在docker中的ip地址
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' tomcat1
你也通过下面的命令查看所有容器的 IP 地址:
# 查看所有容器的 IP
docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq)
需要注意的是,宿主机一定是在所有的虚拟网络中,都有它的「位置」有点就“九省通衢”的感觉。因此,宿主机每「多加入」一个网络,它就会「多」出来一个虚拟 IP 。你可以通过如下命令查看你的宿主机所具有的所有的 IP( 包括了回环IP、物理网络 IP 和虚拟网络 IP )
a、默认的 bridge 网络
你可以通过 docker network ls
来查看网络信息,其中有一个名为 bridge
的 bridge 模式网络。
默认情况下,当你使用 docker run 命令时去创建并启动一个容器时,该容器的网络模式就是 bridge 模式。前提是你在 docker run 中没有使用下面讲到的 --llink 。
在这种情况下,docker 会见这个新创建的容器添加到名为 bridge 的网络中。你可以通过如下命令查看 brige 网路中有哪些容器,以及它们的 IP :
docker network inspect --format '{{json .Containers}}' bridge
b、自建 bridge 网络
你可以使用如下命令自建 bridge 类型的网络:
语法:
docker network create --driver bridge <网络名>
示例:
# docker network create -d bridge hello
接下来再使用 docker run 创建并启动容器时多使用一个 --network <网络名>
的选项,将容器添加到指定局域网中。例如:
docker run -d --rm --net hello --name mysql-3306 -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_ROOT_HOST=% \
mysql:8.0.16
docker run -d --rm --net hello --name mysql-3307 -p 3307:3306 \
-e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_ROOT_HOST=% \
mysql:8.0.16
使用之前的命令,你会发现它们仨都在 hello 局域网中。
c、使用 bridge 网络
当多个容器在同一个 bridge 类型的局域网中( 例如上例的 hello 局域网 )时,在 A 容器中,可以使用 B 容器的容器名替代 B 容器的 IP 地址!
-
进入上例的 mysql-3306 容器:
docker exec -it mysql-3306 /bin/bash
-
第 2 步:在 mysql-3306 中,用 mysql 的命令行客户端去连 mysql-3307
mysql -h mysql-3307 -u root -p123456
注意:这里 -h
的后面本应该出现 mysql-3307 服务器的 IP 地址的,现在这里出现的是它的名字。
-
第 3 步:创建名为 woniu_db的 database 作为证明,然后退出。
mysql> create database woniu_db;
-
第 4 步:分别进入 mysql-3306 和 mysql-3307,分别用 mysql 命令行客户端连接自己,验证一下,scott 数据库在哪里?
d、–link 选项
前一章说明并验证过:在同一个 bridge 类型的网络中,两个容器可以直接用对方的容器名来替代本该使用 IP 的地方。
但是 bridge
网络例外。多个容器都位与 bridge 网络中,按理说本该符合上述规则,但是这就是 bridge 网络的特殊之处。
你同样可以使用 mysql-3306 和 mysql-3307 来做验证,你在 mysql-3307 中使用 -h mysql-3306
来连接 mysql-3306 你会看到如下错误信息:
ERROR 2005 (HY000): Unknown MySQL server host 'mysql-3306' (0)
想要在 bridge
网络中实现类似效果,必须多使用 --link
选项。从上帝视角看,当 A 容器( 未来 )要去使用 B 容器的名字去连接 B 时,那么你在创建并启动 A 容器的 docker run 命令中要多使用 --link <B容器名>
才行。例如:
docker run -d --name mysql-3306 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_ROOT_HOST=% mysql:8.0
docker run -d --name mysql-3307 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_ROOT_HOST=% --link mysql-3306 mysql:8.0
再验证一次,这次就可以了。
2、host 网络
提示:这种模式下,容器相当于是宿主机中的一个进程,而「不是一个独立的机器」。
在 host 模式中,虚拟机( 即,容器 ) 没有自己的 IP ,它用到的是宿主机的 IP( 和端口 ),这种情况下,各个虚拟机( 即,容器 )谁是谁,主要靠它占用的是宿主机的哪个端口来分辨。
host 网络的特点在于,容器中所运行的程序必然会占用宿主机的对应端口。即,mysql 容器必然占用宿主机的 3306 端口;redis 容器必然占用宿主机的 6379 端口;ngxin 容器必然占用 80 端口;… 。所以,host 网络模式创建并运行的容器,不需要 -p
来做端口映射。例如:
docker run -d --rm --name=mysql-3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_ROOT_HOST=% \
-v /docker/mysql/3306/data:/var/lib/mysql \
--net host \
mysql:8.0
如果你使用之前查看容器 IP 的命令来查看 mysql-3306 的 IP ,你会发现它没有自己的 IP 。
host 网络最大的优点就是理论上速度快( 因为,没有网桥分发数据这个环节 ),它的性能要好于 bridge 类型的网络。但是付出的代价是:因为无法指定端口映射,因此在同一个宿主机上只能其一个特定类型的服务。
例如,在 host 模式下,你无法启动 2 个 mysql 容器。因为它俩都需要宿主机的 3306 端口。但宿主机 3306 端口只有一个,因此,只有第一个 mysql 容器能启动成功。