一:网络基础
Docker 本身的技术依赖于 Linux 内核虚拟化技术的发展
所以 Docker 对 Linux 内核的特性有很强的依赖
其中 Docker 使用到的与 Linux 网络有关的技术分别有:网络名称空间
、Veth
、网桥
、Iptables
、路由
# 查看本机路由
[root@localhost blog]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.50.2 0.0.0.0 UG 102 0 0 eth0
172.16.0.0 0.0.0.0 255.255.0.0 U 101 0 0 eth1
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.50.0 0.0.0.0 255.255.255.0 U 102 0 0 eth0
192.168.50.0 0.0.0.0 255.255.255.0 U 102 0 0 eth0
1.网络命名空间
在同一台Linux系统上,生成不同的隔离的网络空间
为了支持网络协议栈的多个实例,Linux 在网络协议栈中引入了网络命名空间(Network amespace),这些独立的协议栈被隔离到不同的命名空间中
处于不同的命名空间的网络协议栈是完全隔离
的,彼此之间无法进行网络通信,就好像两个“平行宇宙”
通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境,而 Docker 正是利用这种网络名称空间的特性,实现了不同容器之间的网络隔离。在 Linux 的网络命名空间内可以有自己独立的 Iptables 来转发、NAT 及 IP 包过滤等功能
Linux 的网络协议栈是十分复杂的,为了支持独立的协议栈,相关的这些全局变量都必须修改为协议栈私有。 最好的办法就是让这些全局变量成为一个 Net Namespace
变量的成员,然后为了协议栈的函数调用加入一个 Namespace 参数。这就是 Linux 网络名称空间的核心
所有的网络设备都只能属于一个网络名称空间。当然, 通常的物理网络设备只能关联到 root 这个命名空间中。虚拟网络设备则可以被创建并关联到一个给定的命名空 间中,而且可以在这些名称空间之间移动
- 回环:本地回环网络 127.0.0.1
① 创建1个命名空间
# 语法
ip netns add 命名空间名称
# 创建一个名称为 namespace01 的命名空间
ip netns add namespace01
# 查看已有的命名空间
ip netns list
[root@localhost ~]# ip netns add namespace01
[root@localhost ~]# ip netns add namespace02
[root@localhost ~]# ip netns list
namespace02
namespace01
2.Veth设备
对端与对端之间的网络合同(缺点:只支持一对一)
引入 Veth 设备对是为了在不同的网络名称空间之间进行通信,利用它可以直接将两个网络名称空间链接起来
由于要连接的两个网络命名空间,所以 Veth 设备是成对出现的,很像一对以太网卡,并且中间有一根直连的网线
既然是一对网卡,那么我们将其中一端称为另一端的 peer
在 Veth 设备的一端发送数据时,它会将数 据直接发送到另一端,并触发另一端的接收操作
① 创建 Veth设备对
# 语法
ip link add veth type veth peer name Veth设备对名称
# 创建1个Veth设备对 veth001
[root@localhost ~]# ip link add veth type veth peer name veth001
# 显示所有连接的IP
[root@localhost ~]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:70:89:d7 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:70:89:e1 brd ff:ff:ff:ff:ff:ff
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:30:b7:ce:44 brd ff:ff:ff:ff:ff:ff
8: vethd217151@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether ba:6c:89:54:b7:61 brd ff:ff:ff:ff:ff:ff link-netnsid 0
9: veth001@veth: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 96:86:6b:2f:e4:37 brd ff:ff:ff:ff:ff:ff
10: veth@veth001: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 46:e2:09:27:7c:30 brd ff:ff:ff:ff:ff:ff
# 实例可以看到9和10 是一对
生成了两个 veth 设备, 互为对方的 peer
② 绑定命名空间
# 语法
ip link set Veth设备对名称 netns 命名空间名称
# 将Veth设备对veth001 和 命名空间namespace01 绑定
ip link set veth001 netns namespace01
# 查看
ip link show | grep veth
[root@localhost ~]# ip link show | grep veth
8: vethd217151@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
10: veth@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
此时,已经查看不到 veth001
了,当我们进入 namespace01
命名空间之后,就可以查看到
# 进入命名空间namespace01
ip netns exec namespace01 bash
# 查看已连接IP
ip link show
[root@localhost ~]# ip netns exec namespace01 bash
[root@localhost ~]# ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
9: veth001@if10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 96:86:6b:2f:e4:37 brd ff:ff:ff:ff:ff:ff link-netnsid 0
③ 将 Veth 分配 IP
# 设置IP
ip netns exec namespace01 ip addr add 172.16.0.111/20 dev veth001
# 绑定
ip netns exec namespace01 ip link set dev veth001 up
# 查看
ip netns exec namespace01 ip a
此时,双方就连通了
④ 查看对端 Veth 设备
ip netns exec namespace01 ethtool -S veth001
ip a | grep 15
⑤ 为对端 Veth 设备设置 IP
ip addr add 172.16.0.112/20 dev veth
ip link set dev veth down
ip link set dev veth up
ping 172.16.0.111
3.网桥
提供一个网络空间,其他网络空间可以使用网桥的网络(优点:支持多对多)
Linux 可以支持多个不同的网络,它们之间能够相互通信,就需要一个网桥。
网桥是二层的虚拟网络设备, 它是把若干个网络接口“连接”起来,从而报文能够互相转发
网桥能够解析收发的报文,读取目标 MAC 地 址的信息,和自己记录的 MAC 表结合,来决定报文的转发目标网口。
网桥设备 brO 绑定了 eth0、 eth1 。对于网络协议械的上层来说,只看得到 brO
因为桥接是在数据链 路层实现的 ,上层不需要关心桥接的细节,于是协议枝上层需要发送的报文被送到 brO ,网桥设备的处理代 码判断报文该被转发到 ethO 还是 ethl ,或者两者皆转发
反过来,从 ethO 或从 ethl 接收到的报文被提交 给网桥的处理代码,在这里会判断报文应该被转发、丢弃还是提交到协议枝上层。
而有时 ethl 也可能会作为 报文的源地址或目的地址 直接参与报文的发送与接收,从而绕过网桥
4.Iptables(内核级别)
其他网络空间可以通过Iptables规则转发网络(缺点:Iptables规则比较复杂)
Linux 网络协议桥非常高效,同时比较复杂 如果我们希望在数据的处理过程中对关心的数据进行 一些操作该怎么做呢?
Linux 提供了一套机制来为用户实现自定义的数据包处理过程。
在 Linux 网络协议棋中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在 Linux 网络棋处理 据包的过程中对数据包进行 些操作
例如过滤、修改、丢弃等 整个挂接点技术叫作 Netfilter lptables Netfilter 负责在内核中执行各种挂接的规则,运行在内核模式中
而 lptables 是在用户模式下运行的进程, 负责协助维护内核中 Netfilter 的各种规则表通过者的配合来实现整个 Linux 网络协议战中灵活的数据包处理 机制
5.总结
设备 | 作用 |
---|---|
Network Namespace 网络命名空间 |
主要提供了关于网络资源的隔离 包括网络设备、IPv4 和 IPv6 协议栈、IP 路 由表、防火墙、 /proc/net 目录、/sys/class/net 目录、端口(socket)等 |
Veth Pair Veth设备对 |
2个虚拟网卡组成的数据通道 在 Docker 中,用于连接 Docker 容器和 Linux Bridge 一端在容器中作为 eth0 网卡 另一端在 Linux Bridge 中作为网桥的 一个端口 |
Linux Bridge Linux网桥 |
功能相当于物理交换机,为连在其上的设备(容器)转发数据帧 如 docker0 网桥 |
iptables | 主要为容器提供 NAT 以及容器网络安全 |
二:网络模式
Docker 使用 Linux 桥接的方式,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个容器时会根据 Docker 网桥的网段分配给容器一个 IP 地址,称为 Container-IP,同时 Docker 网桥是每个容器的默认网关
因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信
Docker 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接 Container-IP 访问到容器
如果容器希望外部访问能够访问到,可以通过映射容器端口到 宿主主机(端口映射),即 docker run 创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机 IP]:[容器端口]
访问容器
安装Docker时,它会自动创建三个网络。可以使用docker network ls
命令列出这些网络
docker网络相关命令
查看所有网络
docker network ls
创建网桥
docker network create darker01
查看网桥的详情信息
docker network inspect [网桥名称|网桥ID]
删除网桥
docker network rm [网桥名称|网桥ID]
# 选项
-f 强制删除正在使用的
清理(未使用的)网桥
docker network prune
# 选项
-a 清理所有的
-f 强制清理正在使用的
连接网桥
docker run --network [网桥名称] [镜像ID|镜像名称]
实例
# 列出当前的网络模式
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
419d3d6928a0 bridge bridge local
78e469f0b088 host host local
d6358ec73d1d none null local
# 创建一个网桥 darker01
[root@localhost ~]# docker network create darker01
818d2855c65d39e38f46de10e8b0839b040058bb464321bbe1553b89a9b4e20d
# 创建一个网桥 darker01
[root@localhost ~]# docker network create darker02
bbb1ce7b47473fd585708da9f0f8f917e93de953bd55532289dd6ed495e7078a
# 列出当前的网络模式
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
419d3d6928a0 bridge bridge local
e1bbe97cfe35 darker01 bridge local
6230d38b093b darker02 bridge local
78e469f0b088 host host local
d6358ec73d1d none null local
# 删除一个网桥 darker01
[root@localhost ~]# docker network rm darker01
darker01
# 列出当前的网络模式
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
419d3d6928a0 bridge bridge local
bbb1ce7b4747 darker02 bridge local
78e469f0b088 host host local
d6358ec73d1d none null local
# 清理未使用的网桥
[root@localhost ~]# docker network prune
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
darker02
# 列出当前的网络模式
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
419d3d6928a0 bridge bridge local
78e469f0b088 host host local
d6358ec73d1d none null local
Docker网络模式 | 配置 | 说明 |
---|---|---|
Host模式 | –-network=host | 容器和宿主机共享 Network namespace |
Containe模式 | --network=container:ID | 容器和另外一个容器共享 Network namespace kubernetes 中的 pod 就是多个容器共享一个 Network namespace |
None模式 | --network=none | 容器有独立的 Network namespace,但并没有对其进行任何网络设置 如分配 veth pair 和网桥连接,配置 IP 等 |
Bridge模式 | --network=bridge | 当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚 拟网桥 此主机上启动的 Docker 容器会连接到这个虚拟网桥上 虚拟网桥的工作方式和物理交换机类似 这样主机上的所有容器 就通过交换机连在了一个二层网络中(默认为该模式) |
1.Host 模式
将容器网络 与 根命令空间网络互连,这时候可以在根命令空间用回环网络访问容器
相当于Vmware中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址
如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace
容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口
但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用 host 模式的容器可以直接使用宿主机的 IP 地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行 NAT,host 最大的优势就是网络性能比较好,但是 docker host 上已经使用的端口就不能再 用了,网络的隔离性不好
docker run -dit --name centos07 --network host centos
docker run -dit --name centos08 --network host centos
docker ps
docker exec -it centos07 ip addr
docker exec -it centos08 ip addr
# 运行一个容器 centos07
[root@localhost ~]# docker run -dit --name centos07 --network host centos
dc88b6e0c40d2ca1e600973dbd2105e5fa8b2b3949cc18972ac3d8d0bff00e33
# 运行一个容器 centos08
[root@localhost ~]# docker run -dit --name centos08 --network host centos
f8b4fcf8aad6c5f6b3f740ff9f3af92f1844471df4b3f93355c59af470e59377
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8b4fcf8aad6 centos "/bin/bash" 3 seconds ago Up 3 seconds centos08
dc88b6e0c40d centos "/bin/bash" 7 seconds ago Up 6 seconds centos07
# 查看容器 centos07 的IP地址
[root@localhost ~]# docker exec -it centos07 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:70:89:d7 brd ff:ff:ff:ff:ff:ff
inet 192.168.50.103/24 brd 192.168.50.255 scope global dynamic noprefixroute eth0
valid_lft 1237sec preferred_lft 1237sec
inet 192.168.50.101/24 brd 192.168.50.255 scope global secondary noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::c725:1123:43a1:c9e4/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:70:89:e1 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.11/16 brd 172.16.255.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::9f4b:56ea:6f4d:d64a/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:9e:0f:3a:9e 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:9eff:fe0f:3a9e/64 scope link
valid_lft forever preferred_lft forever
# 查看容器 centos08 的IP地址
[root@localhost ~]# docker exec -it centos08 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:70:89:d7 brd ff:ff:ff:ff:ff:ff
inet 192.168.50.103/24 brd 192.168.50.255 scope global dynamic noprefixroute eth0
valid_lft 1231sec preferred_lft 1231sec
inet 192.168.50.101/24 brd 192.168.50.255 scope global secondary noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::c725:1123:43a1:c9e4/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:70:89:e1 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.11/16 brd 172.16.255.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::9f4b:56ea:6f4d:d64a/64 scope link noprefixroute
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:9e:0f:3a:9e 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:9eff:fe0f:3a9e/64 scope link
valid_lft forever preferred_lft forever
2.Container 模式
将一个容器的网络 共享给其它容器
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace
,而不是和宿主机共享。
新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等
同样,两个 容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信
docker run -itd --name test01 nginx
docker run -itd --name test02 --network "container:test01" nginx
docker exec -it test02 sh
docker exec -it test01 sh
# 目标容器
docker run -d --name test01 nginx
# 连接容器(会出错,因为在同一个名称空间中,端口已经被占用了)
docker run -d --name test02 --network "container:test01" nginx
docker run -dit --name centos05 centos
docker run -dit --name centos06 --network "container:centos05" centos
docker ps
docker exec -it centos05 ip addr
docker exec -it centos06 ip addr
# 运行一个容器 centos05
[root@localhost ~]# docker run -dit --name centos05 centos
496f1aa6dcb55751a63a2563a3daf549ab4c960b24ec1fab1fff5c91bad986ff
# 运行一个容器 centos06
[root@localhost ~]# docker run -dit --name centos06 --network "container:centos05" centos
2caa54c1418fb7102b72e184fb998b51e8f676c6f28e6ef34118ae854f171eba
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2caa54c1418f centos "/bin/bash" 2 seconds ago Up 2 seconds centos06
496f1aa6dcb5 centos "/bin/bash" 24 seconds ago Up 23 seconds centos05
# 进入容器 centos05 内部查看IP地址
[root@localhost ~]# docker exec -it centos05 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: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
# 进入容器 centos05 内部查看IP地址
[root@localhost ~]# docker exec -it centos06 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: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
3.None 模式
不提供网络,只提供了一个本地回环地址:127.0.0.1
使用 none 模式,Docker 容器拥有自己的 Network Namespace
,但是,并不为 Docker 容器进行任何网络配置
也就是说,这个 Docker 容器没有网卡、IP、路由等信息
需要我们自己为 Docker 容器添加网卡、配置 IP 等。 这种网络模式下容器只有 lo 回环网络,没有其他网卡
none 模式可以在容器创建时通过--network=none
来指定
这种类型的网络没有办法联网,封闭的网络能很好地保证容器的安全性
docker run -dit --name centos03 --network=none centos
docker run -dit --name centos04 --network=none centos
docker ps
docker exec -it centos03 ip addr
docker exec -it centos04 ip addr
# 运行1个容器 centos03 指定网络模式为none
[root@localhost ~]# docker run -dit --name centos03 --network=none centos
4a11b2c4af5a5c35037be74ed458aa93a2c712c5aca91c317762a51b36945671
# 运行1个容器 centos04 指定网络模式为none
[root@localhost ~]# docker run -dit --name centos04 --network=none centos
218b61d35e23f93ff3adb65af8c608345d37f6e00da7eb1b21f0afc634092392
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
218b61d35e23 centos "/bin/bash" 4 seconds ago Up 3 seconds centos04
4a11b2c4af5a centos "/bin/bash" 8 seconds ago Up 7 seconds centos03
# 查看容器 centos03 的IP地址
[root@localhost ~]# docker exec -it centos03 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
# 查看容器 centos04 的IP地址
[root@localhost ~]# docker exec -it centos04 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
[root@localhost ~]#
4.Bridge 模式(Docker默认的网络模式)
创建1个统一的网络(交换机),为与其相连的容器提供网络,通过网桥 进行网络转发
相当于Vmware中的NAT模式
当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上
虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个 二层网络中。
从 docker0 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关
在主机上创建 一对虚拟网卡 veth pair 设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 eth0(容器的网 卡),另一端放在主机中,以 vethxxx 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中
可以 通过 brctl show
命令查看。 bridge 模式是 docker 的默认网络模式,不写--net 参数,就是 bridge 模式
使用 docker run -p
时,docker 实际是在 iptables 做了 DNAT 规则,实现端口转发功能
可以使用 iptables -t nat -vnL
查看
docker run -dit --name centos01 centos
docker run -dit --name centos02 centos
docker ps
docker exec -it centos01 ip addr
docker exec -it centos02 ip addr
docker exec -it centos01 ping 172.17.0.3
docker exec -it centos01 ping 172.17.0.2
# 启动1个容器 centos01
[root@localhost ~]# docker run -dit --name centos01 centos
e354a5bfcd3f924233662149981fe874ff5bdde73227b55e16d826d286a889fd
# 启动另1个容器 centos02
[root@localhost ~]# docker run -dit --name centos02 centos
1800a8843e66233a5a1353fb1f4470fec5b5b75546d836a1aa5af7025f221f2c
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1800a8843e66 centos "/bin/bash" 3 seconds ago Up 2 seconds centos02
e354a5bfcd3f centos "/bin/bash" 7 seconds ago Up 6 seconds centos01
# 查看容器 centos01 的IP(172.17.0.2)
[root@localhost ~]# docker exec -it centos01 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
17: eth0@if18: <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
# 查看容器 centos02 的IP(172.17.0.3)
[root@localhost ~]# docker exec -it centos02 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
19: eth0@if20: <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容器centos01的IP地址
[root@localhost ~]# 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.424 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.052 ms
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 0.047/0.142/0.424/0.162 ms
# 宿主机ping容器centos02的IP地址
[root@localhost ~]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.222 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.051 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.050 ms
^C
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 0.050/0.095/0.222/0.073 ms
# 到容器centos01的内部 ping容器centos02的IP地址
[root@localhost ~]# docker exec -it centos01 bash
[root@e354a5bfcd3f /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.103 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.072 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.076 ms
^C
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 0.067/0.079/0.103/0.016 ms
# 到容器centos02的内部 ping容器centos01的IP地址
[root@localhost ~]# docker exec -it centos02 bash
[root@1800a8843e66 /]# 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.100 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.103 ms
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 0.066/0.084/0.103/0.017 ms
面试题
内部网络是隔离的(通过名称空间隔离)
Veth可以连通,但是只能1对1
网桥可以连通多个,多个网络连接用一个网桥,通过这个网桥来转发
三:探索
1.docker与容器的网络通信
docker默认是桥接模式(Bridge)
# 启动1个容器 centos01
[root@localhost ~]# docker run -dit --name centos01 centos
e354a5bfcd3f924233662149981fe874ff5bdde73227b55e16d826d286a889fd
# 启动另1个容器 centos02
[root@localhost ~]# docker run -dit --name centos02 centos
1800a8843e66233a5a1353fb1f4470fec5b5b75546d836a1aa5af7025f221f2c
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1800a8843e66 centos "/bin/bash" 3 seconds ago Up 2 seconds centos02
e354a5bfcd3f centos "/bin/bash" 7 seconds ago Up 6 seconds centos01
# 查看容器 centos01 的IP(172.17.0.2)
[root@localhost ~]# docker exec -it centos01 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
17: eth0@if18: <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
# 查看容器 centos02 的IP(172.17.0.3)
[root@localhost ~]# docker exec -it centos02 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
19: eth0@if20: <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容器centos01的IP地址
[root@localhost ~]# 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.424 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.047 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.052 ms
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 0.047/0.142/0.424/0.162 ms
# 宿主机ping容器centos02的IP地址
[root@localhost ~]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.222 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.057 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.051 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.050 ms
^C
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 0.050/0.095/0.222/0.073 ms
# 到容器centos01的内部 ping容器centos02的IP地址
[root@localhost ~]# docker exec -it centos01 bash
[root@e354a5bfcd3f /]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.103 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.072 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.076 ms
^C
--- 172.17.0.3 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 0.067/0.079/0.103/0.016 ms
# 到容器centos02的内部 ping容器centos01的IP地址
[root@localhost ~]# docker exec -it centos02 bash
[root@1800a8843e66 /]# 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.100 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.103 ms
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 6ms
rtt min/avg/max/mdev = 0.066/0.084/0.103/0.017 ms
可以在启动容器的时候,指定网络模式(--network=网络模式
)
# 运行1个容器 centos03 指定网络模式为none
[root@localhost ~]# docker run -dit --name centos03 --network=none centos
4a11b2c4af5a5c35037be74ed458aa93a2c712c5aca91c317762a51b36945671
# 运行1个容器 centos04 指定网络模式为none
[root@localhost ~]# docker run -dit --name centos04 --network=none centos
218b61d35e23f93ff3adb65af8c608345d37f6e00da7eb1b21f0afc634092392
# 查看正在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
218b61d35e23 centos "/bin/bash" 4 seconds ago Up 3 seconds centos04
4a11b2c4af5a centos "/bin/bash" 8 seconds ago Up 7 seconds centos03
# 查看容器 centos03 的IP地址
[root@localhost ~]# docker exec -it centos03 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
# 查看容器 centos04 的IP地址
[root@localhost ~]# docker exec -it centos04 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
[root@localhost ~]#
docker network create darker01
docker run -dit --name nginx01 --network darker01 nginx
docker run -dit --name redis01 --network darker01 redis
docker run -dit --name mysql01 --network darker01 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
docker run -dit --name test01 --network darker01 busybox
docker exec -it test01 ping nginx01
docker exec -it test01 ping redis01
docker exec -it test01 ping mysql01
# 创建网桥
[root@localhost ~]# docker network create darker01
5f1f52bdc16ea715894fbdc875d2dc3e838e7930c623956d7c567bd6635a2ff5
# 创建一个容器 nginx
root@localhost ~]# docker run -dit --name nginx01 --network darker01 nginx
1fa1a8787797dc55fc09861a74ac80a611fb2f6f5f1357fab387dc4276b698a2
# 创建一个容器 redis
[root@localhost ~]# docker run -dit --name redis01 --network darker01 redis
ff8bb9187258547acbe5272203c7ea2f675b313aace3479a8399bc950b22c54e
# 创建一个容器 mysql
[root@localhost ~]# docker run -dit --name mysql01 --network darker01 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
8d59729abc3d60bcb846b6c4d1799c0eb85398d028095aff3b21bae3e6233263
# 创建一个测试容器 test01
[root@localhost ~]# docker run -dit --name test01 --network darker01 busybox
ea8cee926f1b384865810b08539a8c43c7e50dd08f6cf1b8fce1195f47c234b5
# 在测试容器 test01 中 ping容器 nginx01
[root@localhost ~]# docker exec -it test01 ping nginx01
PING nginx01 (172.24.0.2): 56 data bytes
64 bytes from 172.24.0.2: seq=0 ttl=64 time=0.082 ms
64 bytes from 172.24.0.2: seq=1 ttl=64 time=0.072 ms
64 bytes from 172.24.0.2: seq=2 ttl=64 time=0.079 ms
# 在测试容器 test01 中 ping容器 redis01
[root@localhost ~]# docker exec -it test01 ping redis01
PING redis01 (172.24.0.3): 56 data bytes
64 bytes from 172.24.0.3: seq=0 ttl=64 time=0.093 ms
64 bytes from 172.24.0.3: seq=1 ttl=64 time=0.079 ms
# 在测试容器 test01 中 ping容器 mysql01
[root@localhost ~]# docker exec -it test01 ping mysql01
PING mysql01 (172.24.0.4): 56 data bytes
64 bytes from 172.24.0.4: seq=0 ttl=64 time=0.081 ms
64 bytes from 172.24.0.4: seq=1 ttl=64 time=0.081 ms