1.网络的基本管理
Docker 在启动时会开启一个虚拟网桥设备 docker0,我的docker0的默认地址为 172.17.0.1/16, 容器启动后都会被桥接到 docker0 上,并自动分配到一个 IP 地址。
1.查看docker网络的模式
[root@server1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b57250eb8b99 bridge bridge local
b08aae61251c host host local
e41e6eb8399b none null local
2.获取容器的PID
每一个容器都会有一个独有的Pid
[root@server1 ~]# docker run -it --name vm1 ubuntu
root@7e2c2adcb47b:/# [root@server1 ~]#
[root@server1 ~]# docker inspect vm1 | grep Pid
"Pid": 13774,
"PidMode": "",
"PidsLimit": 0,
每一个独有的Pid都会在/proc目录下有一个相应的以Pid为名的目录,这个目录里面的ns目录有着关于这个Pid容器网络的文件
[root@server1 ~]# cd /proc/13774
[root@server1 13774]# ll ns/
total 0
lrwxrwxrwx 1 root root 0 Jun 10 23:37 ipc -> ipc:[4026532308]
lrwxrwxrwx 1 root root 0 Jun 10 23:37 mnt -> mnt:[4026532306]
lrwxrwxrwx 1 root root 0 Jun 10 23:36 net -> net:[4026532311]
lrwxrwxrwx 1 root root 0 Jun 10 23:37 pid -> pid:[4026532309]
lrwxrwxrwx 1 root root 0 Jun 10 23:37 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jun 10 23:37 uts -> uts:[4026532307]
2.docker的四种网络模式(Bridge、Host、Container、None)
bridge模式,使用–net=bridge指定,不使用-net则默认为bridge模式
none模式,使用–net=none指定。
host模式,使用–net=host指定。
container 模式,使用–net=container:容器名称或ID指定
1.Bridge模式
- Bridge 桥接模式的实现步骤主要如下:
(1) Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为
veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将
报文传输给另一方。
(2) Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
(3) Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到DockerContainer 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。 - bridge 桥接模式下的 Docker Container 在使用时,并非为开发者包办了一切。最明显的是,该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。虽然 NAT 模式经过中间处理实现了这一点,但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器内部服务的访问者需要使用服务发现获知服务的外部端口等。另外 NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
[root@server1 ~]# docker run -it --name vm1 ubuntu
root@7e2c2adcb47b:/# [root@server1 ~]# ##使用ctrl+p+q 离开
[root@server1 13774]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024296e38919 no veth1800e2d
veth5130bec
vethcfbd123 <--vm1的桥接
[root@server1 13774]# docker stop vm1
vm1
[root@server1 13774]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024296e38919 no veth1800e2d
veth5130bec
2.Host模式
使用docker run时使用–net=host指定,docker使用的网络实际上和宿主机一样,在容器内看到的网卡ip是宿主机上的ip。host模式很好的解决了容器与外界通信的地址转换问题,可以直接使用宿主机的IP镜像通信。但是也降低了隔离性,同时还会引起网络资源的竞争和冲突。
[root@server1 13774]# docker run -it --name vm2 --net host ubuntu
root@server1:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:78:da:44 brd ff:ff:ff:ff:ff:ff
inet 172.25.80.1/24 brd 172.25.80.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe78:da44/64 scope link
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:96:e3:89:19 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:96ff:fee3:8919/64 scope link
valid_lft forever preferred_lft forever
127: veth5130bec@if126: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether fe:bf:1a:6d:23:4c brd ff:ff:ff:ff:ff:ff
inet6 fe80::fcbf:1aff:fe6d:234c/64 scope link
valid_lft forever preferred_lft forever
129: veth1800e2d@if128: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 16:61:c9:22:59:ad brd ff:ff:ff:ff:ff:ff
inet6 fe80::1461:c9ff:fe22:59ad/64 scope link
valid_lft forever preferred_lft forever
root@server1:/# ip a[root@server1 13774]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:78:da:44 brd ff:ff:ff:ff:ff:ff
inet 172.25.80.1/24 brd 172.25.80.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe78:da44/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:96:e3:89:19 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:96ff:fee3:8919/64 scope link
valid_lft forever preferred_lft forever
127: veth5130bec@if126: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether fe:bf:1a:6d:23:4c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::fcbf:1aff:fe6d:234c/64 scope link
valid_lft forever preferred_lft forever
129: veth1800e2d@if128: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether 16:61:c9:22:59:ad brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::1461:c9ff:fe22:59ad/64 scope link
valid_lft forever preferred_lft forever
可以看到容器使用ip a查询到的结果与宿主机查询到的相同
3.Container模式
多个容器使用共同的网络,看到的ip是一样的。container模式的应用场景就在于可以将一个应用的多个组件放在不同的容器中,这些容器配成container模式的网络,这样它们就可以作为一个整体对外提供服务。同样这种模式也降低了容器间的隔离性。
Docker Container 的 other container 网络模式,可以用来更好的服务于容器间的通信。
在这种模式下的 Docker Container 可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。另外,这种模式还节约了一定数量的网络资源。
[root@server1 13774]# docker run -it --name vm1 ubuntu
root@2b8373416200:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
136: eth0@if137: <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
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
[root@server1 13774]# docker run -it --name vm2 --net container:vm1 ubuntu
root@2b8373416200:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
136: eth0@if137: <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
inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
vm1与vm2使用ip addr 查询到的结果是一样的,因为vm2使用的是vm1容器的网络
4.None模式
none模式是指禁用网络功能,只有lo接口,在容器创建时使用
–network=none指定
[root@server1 13774]# docker run -it --name vm3 --net none ubuntu
root@181cca9bd7b3:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
3.创建自定义网络模式
1.创建一个bridge模式的网络
[root@server1 13774]# docker network create my_net1
2d8a5cbbbb56dd77253a264f63203726d36cfa2de3fa48f3114af006d1f99f6b
[root@server1 13774]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b57250eb8b99 bridge bridge local
b08aae61251c host host local
2d8a5cbbbb56 my_net1 bridge local
e41e6eb8399b none null local
[root@server1 13774]# ip a
138: br-2d8a5cbbbb56: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:b7:73:1b:24 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 brd 172.18.255.255 scope global br-2d8a5cbbbb56
valid_lft forever preferred_lft forever
[root@server1 13774]# docker net1 work inspect my_net1
{
"Subnet": "172.18.0.0/16", ##默认单调递增,18,19...
"Gateway": "172.18.0.1"
}
同一桥接下的两个容器可以直接使用容器名进行通信,因为会自动添加解析。
[root@server1 13774]# docker run -it --name vm1 --network=my_net1 ubuntu
root@107ca8e09048:/# ping vm1
PING vm1 (172.18.0.2) 56(84) bytes of data.
64 bytes from 107ca8e09048 (172.18.0.2): icmp_seq=1 ttl=64 time=0.021 ms
64 bytes from 107ca8e09048 (172.18.0.2): icmp_seq=2 ttl=64 time=0.024 ms
^C
--- vm1 ping statistics ---421-124
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.021/0.022/0.024/0.005 ms
root@107ca8e09048:/# [root@server1 13774]# docker run -it --name vm2 --network=my_net1 ubuntu
root@6a98915169c5:/# ping vm1
PING vm1 (172.18.0.2) 56(84) bytes of data.
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=1 ttl=64 time=0.116 ms
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=2 ttl=64 time=0.045 ms
^C
--- vm1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.045/0.080/0.116/0.036 ms
2.再创建一个bridge的网络,自定义ip和网关
[root@server1 13774]# docker network create --subnet=172.21.0.0/24 --gateway=172.21.0.1 my_net2
4c329d07f4b7c766076a3eea6fd9707b85645dfbfe64cf3b88c61afcff2c4ab4
[root@server1 13774]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b57250eb8b99 bridge bridge local
b08aae61251c host host local
2d8a5cbbbb56 my_net1 bridge local
4c329d07f4b7 my_net2 bridge local
e41e6eb8399b none null local1
3.创建容器
[root@server1 13774]# docker run -it --name vm3 --network=my_net2 --ip=172.21.0.10 ubuntu
root@c23736c8cd79:/# ping vm1
ping: unknown host vm1
root@c23736c8cd79:/# ^C
root@c23736c8cd79:/# ping vm3
PING vm3 (172.21.0.10) 56(84) bytes of data.
64 bytes from c23736c8cd79 (172.21.0.10): icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from c23736c8cd79 (172.21.0.10): icmp_seq=2 ttl=64 time=0.024 ms
^C
--- vm3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.020/0.022/0.024/0.002 ms
可以看到,使用使用不同网桥的容器之间是不能通信的,因为daocker在设计上就是要隔离不同的network的
4.如何使两个使用不同网桥的容器进行通信
使用 docker network connect命令为vm1添加一块my_net2 的网卡。
[root@server1 ~]# docker network connect my_net2 vm1
root@c23736c8cd79:/# ping vm1
PING vm1 (172.21.0.2) 56(84) bytes of data.
64 bytes from vm1.my_net2 (172.21.0.2): icmp_seq=1 ttl=64 time=0.099 ms
64 bytes from vm1.my_net2 (172.21.0.2): icmp_seq=2 ttl=64 time=0.036 ms
64 bytes from vm1.my_net2 (172.21.0.2): icmp_seq=3 ttl=64 time=0.038 ms
^C
--- vm1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.036/0.057/0.099/0.030 ms
docker的bridge自定义网络之间可以随便添加对方的网卡,但系统自带的网桥与自定义网络只能是系统自带的网桥对应的容器添加bridge自定义网络对应的容器的网卡,否则会出错。
4.docker的跨主机网络方案——macvlan
macvlan网络方案实现
Linux kernel提供的一种网卡虚拟化技术。
无需Linux bridge,直接使用 物理接口,性能极好。
1.在两台docker主机上各添加一块网卡,打开网卡混杂模式:
150: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 52:54:00:f5:d3:c4 brd ff:ff:ff:ff:ff:ff
[root@server1 ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth1
1 BOOTPROTO=none
2 DEVICE=eth1
3 ONBOOT=yes
[root@server1 ~]# ifup eth1
[root@server1 ~]# ip a
150: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:f5:d3:c4 brd ff:ff:ff:ff:ff:ff
inet6 fe80::5054:ff:fef5:d3c4/64 scope link
valid_lft forever preferred_lft forever
[root@server1 ~]# ip link set eth1 promisc on
[root@server1 ~]# ip a
150: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:f5:d3:c4 brd ff:ff:ff:ff:ff:ff
inet6 fe80::5054:ff:fef5:d3c4/64 scope link
valid_lft forever preferred_lft forever
server2操作相同
注意 : 如果不开启混杂模式,会导致macvlan网络无法访问外界,具体在不使用vlan时,表现为无法ping通路由,无法ping通同一网络内其他主机。
2.在两台主机上各创建macvlan网络
[root@server1 ~]# docker network create -d macvlan --subnet=172.22.0.0/24 --gateway=172.22.0.1 -o parent=eth1 macvlan1
26c0a6f66d16ad95c4d66fed815238ba6c1bb48bb88c634d11ebf984540a2b40
[root@server1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b57250eb8b99 bridge bridge local
b08aae61251c host host local
26c0a6f66d16 macvlan1 macvlan local
e41e6eb8399b none null local
[root@server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024296e38919 no
3.在两台主机上都加载ubuntu容器,并使用macvlan1建立容器
[root@server1 ~]# docker load -i ubuntu.tar
[root@server1 ~]# docker run -it --name vm1 --network=macvlan1 --ip=172.22.0.10 ubuntu
[root@server1 ~]# docker run -it --name vm2 --network=macvlan1 --ip=172.22.0.11 ubuntu
[root@server2 ~]# docker load -i ubuntu.tar
[root@server2 ~]# docker run -it --name vm3 --network=macvlan1 --ip=172.22.0.12 ubuntu
4.测试容器之间是否可以通信
vm2 ping vm1 成功
root@b070e6e7e3fa:/# ping vm1
PING vm1 (172.22.0.10) 56(84) bytes of data.
64 bytes from vm1.macvlan1 (172.22.0.10): icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from vm1.macvlan1 (172.22.0.10): icmp_seq=2 ttl=64 time=0.036 ms
^C
vm3 ping vm1 失败,因为没有解析,直接ping vm1的ip,成功
[root@server2 ~]# docker run -it --name vm3 --network=macvlan1 --ip=172.22.0.12 ubuntu
root@16c5a3aa2a53:/# ping vm1
^C
root@16c5a3aa2a53:/# ping 172.22.0.10
PING 172.22.0.10 (172.22.0.10) 56(84) bytes of data.
64 bytes from 172.22.0.10: icmp_seq=1 ttl=64 time=1.15 ms
64 bytes from 172.22.0.10: icmp_seq=2 ttl=64 time=0.294 ms
^C
互联成功!
注意:macvlan模式不依赖网桥,所以brctl show查看并没有创建新的bridge,但是查看容器的网络,会看到虚拟网卡对应了一个interface是4
而宿主主机的eth1正是4。
5.macvlan会独占主机的网卡的解决方案
-
macvlan会独占主机网卡,但可以使用vlan子接口实现多
macvlan网络 -
vlan可以将物理二层网络划分为4094个逻辑网络,彼此隔离,
vlan id取值为1~4094
添加vlan子接口
[root@server1 ~]# docker network create -d macvlan --subnet=172.23.0.0/24 --gateway=172.23.0.1 -o parent=eth1.1 macvlan2
a3a5fe37e3817f07883fa28aa8ae2feaa6112310dfb6a3ea63ea319e9fc9914b
[root@server1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
b57250eb8b99 bridge bridge local
b08aae61251c host host local
26c0a6f66d16 macvlan1 macvlan local
a3a5fe37e381 macvlan2 macvlan local
e41e6eb8399b none null local
给容器添加子接口实现不同子接口容器间的通讯
[root@server1 ~]# docker network connect macvlan1 vm3
[root@server1 ~]# docker attach vm3
root@3ba9aab32c69:/#
root@3ba9aab32c69:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
156: eth0@if155: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether 02:42:ac:17:00:0b brd ff:ff:ff:ff:ff:ff
inet 172.23.0.11/24 brd 172.23.0.255 scope global eth0
valid_lft forever preferred_lft forever
157: eth1@if150: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
link/ether 02:42:ac:16:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.22.0.2/24 brd 172.22.0.255 scope global eth1
valid_lft forever preferred_lft forever
root@3ba9aab32c69:/# ping 172.22.0.11
PING 172.22.0.11 (172.22.0.11) 56(84) bytes of data.
64 bytes from 172.22.0.11: icmp_seq=1 ttl=64 time=0.223 ms
64 bytes from 172.22.0.11: icmp_seq=2 ttl=64 time=0.033 ms
^C
--- 172.22.0.11 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.033/0.128/0.223/0.095 ms