本文最后更新于 2024年12月5日
Docker的网络用于容器间的互联和通信,以及宿主机端口映射,容器IP变动的时候可以设置网络直接使用服务名进行网络通信而不受影响。类似于虚拟机软件分配IP地址给各个安装的虚拟机以及物理机,虚拟机之间以及虚拟机和物理机之间可以相互通信。
1.查看容器的网络 1.查看容器网络类型
docker inspect命令查看关于Networks
的部分
当前容器是bridge
网络,网关是172.17.0.1
, IP是172.17.0.2
"Networks" : {
"bridge" : {
"IPAMConfig" : null ,
"Links" : null ,
"Aliases" : null ,
"NetworkID" : "2def63006d0705d822ebd7269baf1512be0fc886c40e9047f35635ef21585b33" ,
"EndpointID" : "4fd79243a84032b34a57a39b0ffc03136bef175498980abdc097117e17f135fe" ,
"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
}
}
2.查看当前有多少个docker网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
2def63006d07 bridge bridge local
f8b834999d26 host host local
fd9dc003ef95 lzjnet bridge local
2ca13d3f5552 none null local
3.查看网络的情况
docker network inspect 网络名
网络lzjnet的网络类型是bridge
,还有IP等信息
[
{
"Name" : "lzjnet" ,
"Id" : "fd9dc003ef956e7b3f01d74b81f5fc6cc04c76ce5144beadc9707dd4a7a41134" ,
"Created" : "2024-11-26T23:12:55.276879774+08:00" ,
"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" : { } ,
"Options" : { } ,
"Labels" : { }
}
]
2.Docker的网络类型 几种常见的网络类型
网络模式
简介
bridge
默认为该模式,为每一个容器分配和设置IP,并将容器连接到默认的虚拟网桥docker0
host
容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
none
容器有独立的network namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接,IP等
container
新创建的容器不会自动创建自己的网卡和配置IP,而是和一个指定的容器共享IP和端口范围等
2.1 bridge网络 1.主机和容器联网
Docker服务默认会创建一个网桥(上有一个docker0的内部接口),该桥接网络的名称为docker0
,它在内核层 连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络 。Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
2.容器之间联网
Docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关,因为在同一宿主机内的容器都接入同一网桥,这样容器之间就可以通过容器的Container-IP直接通信。
3.bridge网络的分配机制
docker run
的时候,没有指定network的话,默认使用的网桥模式就是bridge(docker0)。在宿主机ifconfig就可以看见docker0和自己创建的网络(eth0, eth1…..),lo代表127.0.0.1。
网桥docker0创建一对对等的虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配。
整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)
每个容器内部也有一块网卡,每个接口叫eth0,docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
验证veth-pair:
查看正在运行的Docker容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
38188376416b tomcat "catalina.sh run" About a minute ago Up About a minute 8080/tcp inspiring_austin
宿主机执行ip addr
查看宿主机的网络情况
[root@localhost ~]# 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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:44:65:de brd ff:ff:ff:ff:ff:ff
inet 192.168.228.104/24 brd 192.168.228.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::2ac6:ec4:9411:4da8/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ff:ca:bc:ec 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
inet6 fe80::42:ffff:feca:bcec/64 scope link
valid_lft forever preferred_lft forever
15: vethc5f3f03@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 26:9a:2e:de:95:5a brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::249a:2eff:fede:955a/64 scope link
valid_lft forever preferred_lft forever
进入容器,一般需要先更新tomcat容器的yum,再安装工具iproute2
sudo apt-get update
sudo apt-get upgrade
apt-get install -y iproute2
然后,在容器内执行ip addr
查看容器的网络情况
root@38188376416b:/# 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
14: eth0@if15: <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
然后可见宿主机的网卡 15: vethc5f3f03@if14
和容器网卡 14: eth0@if15
两两匹配,互互相同
2.2 host网络 直接使用宿主机的IP地址与外界通信,不需要额外进行NAT转换。
容器将不再获得一个独立的网络名称空间,而是和宿主机共用一个网络名称空间,容器将不会虚拟出自己的网卡,而是使用宿主机的IP和端口,容器没有自己的IP。
这种模式下,使用-p
端口映射是无效的,也是没有任何意义的。
2.3 none网络 等同于禁用网络功能,不为容器进行任何网络配置,容器没有网卡,路由等信息,只有一个本地回环网卡lo
2.4 container网络 新建的容器和一个已经存在的容器共享一个网络IP配置而不是和宿主机共享,新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围等,同样,两个容器除了网络方面,其他的例如文件系统,进程列表等还是隔离的。
需要注意的是:
1.继承和被继承的容器的容器内端口不能是相同的,否则会导致冲突,因为两个容器共享网段和IP
验证:先启动一个tomcat容器tomcat86
,该容器内的程序会占用容器的8080,在启动另一个tomcat容器tomcat87
和前者共享网络,因为也是基于tomcat镜像,所以同样会占用容器的8080,两个容器端口范围是共享的,导致报错Error response from daemon: conflicting options: port publishing and the container type network mode.
docker run -d --privileged = true -p 8086 :8080 --name tomcat86 tomcat
docker run -d --privileged = true -p 8086 :8080 --network container:tomcat86 --name tomcat87 tomcat
[root@localhost ~]# docker run -d --privileged=true -p 8086:8080 --name tomcat86 tomcat
c8464b5448296b51bc5b4e4598acce709513aa6ac7fac6ef335e5a39e8a785f3
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c8464b544829 tomcat "catalina.sh run" 4 seconds ago Up 2 seconds 0.0.0.0:8086->8080/tcp tomcat86
0bad9102a5a7 alpine "/bin/sh" 11 minutes ago Up 11 minutes alpine1
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]#
[root@localhost ~]# docker run -d --privileged=true -p 8086:8080 --network container:tomcat86 --name tomcat87 tomcat
docker: Error response from daemon: conflicting options: port publishing and the container type network mode.
See 'docker run --help'.
2.被继承的容器结束运行后,继承它的容器也会失去网络功能,只剩下一个回环网卡lo
验证:先运行一个精简版Linux容器alpine1
,在运行一个同样的容器alpine2
,指定和alpine1
共享网络,查看容器内网络可见网卡名称和IP地址都是完全一样的
docker run -it --name alpine1 alpine /bin/sh
[root@localhost ~]# docker run -it --name alpine1 alpine /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
16: eth0@if17: <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 run -it --name alpine2 --network container:alpine1 alpine /bin/sh
[root@localhost ~]# docker run -it --name alpine2 --network container:alpine1 alpine /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
16: eth0@if17: <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
关闭容器alpine1
,进入容器alpine2
查看IP,发现eth
网卡跟着消失了,只剩下lo
[root@localhost ~]# docker stop alpine1
alpine1
[root@localhost ~]# 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
2.5 自定义网络 为什么要自定义网络?
1.容器间的互联和通信以及端口映射 2.bridge模式网络分配给容器的IP是可能随着容器的启动关闭而导致分配的地址发生变动的,但是Docker自带的bridge网络比较简单,没有内置DNS功能 ,自定义网络后,容器IP变动的时候可以通过服务名直连网络而不受影响,当用户创建自定义网络时,Docker自动配置了一个内置DNS服务器,这个DNS服务器会根据容器的名称自动解析对应的IP地址。
自定义网络默认也是采用桥接模式bridge
,只是功能比默认的那个更强,自然就维护好了容器名和IP的映射关系(DNS)
验证:
创建一个网络lzjnet
docker network create lzjnet
创建容器tomcat1 tomcat2,指定我们自己创建的网络,然后互PING
docker run -it --privileged = true --network lzjnet --name alpine81 alpine
docker run -it --privileged = true --network lzjnet --name alpine82 alpine
[root@localhost ~]# docker attach alpine81
/ # ping alpine82
PING alpine82 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.889 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.195 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.181 ms
64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.167 ms
64 bytes from 172.18.0.3: seq=4 ttl=64 time=0.547 ms
^C
--- alpine82 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.167/0.395/0.889 ms
[root@localhost ~]# docker attach alpine82
/ # ping alpine81
PING alpine81 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.079 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.133 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.169 ms
64 bytes from 172.18.0.2: seq=3 ttl=64 time=0.186 ms
64 bytes from 172.18.0.2: seq=4 ttl=64 time=0.663 ms
64 bytes from 172.18.0.2: seq=5 ttl=64 time=0.260 ms
64 bytes from 172.18.0.2: seq=6 ttl=64 time=0.176 ms
^C
--- alpine81 ping statistics ---
7 packets transmitted, 7 packets received, 0% packet loss
round-trip min/avg/max = 0.079/0.238/0.663 ms
可以发现可以使用容器名相互PING通
3.总结 Docker可以使用4种网络模式来实现容器之间以及和宿主机的网络通信,自己实现自定义的网络桥接模式功能更强。