脚本宝典收集整理的这篇文章主要介绍了Docker之网络,脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
docker安装时会自动在host上创建三个网络
$ docker network ls
NETWORK ID NamE DRIVER SCOPE
5376af5a55ad bridge bridge local
049e90fb8744 host host local
1c17c651c262 none null local
Docker服务启动时会首先在主机上自动创建一个docker0虚拟网桥,实际上是一个Linux网桥。网桥可以理解为一个软件交换机,负责挂载其上的接口之间进行包转发。Docker随机分配一个本地未占用的私有网段中的一个地址给docker0接口
当创建一个Docker容器的时候,同时会创建了一对veth pair互联接口。当向任一个接口发送包时,另外一个接口自动收到相同的包。互联接口的一端位于容器内,即eth0;另一端在本地并被挂载到docker0网桥,名称以veth开头(例如vethAQI2QT)。通过这种方式,主机可以与容器通信,容器之间也可以相互通信。
none网络就是什么都没有的网络。挂在这个网络下的容器除了lo
,没有其他任何网卡。容器创建时,可以通过--network=none
指定使用none网络
$ docker run -it --network=none busybox
封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用none网络。比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。
连接到host网络的容器共享Docker host的网络栈,容器的网络配置与host完全一样。可以通过 --network=host
指定使用host网络
$ docker run -IT --network=host busybox
进入docker容器中执行
$ ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:bb:6b:c7 brd ff:ff:ff:ff:ff:ff
3: virbr0: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue qlen 1000
link/ether 52:54:00:bb:93:fc brd ff:ff:ff:ff:ff:ff
...省略...
$ hostname
jannal.docker.COM
在容器中可以看到host的所有网卡,并且连hostname也是host的。
直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择host网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再用了。
Docker host的另一个用途是让容器可以直接配置host网路,比如某些跨host的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理iptables
Docker安装时会创建一个命名为docker0的Linux bridge。如果不指定--network,创建的容器默认都会挂到docker0上
一个新的网络接口veth80c2b3d被挂到了docker0上,veth80c2b3d就是新创建容器的虚拟网卡
$ brctl show
bridge name bridge id STP enabled interfaces
...省略...
br-fe270d626e9c 8000.02420cbe41a7 no
docker0 8000.02423a05b84c no veth80c2b3d
virbr0 8000.525400bb93fc yes virbr0-nic
$ docker ps
CONTAINER ID IMAGE ...
8c7f87e79c4f busybox ...
$ docker exec -it 8c7f87e79c4f /bin/bash
容器内执行
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
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
57: eth0@if58: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
容器内有一个网卡eth0@if58
。veth80c2b3d
和eth0@if58
实际上是一对veth pair。veth pair是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头(eth0@if58)在容器中,另一头(veth80c2b3d)挂在网桥docker0上,其效果就是将eth0@if58也挂在了docker0上。
eth0@if58的Ip网段为什么是172.17.0.3/16
?
bridge网络配置的subnet就是172.17.0.0/16,并且网关是172.17.0.1
网关就是docker0
容器创建时,docker会自动从172.17.0.0/16中分配一个IP,这里16位的掩码保证有足够多的IP可以供容器使用
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "5376af5a55ada8e8c62464f537c6c01c520346c579834db2F19c723114195ccc",
"Created": "2021-08-16T10:40:49.736330436+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": {
"8c7f87e79c4f7e376d8641615ad3d2f3071ceb2e78a21DF9a2929978b1662f55": {
"Name": "busy",
"EndpointID": "f5aa27be680b1066d00bef2b4379a079f7af45905346192aa1eec868db242345",
"MaCADdress": "02:42:ac:11:00:03",
"ipv4Address": "172.17.0.3/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": {}
}
]
可以看到docker0的 Ip是 172.17.0.1
$ ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:3aff:fe05:b84c prefixlen 64 scopeid 0x20<link>
ether 02:42:3a:05:b8:4c txqueuelen 0 (Ethernet)
RX packets 28 bytes 2469 (2.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 97 bytes 22049 (21.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
网络拓扑图
容器中的eth0实际上和外面host上的某个veth是成对的(pair)关系,那么,有没有办法知道host上的vethxxx和哪个container eth0是成对的关系呢?
方法一:
1. 在目标容器里查看:
$ cat /Sys/class/net/eth0/iflink
5
2. 在主机上遍历/sys/claas/net下面的全部目录,
查看子目录ifindex的值和容器里查出来的iflink值相当的veth名字,
这样就找到了容器和主机的veth pair关系
$ cat /sys/class/net/veth80c2b3d/ifindex
5
方法二
1. 在目标容器中执行
$ ip link show eth0
116:eth0@if117,其中116是eth0接口的index,117是和它成对的veth的index。
2. 在host中执行。可以看到对应117的veth网卡是哪一个
$ ip link show |grep 117
方法三
1. 可以通过ethtool-s命令列出veth pair对端的网卡index
$ ethtool -S eth0
2. 查看主机上index为6的网卡
$ ip addr
Docker提供三种user-defined网络驱动:bridge、overlay和macvlan。overlay和macvlan用于创建跨主机的网络
可通过bridge驱动创建类似前面默认的bridge网络
$ docker network create --driver bridge --subnet 172.50.16.0/24 net0
391304d84cec40ccef6aa9f46580b4f2c6f42e0026c294a680ece26524f35f77
$ docker network inspect net0
[
{
"Name": "net0",
"Id": "391304d84cec40ccef6aa9f46580b4f2c6f42e0026c294a680ece26524f35f77",
"Created": "2021-09-16T21:43:52.880434594+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.50.16.0/24"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
5376af5a55ad bridge bridge local
049e90fb8744 host host local
391304d84cec net0 bridge local
1c17c651c262 none null local
--ip指定静态IP。只有使用 --subnet创建的网络才能指定静态IP。
$ docker run -it --network=net0 --ip 172.50.16.2 busybox
在docker容器中执行,可以看到eth0@if65网卡对应的IP是172.50.16.2
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
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
64: eth0@if65: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:32:10:02 brd ff:ff:ff:ff:ff:ff
inet 172.50.16.2/24 brd 172.50.16.255 scope global eth0
valid_lft forever preferred_lft forever
使用默认docker0创建一个容器
$ docker run -it --name docker0-busybox busybox
在容器中执行
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
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
68: eth0@if69: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
使用docker0的容器IP是172.17.0.3
,使用net0的容器IP是172.50.16.2
。在两个容器中ping各自的IP,默认情况下肯定是无法ping通的。因为两个网络属于不同的网桥
$ ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
$ ping 172.50.16.2
PING 172.50.16.2 (172.50.16.2): 56 data bytes
查看
$ brctl show
bridge name bridge id STP enabled interfaces
br-391304d84cec 8000.02423c2a9a63 no veth7870726
docker0 8000.02423a05b84c no veth4beae2e
veth8CF70c5
virbr0 8000.525400bb93fc yes virbr0-nic
如果host上对每个网络都有一条路由,同时操作系统上打开了ip forwarding
, host就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。通过命令可以看出host确实已经成为一个路由器了
1. 在Docker Host(宿主机)上查看路由表
$ ip r
default via 192.168.100.2 dev ens33 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.50.16.0/24 dev br-391304d84cec proto kernel scope link src 172.50.16.1
192.168.100.0/24 dev ens33 proto kernel scope link src 192.168.100.128 metric 100
2. 查看ip forward是否开启
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
3. 查看iptables,iptables DROP掉了网桥br-391304d84cec与docker0之间双向的流量(这才是不能通信的原因)
$ iptable-save
...省略...
-A DOCKER-ISOLATION-STAGE-1 -i br-391304d84cec ! -o br-391304d84cec -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
...省略...
既然iptables已经断掉了两个网络之间的流量,那么怎样才能想让两个网络能互通?
$ docker ps
CONTAINER ID IMAGE names
694b8f056a5d busybox ...省略... docker0-busybox
a32815a8712b busybox
通过docker network connect 实现为694b8f056a5d添加一个网卡
$ docker network connect net0 694b8f056a5d
在docker0-busybox 容器中查看。发现多了一个网卡eth1@if71,分配的地址为172.50.16.3
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
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
68: eth0@if69: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
70: eth1@if71: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:32:10:03 brd ff:ff:ff:ff:ff:ff
inet 172.50.16.3/24 brd 172.50.16.255 scope global eth1
valid_lft forever preferred_lft forever
再次测试,发现可以ping通
$ ping 172.50.16.2
PING 172.50.16.2 (172.50.16.2): 56 data bytes
64 bytes from 172.50.16.2: seq=0 TTL=64 time=0.283 ms
64 bytes from 172.50.16.2: seq=1 ttl=64 time=0.093 ms
-P
或者-p
指定端口映射,使用-P
时,docker会随机映射一个49000-49900的端口至容器内部开放的网络端口-p
可以指定要映射的端口,并且在一个指定端口上只可以绑定一个容器,多次使用-p
可以绑定多个端口。hostPort:containerPort
docker run -d -p 3000:3000 jannal/centos6.6-sshd:latest /bin/bash
此时会默认绑定本地所有网卡接口的所有地址ip:hostPort:containerPort
docker run -d -p 192.168.6.107:3000:3000 jannal/centos6.6-sshd:latest /bin/bash
docker run -d -p 192.168.6.107::3000 jannal/centos6.6-sshd:latest /bin/bash
本地会自动分配一个端口docker run -d -p 192.168.6.107:3000:3000/udp jannal/centos6.6-sshd:latest /bin/bash
--network
指定相应的网络,或者通过docker network connect
将现有容器加入到指定网络容器名
通信。使用docker DNS有个限制:只能在自定义网络中使用。即默认的bridge网络是无法使用DNS的。-p
和-P
标记,从而避免了暴露数据库服务端口到外部网络上
Docker服务启动后会默认启用一个内嵌的DNS服务,来自动解析同一个网络中的容器主机名和地址,如果无法解析,则通过容器内的DNS相关配置进行解析
容器中主机名和DNS配置信息可以通过三个系统配置文件来管理:/etc/resolv.conf、/etc/hostname和/etc/hosts。在容器中使用mount命令可以看到这三个文件挂载信息
$ docker exec -it b804919a247b /bin/bash
$ mroot@b804919a247b:/# mount
...省略...
/dev/sda2 on /etc/resolv.conf type xfs (rw,relatime,attr2,inode64,noquota)
/dev/sda2 on /etc/hostname type xfs (rw,relatime,attr2,inode64,noquota)
/dev/sda2 on /etc/hosts type xfs (rw,relatime,attr2,inode64,noquota)
...省略...
Docker启动容器时,会从宿主机上复制 /etc/resolv.conf文件,并删除掉其中无法连接到的DNS服务器
root@b804919a247b:/# cat /etc/resolv.conf
seArch docker.com
nameserver 127.0.0.11
options ndots:0
/etc/hosts文件中默认只记录了容器自身的地址和名称
root@b804919a247b:/# 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
172.18.0.2 b804919a247b
/etc/hostname文件则记录了容器的主机名:
root@b804919a247b:/# cat /etc/hostname
b804919a247b
容器运行时,可以在运行中的容器里直接编辑/etc/hosts、/etc/hostname和/etc/resolve. conf文件。但是这些修改是临时的,只在运行的容器中保留,容器终止或重启后并不会被保存下来,也不会被docker commit提交。
以上是脚本宝典为你收集整理的Docker之网络全部内容,希望文章能够帮你解决Docker之网络所遇到的问题。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。