Docker 网络基本概念
在之前讲 Redis 集群搭建的时候,我们用过一个选项 --net host
,现在就来讲讲该选项,以及 Docker 的网络。
docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
网络情况
我们先停止 Docker:systemctl stop docker
在不启动 Docker 的情况下,网络情况是这样的:
$ ifconfig
enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.2.242 netmask 255.255.255.0 broadcast 192.168.2.255
inet6 fe80::3c89:876e:2930:5286 prefixlen 64 scopeid 0x20<link>
ether 08:00:27:74:1d:cd txqueuelen 1000 (Ethernet)
RX packets 90493 bytes 13330101 (12.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 38633 bytes 3330369 (3.1 MiB)
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 6230364 bytes 7704637318 (7.1 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 6230364 bytes 7704637318 (7.1 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:06:12:45 txqueuelen 1000 (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
第一个 enp0s8,有一个 ip 地址 192.168.2.242,就是我们宿主机的地址
第二个 lo,就是 localhost 的简写,指本地回环链路;
第三个:virbr0,用的较少,了解即可。在虚拟机里,安装一个 Centos 的过程中,如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的 virbr0 网卡(virbr0 网卡还有一个固定的默认 IP 地址 192.168.122.1),是做虚拟机网桥的使用的,其作用是为连接其上的虚机网卡提供 NAT 访问外网的功能。
之前学习 Linux 安装,勾选安装系统的时候附带了 libvirt 服务才会生成的一个东西,如果不需要可以直接将 libvirtd 服务卸载:yum remove libvirt-libs.x86_64
docker 启动后,多了一个 docker0 的虚拟网桥:
$ ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:c0ff:fe81:167e prefixlen 64 scopeid 0x20<link>
ether 02:42:c0:81:16:7e txqueuelen 0 (Ethernet)
RX packets 57719 bytes 2948857 (2.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 60032 bytes 75842649 (72.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
容器与容器之间、容器和宿主机之间,就是通过该虚拟网桥来通信的。
查看 docker 网络模式,这是安装 Docker 后,默认创建的:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5bd056a8204a bridge bridge local
553d2c47bcaa host host local
1ddfe19eb462 none null local
我们主要掌握前 2 个,第 3 个 none 很少用到。
我们看看文档:
$ docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
可以创建一个网络:
$ docker network create aa_network
9eeb4fd0bf15a59d77bdba7e40594eb30ddd2c2c2ad66df706608a939cd2d193
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
9eeb4fd0bf15 aa_network bridge local
5bd056a8204a bridge bridge local
553d2c47bcaa host host local
1ddfe19eb462 none null local
NAME 为 bridge 的网络,是桥接模式;NAME 为 host 的是主机模式
查看网络源数据:docker network inspect XXX网络名字
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "5bd056a8204a81086acd846de2d0791373671f14a5f6880ebcbf7f4ddceb92cb",
"Created": "2023-09-10T12:10:26.138357898+08:00",
"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": {},
"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": {}
}
]
Docker 的网络能解决什么问题:
- 容器间的互联和通信以及端口映射
- 容器 IP 变动时,可以通过服务名直接网络通信而不受到影响
访问一个容器,比较关键的一点是在不在同一网段。目前我们是在单机运行 Docker,所以这个问题不明显;
在工作中,则设计到多个 Docker,他们之间的网络管理和容器调用的规划,就得用到 Docker 网络的问题了
网络模式
网络模式 | 简介 |
---|---|
bridge | 为每一个容器分配、设置 IP 等,并将容器连接到一个 docker0。虚拟网桥,默认是该模式 |
host | 容器将不会虚拟出自己的网课,配置自己的 IP 等,而是使用宿主机的 IP 和端口 |
none | 容器有独立的 Network namespace,但并没有对其进行任何网络设置, 如分配 veth pair 和网桥连接,IP 等 |
container | 新创建的容器不会创建自己的网卡和配置自己的 IP, 而是和一个指定的容器共享 IP、端口范围等 |
- bridge 模式:使用–network bridge 指定,默认使用 docker0。默认模式,最常见的模式
- host 模式:使用–network host 指定
- none 模式:使用–network none 指定,几乎不用
- container 模式:使用–network container:NAME 或者容器 ID 指定
接下来我们通过一个实例,来理解为什么我们要学习这个 Docker 的网络知识
容器实例内默认网络 IP 生产规则
先启动两个 ubuntu 容器实例:
$ docker run -it --name u1 ubuntu
$ docker run -it --name u2 ubuntu
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3e1c46b6b32e ubuntu "bash" 8 seconds ago Up 7 seconds u2
64fecffbfaca ubuntu "bash" 26 seconds ago Up 25 seconds u1
接下来查看下容器内的信息:docker inspect u1
,最后面有网络的信息:
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "5bd056a8204a81086acd846de2d0791373671f14a5f6880ebcbf7f4ddceb92cb",
"EndpointID": "9b0b1229700e53ea0651dd347d599d3873fa6f00ad92e255c72c2c17fabc87e8",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
可以看到目前是桥接模式,网关是 172.17.0.1,容器本身的 IP 是 172.17.0.2
u2 的信息:
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "5bd056a8204a81086acd846de2d0791373671f14a5f6880ebcbf7f4ddceb92cb",
"EndpointID": "3acf96d0214c8bb088e615e5e0544f19527e7da4fe8dd2cf57dee9f4f72c8ef0",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
如果我们删除 u2 实例,再启动一个新的 u3,并查看其休息:
$ docker rm -f u2
$ docker run -it --name u3 ubuntu
$ docker inspect u3
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "5bd056a8204a81086acd846de2d0791373671f14a5f6880ebcbf7f4ddceb92cb",
"EndpointID": "371217a338a6787dd444ebd315fe5fee14b6346d2dd90601bcc49a29b7ecdfda",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
可以看到 u3 的 IP,和之前 u2 的一样。如果我们想要 u2 的服务,结果 u2 被删除了,请求发到 u3 了,那么可能就会出错。
结论:docker 容器内部的 ip 是有可能会发生改变的。
为此,有必要自己做一些网络设计,例如创建一个新的网络模式,让部分容器在该网络模式下运行。
bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为 docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。示意图:
说明:
- Docker 使用 Linux 桥接,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个容器时会根据 Docker 网桥的网段分配给容器一个 IP 地址,称为 Container-IP,同时 Docker 网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信。
- docker run 的时候,没有指定 network 的话默认使用的网桥模式就是 bridge,使用的就是 docker0。在宿主机 ifconfig,就可以看到 docker0 和自己 create 的 network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo 代表 127.0.0.1,即 localhost,inet addr 用来表示网卡的 IP 地址
- 网桥 docker0 创建一对对等虚拟设备接口一个叫 veth,另一个叫 eth0,成对匹配。
- 整个宿主机的网桥模式都是 docker0,类似一个交换机有一堆接口,每个接口叫 veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫 veth pair);
- 每个容器实例内部也有一块网卡,每个接口叫 eth0;
- docker0 上面的每个 veth 匹配某个容器实例内部的 eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的 ip,此时两个容器的网络是互通的。
接下来我们两两匹配验证,启动两个 Tomcat:
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
然后我们可以用 ip addr 命令查看,在下方多了两个 veth 的:
61: veth6ddaa35@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether e6:d2:ee:03:d7:7e brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::e4d2:eeff:fe03:d77e/64 scope link
valid_lft forever preferred_lft forever
63: veth6b10f89@if62: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether fa:f7:44:71:39:65 brd ff:ff:ff:ff:ff:ff link-netnsid 3
inet6 fe80::f8f7:44ff:fe71:3965/64 scope link
valid_lft forever preferred_lft forever
进入到容器内部,可以看到有 eth0 的:
$ docker exec -it tomcat81 bash
$ 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
60: eth0@if61: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以看到 eho0 和 veth 是一一配对的,
接下来介绍下 host 模式。
host
host,主机模式,直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行 NAT 转换。
容器将不会获得一个独立的 Network Namespace, 而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的 IP 和端口。示意图:
再启动一个 Tomcat:可以看到有一个警告,不太推荐该种模式
$ docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
WARNING: Published ports are discarded when using host network mode
09a334d59bc97365d886911be278ebcd9e4dff637dcda97a6687fe3e9b1d2335
为什么有警告?docker 启动时指定–network=host 或-net=host,如果还指定了-p 映射端口,那这个时候就会有此警告,并且通过-p 设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
解决的办法就是使用 docker 的其他网络模式,例如–network=bridge;或者不用-p 选项,或忽略警告
此时我们用 docker inspect tomcat83
查看信息:没有网关和 IP 地址。
"Networks": {
"host": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "553d2c47bcaad9d82904e56225e6afae3d5a23379822c9d96ac74170041aad79",
"EndpointID": "1946b0286e008731cb65b6a30f074d6995dc08936126029bb76ea4665dd3d446",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
进入容器内部看:几乎和宿主机的一样
$ docker exec -it tomcat83 bash
$ 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: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:a4:2c:88 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic enp0s3
valid_lft 84224sec preferred_lft 84224sec
inet6 fe80::d81a:24b:f174:82f/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:74:1d:cd brd ff:ff:ff:ff:ff:ff
inet 192.168.2.242/24 brd 192.168.2.255 scope global noprefixroute dynamic enp0s8
valid_lft 602624sec preferred_lft 602624sec
inet6 fe80::3c89:876e:2930:5286/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 52:54:00:06:12:45 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
5: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN group default qlen 1000
link/ether 52:54:00:06:12:45 brd ff:ff:ff:ff:ff:ff
6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:94:6e:78:c1 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
没有设置-p 的端口映射了,如何访问启动的 tomcat83 ?直接访问宿主机即可!http://宿主机 IP:8080/
在 CentOS 里面用默认的火狐浏览器访问容器内的 tomcat83 看到访问成功,因为此时容器的 IP 借用主机的,所以容器共享宿主机网络 IP,这样的好处是外部主机与容器可以直接通信。
none
在 none 模式下,并不为 Docker 容器进行任何网络配置,禁用了网络功能,只有 lo 标识(就是 127.0.0.1,本地回环)
也就是说,这个 Docker 容器没有网卡、IP、路由等信息,只有一个 lo,需要我们自己为 Docker 容器添加网卡、配置 IP 等。
启动一个来分析:
docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
通过 inspect 查看:没有网关和 IP
$ docker inspect tomcat84 | tail -n 20
"Networks": {
"none": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "1ddfe19eb462f6485c00ec56945ce5d1835d4aac20b6229e73a0018176c05ff5",
"EndpointID": "9b92af07ef5c8c85a0c1218167304a72ac01047af69be44e489d199e1879d260",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
进入容器内看:
$ docker exec -it tomcat84 bash
$ 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
了解即可,不过多展开
container
新建的容器和已经存在的一个容器共享一个网络 IP 配置而不是和宿主机共享。
新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同
样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
示意图:
接下来实践下,先创建一个容器:
docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
然后创建第二个,并使用第一个容器的网卡,但是报错了:
$ docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8
$ docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
See 'docker run --help'.
相当于 tomcat86 和 tomcat85 公用同一个 ip 同一个端口,导致端口冲突
这里我们换个镜像:Alpine 操作系统。Alpine Linux 是一款面向安全的、轻型、独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为、基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M 的大小,所以特别适合容器打包
启动 2 个容器:
docker run -it --name alpine1 alpine /bin/sh
新开一个终端,运行第二个:
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
接下来验证是否共用搭桥,在两个终端内执行 ip addr
:
$ docker exec -it alpine1 /bin/sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
$ docker exec -it alpine2 /bin/sh
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
可以看到两个 IP 都是一样的,172.17.0.2。如果 alpine1 被关闭了呢?docker stop alpine1
那么 alpine2 也没有 IP 了:
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
自定义网络
接下来介绍第 5 种:自定义网络
Docker 默认的网络有 3 种:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5bd056a8204a bridge bridge local
553d2c47bcaa host host local
1ddfe19eb462 none null local
但是我们也可以创建一个网络:
$ docker network create aa_network
9eeb4fd0bf15a59d77bdba7e40594eb30ddd2c2c2ad66df706608a939cd2d193
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
9eeb4fd0bf15 aa_network bridge local
5bd056a8204a bridge bridge local
553d2c47bcaa host host local
1ddfe19eb462 none null local
为什么需要自定义网络?可以将容器分门别类,在各自的网络中通信。之前我们演示过,Docker 内容器的 IP 是有可能发生变化的
在介绍自定义网络之前,我们再次演示下,不使用自定义网络有什么问题。
为避免干扰,先删除其他容器,再启动两个 Tomcat:
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
然后我们打开两个终端,分别进入容器:
docker exec -it tomcat81 bash
docker exec -it tomcat82 bash
81 的 IP 信息:172.17.0.2
$ 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
23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
82 的 IP 信息:172.17.0.3
$ 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
25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
此外,在两个容器内,互相是能 ping 通的,例如 81 能 ping 通 82:
$ ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.024 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.024 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.026 ms
既然 IP 地址是可能变化的,那么根据 IP 地址来通信是可能会被干扰的,能否通过服务名来 ping 呢?当然是不行的,例如在 81:
$ ping tomcat2
ping: tomcat2: Name or service not known
接下来我们演示,使用自定义网络的话,能不能解决上述问题。
首先自定义桥接网络,自定义网络默认使用的是桥接网络 bridge:
$ docker network create zzyy_network
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
f1c9ebe5d961 bridge bridge local
553d2c47bcaa host host local
1ddfe19eb462 none null local
daf309d234de zzyy_network bridge local
删除之前的容器,新建容器,加入上一步新建的网络:
docker run -d -p 8081:8080 --network zzyy_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network zzyy_network --name tomcat82 billygoo/tomcat8-jdk8
再次打开两个终端,分别进入容器,,并且试试能否 ping 通:
$ docker exec -it tomcat81 bash
$ ping tomcat82
PING tomcat82 (172.18.0.3) 56(84) bytes of data.
64 bytes from tomcat82.zzyy_network (172.18.0.3): icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from tomcat82.zzyy_network (172.18.0.3): icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from tomcat82.zzyy_network (172.18.0.3): icmp_seq=3 ttl=64 time=0.039 ms
可以看到完全能 ping 通。
结论:自定义网络本身就维护好了主机名和 IP 的对应关系( IP 和域名都能通)
link 技术
在过去,Docker 还有一种通信的功能(类似网络),叫做 link,不过已经过时了,不用再去学习,官网文档如下:Legacy container links
The
--link
flag is a legacy feature of Docker. It may eventually be removed. Unless you absolutely need to continue using it, we recommend that you use user-defined networks to facilitate communication between two containers instead of using--link
.…
(完)