03云计算-Docker网络
网络基础
其中 Docker 使用到的与 Linux 网络有关的技术分别有:网络名称空间、Veth、Iptables、网桥、路由。
网络名称空间
为了支持网络协议栈的多个实例,Linux 在网络协议栈中引入了网络名称空间(Network Namespace),这些 独立的协议栈被隔离到不同的命名空间中。处于不同的命名空间的网络协议栈是完全隔离的,彼此之间无法进行 网络通信,就好像两个“平行宇宙”。通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环 境,而 Docker 正是利用这种网络名称空间的特性,实现了不同容器之间的网络隔离。在 Linux 的网络命名空间 内可以有自己独立的 Iptables 来转发、NAT 及 IP 包过滤等功能
Linux 的网络协议栈是十分复杂的,为了支持独立的协议栈,相关的这些全局变量都必须修改为协议栈私有。 最好的办法就是让这些全局变量成为一个 Net Namespace 变量的成员,然后为了协议栈的函数调用加入一个 Namespace 参数。这就是 Linux 网络名称空间的核心。所以的网络设备都只能属于一个网络名称空间。当然, 通常的物理网络设备只能关联到 root 这个命名空间中。虚拟网络设备则可以被创建并关联到一个给定的命名空 间中,而且可以在这些名称空间之间移动
Veth 设备
引入 Veth 设备对是为了在不同的网络名称空间之间进行通信,利用它可以直接将两个网络名称空间链接起 来。由于要连接的两个网络命名空间,所以 Veth 设备是成对出现的,很像一对以太网卡,并且中间有一根直连 的网线。既然是一对网卡,那么我们将其中一端称为另一端的 peer。在 Veth 设备的一端发送数据时,它会将数 据直接发送到另一端,并触发另一端的接收操作
veth设备操作
1.创建 Veth 设备对
#生成了两个 veth 设备, 互为对方的 pee
[root@docker ~]# ip link add veth type veth peer name veth001
[root@docker ~]# ip link show
5: veth001@veth: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 5a:9b:db:5c:50:af brd ff:ff:ff:ff:ff:ff
6: veth@veth001: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 92:e0:2d:70:48:4d brd ff:ff:ff:ff:ff:ff
2.绑定命名空间
[root@docker ~]# ip link set veth001 netns test01
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:ac:d7:3e:d0 brd ff:ff:ff:ff:ff:ff
6: veth@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
#已经查看不到 veth001,当我们进入 test01 命名空间之后,就可以查看到
[root@docker ~]# ip netns exec test01 bash
[root@docker ~]# 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
5: veth001@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 5a:9b:db:5c:50:af brd ff:ff:ff:ff:ff:ff link-netnsid 0
3.将veth分配IP
[root@docker ~]# ip netns exec test01 ip addr add 172.16.0.111/20 dev veth001
# 绑定
[root@docker ~]# ip netns exec test01 ip link set dev veth001 up
# 查看
[root@docker ~]# ip netns exec test01 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
14: veth001@if15: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state
LOWERLAYERDOWN group default qlen 1000
link/ether 96:f1:a2:1d:1d:10 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.16.0.111/20 scope global veth001
valid_lft forever preferred_lft forever
#这个时候双方就通了
4.检查对端Veth设备
[root@docker ~]# ip netns exec test01 ethtool -S veth001
NIC statistics:
peer_ifindex: 15
[root@docker ~]# ip a | grep 15
14: veth001@if15: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state
LOWERLAYERDOWN group default qlen 1000
5.为对端Veth设备设置IP
[root@docker ~]# ip addr add 172.16.0.112/20 dev veth
[root@docker ~]# ip link set dev veth down
[root@docker ~]# ip link set dev veth up
[root@docker ~]# ping 172.16.0.111
PING 172.16.0.111 (172.16.0.111) 56(84) bytes of data.
64 bytes from 172.16.0.111: icmp_seq=1 ttl=64 time=0.126 ms
64 bytes from 172.16.0.111: icmp_seq=2 ttl=64 time=0.081 ms
^C
--- 172.16.0.111 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.081/0.103/0.126/0.024 ms
网桥
Linux 可以支持多个不同的网络,它们之间能够相互通信,就需要一个网桥。 网桥是二层的虚拟网络设备, 它是把若干个网络接口“连接”起来,从而报文能够互相转发。网桥能够解析收发的报文,读取目标 MAC 地 址的信息,和自己记录的 MAC 表结合,来决定报文的转发目标网口。
Linux 可以支持多个不同的网络,它们之间能够相互通信,就需要一个网桥。 网桥是二层的虚拟网络设备, 它是把若干个网络接口“连接”起来,从而报文能够互相转发。网桥能够解析收发的报文,读取目标 MAC 地 址的信息,和自己记录的 MAC 表结合,来决定报文的转发目标网口。
Iptables
我们知道, Linux 网络协议樵非常高效,同时比较复杂 如果我们希望在数据的处理过程中对关心的数据进行 一些操作该怎么做呢? Linux 提供了一套机制来为用户实现自定义的数据包处理过程。
在 Linux 网络协议棋中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在 Linux 网络棋处理数 据包的过程中对数据包进行 些操作,例如过滤、修改、丢弃等 整个挂接点技术叫作 Netfilter lptables
Netfilter 负责在内核中执行各种挂接的规则,运行在内核模式中:而 lptables 是在用户模式下运行的进程, 负责协助维护内核中 Netfilter 的各种规则表 通过 者的配合来实现整个 Linux 网络协议战中灵活的数据包处理 机制
总结
设备 | 作用总结 |
---|---|
network namespace | 主要提供了关于网络资源的隔离,包括网络设备、IPv4 和 IPv6 协议栈、IP 路 由表、防火墙、/proc/net 目录、/sys/class/net 目录、端口(socket)等 |
linux Bridg | 功能相当于物理交换机,为连在其上的设备(容器)转发数据帧。如 docker0 网桥。 |
iptables | 主要为容器提供 NAT以及容器网络安全 |
veth pair | 两个虚拟网卡组成的数据通道。在 Docker 中,用于连接 Docker 容器和 Linux Bridge。一端在容器中作为 eth0 网卡,另一端在 Linux Bridge 中作为网桥的 一个端口 |
VMware的网络类型
# VM网络工作模式:
1.桥接模式
物理机网卡 和 虚拟机网卡桥接,让虚拟机IP和物理机IP在同一网段(上外网)
2.NAT模式
动态网络地址转换:让物理机的网卡编程路由器,虚拟机分配虚拟地址(上外网)
3.仅主机模式
让物理机成为一个局域网,所有其他虚拟机可自定义网段,但是不能上外网
Docker网络类型
Docker 使用 Linux 桥接的方式,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个容器时会 根据 Docker 网桥的网段分配给容器一个 IP 地址,称为 Container-IP,同时 Docker 网桥是每个容器的默认网关。 因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信。
Docker 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外 部网络无法通过直接 Container-IP 访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到 宿主主机(端口映射),即 docker run 创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主 机 IP]:[容器端口]访问容器
Docker网络模型 | 配置 | 说明 |
---|---|---|
host模式 | –-network=host | 容器和宿主机共享 Network namespace |
containe模式 | --network=container:ID | 容器和另外一个容器共享 Network namespace。 kubernetes 中的 pod 就是多个容器共享一个 Network namespac |
none模式 | --network=none | 容器有独立的 Network namespace,但并没有对其进行任何网 络设置,如分配 veth pair 和网桥连接,配置 IP 等 |
bridge模式 | --network=bridge | 当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚 拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。 虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器 就通过交换机连在了一个二层网络中。(默认为该模式) |
桥接模式(docker默认网络模式)
当 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 查看。
## 0.查看docker网络,网卡模式
[root@db01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
bf879512e96f bridge bridge local
43406807c060 host host local
e9f69b17eba4 none null local
## 1.使用docker镜像做网络测试
[root@db01 ~]# docker pull busybox
## 2.运行容器
[root@db01 ~]# docker run -it -d busybox /bin/sh
# 进入容器
[root@db01 ~]# docker exec -it a7ed209f3f9f /bin/sh
# 3.修改桥接网卡的IP
[root@db01 ~]#
[root@db01 ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=192.168.100.1/24
[root@db01 ~]# systemctl daemon-reload
[root@db01 ~]# systemctl restart docker
# 4.修改方法2:
[root@db01 ~]# vim /etc/docker/daemon.json
{
"bip": "192.168.200.1/24",
"registry-mirrors": ["https://pgz00k39.mirror.aliyuncs.com"]
}
host模式
# host:与宿主机共享Network 被Namespace隔离开了 --network=host性能最高
[root@db01 ~]# docker run -it --network host -d busybox /bin/sh
[root@db01 ~]# docker exec -it 9ea2e1b2d244 /bin/sh
/ # ifconfig
#容器使用宿主主机的网卡,不能跟宿主主机之间的端口冲突
Container
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。 新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个 容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
[root@db01 ~]# docker run -it -d centos:7 /bin/bash
[root@db01 ~]# docker exec -it a68ac3a931 /bin/bash
[root@a68ac3a931b4 /]# curl 127.0.0.1
curl: (7) Failed connect to 127.0.0.1:80; Connection refused
[root@db01 ~]# docker run -it --net=container:a68ac3a931b4 -d nginx
[root@db01 ~]# docker exec -it a68ac3a931 /bin/bash
[root@a68ac3a931b4 /]# curl 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
none
使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络 配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等
这种网络模式下容器只有 lo 回环网络,没有其他网卡。none 模式可以在容器创建时通过--network=none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
[root@db01 ~]# docker exec -it b39e0789 /bin/sh
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
自定义网络模式
## 创建自定义网络
docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网路名称>
[root@db01 ~]# docker network create -d bridge --subnet 172.16.2.0/24 --gateway 172.16.2.1 my_network
## 查看网络
[root@db01 ~]# docker network ls
## 使用自定义网络
[root@db01 ~]# docker run -it --network my_network -d busybox /bin/sh
## 删除自定义网络
[root@db01 ~]# docker network rm 网络ID 或者 网络名称
# 清除所有网桥 (清除除了三个默认网桥和正在使用之外和的网桥)
docker network prune
[root@docker ~]# 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
Comments | NOTHING