Docker网络

Docker网络

Docker 本身的技术依赖于 Linux 内核虚拟化技术的发展。所以 Docker 对 Linux 内核的特性有很强的依赖。

1、网络基础

Docker 使用到的与 Linux 网络有关的技术分别有:网络名称空间、Veth、Iptables、网桥、路由。

1.1、网络名称空间

#为了支持网络协议栈的多个实例,Linux 在网络协议栈中引入了网络名称空间(Network Namespace),这些 独立的协议栈被隔离到不同的命名空间中。处于不同的命名空间的网络协议栈是完全隔离的,彼此之间无法进行 网络通信,就好像两个“平行宇宙”。通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环 境,而 Docker 正是利用这种网络名称空间的特性,实现了不同容器之间的网络隔离。在 Linux 的网络命名空间 内可以有自己独立的 Iptables 来转发、NAT 及 IP 包过滤等功能。

#Linux 的网络协议栈是十分复杂的,为了支持独立的协议栈,相关的这些全局变量都必须修改为协议栈私有。 最好的办法就是让这些全局变量成为一个 Net Namespace 变量的成员,然后为了协议栈的函数调用加入一个 Namespace 参数。这就是 Linux 网络名称空间的核心。所以的网络设备都只能属于一个网络名称空间。当然, 通常的物理网络设备只能关联到 root 这个命名空间中。虚拟网络设备则可以被创建并关联到一个给定的命名空 间中,而且可以在这些名称空间之间移动。

1.2、Veth设备

#引入 Veth 设备对是为了在不同的网络名称空间之间进行通信,利用它可以直接将两个网络名称空间链接起 来。由于要连接的两个网络命名空间,所以 Veth 设备是成对出现的,很像一对以太网卡,并且中间有一根直连 的网线。既然是一对网卡,那么我们将其中一端称为另一端的 peer。在 Veth 设备的一端发送数据时,它会将数 据直接发送到另一端,并触发另一端的接收操作。

1.3、veth操作实验

#实验目的:新建两个网络命名空间,通过veth连接两个命名空间,实现网络互通

1.3.1、创建两个网络命名空间

[root@web01 ~]# ip netns add test01
[root@web01 ~]# ip netns add test02
[root@web01 ~]# ip netns list
test02
test01

#PS:删除网络名称空间:ip netns del [网络名称空间名]

1.3.2、进入某个网络命名空间,创建一个veth对设备

#(此处为进入test01网络命名空间,创建了一对名为ddff01和ddff02的veth设备)
[root@web01 ~]# ip netns exec test01 bash
[root@web01 ~]# ip link add ddff01 type veth peer name ddff02
[root@web01 ~]# 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
2: ddff02@ddff01: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 02:28:88:d0:b2:d9 brd ff:ff:ff:ff:ff:ff
3: ddff01@ddff02: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 16:6c:3e:b6:99:a7 brd ff:ff:ff:ff:ff:ff
    
#	删除veth设备 ip link delete [veth设备名]

1.3.3、将一个veth设备绑定到目标网络命名空间,并为其分配IP

#将veth设备ddff02,绑定到网络名称空间test02
[root@web01 ~]# ip link set ddff02 netns test02

#进入网络命名空间test02
[root@web01 ~]# ip netns exec test02 bash
#查看网卡信息,发现名为ddff02的veth设备
[root@web01 ~]# 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
2: ddff02@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 02:28:88:d0:b2:d9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
#为veth设备ddff02分配IP,并重启查看网卡信息
[root@web01 ~]# ip addr add 172.16.0.102/20 dev ddff02
[root@web01 ~]# ip link set dev ddff02 down
[root@web01 ~]# ip link set dev ddff02 up
[root@web01 ~]# 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
2: ddff02@if3: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
    link/ether 02:28:88:d0:b2:d9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.0.102/20 scope global ddff02
       valid_lft forever preferred_lft forever

1.3.4、返回原网络命名空间,为veth设备分配IP

#退出当前网络命名空间,返回至test01网络命名空间
[root@web01 ~]# exit

#为veth设备ddff01分配IP并重启网卡
[root@web01 ~]# ip addr add 172.16.0.101/20 dev ddff01
[root@web01 ~]# ip link set ddff01 down
[root@web01 ~]# ip link set ddff01 up
[root@web01 ~]# 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
3: ddff01@if2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 16:6c:3e:b6:99:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.0.101/20 scope global ddff01
       valid_lft forever preferred_lft forever

1.3.5、ping另一个网络命名空间的设备IP

#查看网卡配置,确定当前处于test01网络命名空间
[root@web01 ~]# 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
3: ddff01@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 16:6c:3e:b6:99:a7 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.0.101/20 scope global ddff01
       valid_lft forever preferred_lft forever
    inet6 fe80::146c:3eff:feb6:99a7/64 scope link 
       valid_lft forever preferred_lft forever

#ping另一个网络命名空间的设备
[root@web01 ~]# ping 172.16.0.102
PING 172.16.0.102 (172.16.0.102) 56(84) bytes of data.
64 bytes from 172.16.0.102: icmp_seq=1 ttl=64 time=0.125 ms
64 bytes from 172.16.0.102: icmp_seq=2 ttl=64 time=0.054 ms
64 bytes from 172.16.0.102: icmp_seq=3 ttl=64 time=0.058 ms
#成功

1.4、网桥

#Linux 可以支持多个不同的网络,它们之间能够相互通信,就需要一个网桥。 网桥是二层的虚拟网络设备, 它是把若干个网络接口“连接”起来,从而报文能够互相转发。网桥能够解析收发的报文,读取目标 MAC 地 址的信息,和自己记录的 MAC 表结合,来决定报文的转发目标网口。

#网桥设备 brO 绑定了 eth0、 eth1 。对于网络协议械的上层来说,只看得到 brO 。因为桥接是在数据链 路层实现的 ,上层不需要关心桥接的细节,于是协议枝上层需要发送的报文被送到 brO ,网桥设备的处理代 码判断报文该被转发到 ethO 还是 ethl ,或者两者皆转发。反过来,从 ethO 或从 ethl 接收到的报文被提交 给网桥的处理代码,在这里会判断报文应该被转发、丢弃还是提交到协议枝上层。 而有时 ethl 也可能会作为 报文的源地址或目的地址 直接参与报文的发送与接收,从而绕过网桥。

1.4.1、网桥的用法

#docker network [cmd]

#列出所有网桥
[root@web01 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
bcbb2870152f   bridge    bridge    local
3bca0fdf0d9c   host      host      local
ebf068759f7f   none      null      local

#创建网桥
#docker network inspect [网桥名称]
[root@web01 test]# docker network create ddff
9efa72ec17b24f396ccc2ebd5205c50aa596eda64462b7de842020c827e65ad1
[root@web01 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
bcbb2870152f   bridge    bridge    local
9efa72ec17b2   ddff      bridge    local
3bca0fdf0d9c   host      host      local
ebf068759f7f   none      null      local

#查看网桥信息
#docker network inspect [网桥名称|网桥ID]
[root@web01 test]# docker network inspect ddff

#连接一个容器
#docker network connect [网桥名称] [容器名称]
[root@web01 test]# docker network connect ddff nginx

#断开一个连接
#docker network disconnect [网桥名称] [容器名称]
[root@web01 test]# docker network disconnect ddff nginx

#删除一个网桥
#docker network rm [网桥名称]
[root@web01 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
bcbb2870152f   bridge    bridge    local
9efa72ec17b2   ddff      bridge    local
3bca0fdf0d9c   host      host      local
ebf068759f7f   none      null      local
[root@web01 test]# docker network rm ddff
ddff
[root@web01 test]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
bcbb2870152f   bridge    bridge    local
3bca0fdf0d9c   host      host      local
ebf068759f7f   none      null      local

#清除所有的网桥
#(此命令会清除所有网桥,但不会清除默认和正在使用的网桥)
#docker network prune
[root@web01 test]# 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

1.5、iptables

#我们知道, Linux 络协议樵非常高效,同时比较复杂 如果我们希望在数据的处理过程中对关心的数据进行 一些操作该怎么做呢? Linux 提供了一套机制来为用户实现自定义的数据包处理过程。

#在 Linux 网络协议棋中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在 Linux 网络棋处理数 据包的过程中对数据包进行 些操作,例如过滤、修改、丢弃等 整个挂接点技术叫作 Netfilter lptables

#Netfilter 负责在内核中执行各种挂接的规则,运行在内核模式中:而 lptables 是在用户模式下运行的进程, 负责协助维护内核中 Netfilter 的各种规则表 通过 者的配合来实现整个 Linux 网络协议战中灵活的数据包处理机制

1.6、总结

设备 作用
network namespace 主要提供了关于网络资源的隔离,包括网络设备、IPv4 和 IPv6 协议栈、IP 路 由表、防火墙、/proc/net 目录、/sys/class/net 目录、端口(socket)等。
linux Bridge 功能相当于物理交换机,为连在其上的设备(容器)转发数据帧。如 docker0 网桥。
iptables 主要为容器提供 NAT 以及容器网络安全。
veth pair 两个虚拟网卡组成的数据通道。在 Docker 中,用于连接 Docker 容器和 LinuxBridge。一端在容器中作为 eth0 网卡,另一端在 Linux Bridge 中作为网桥的一个端口。

2、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 namespace。
none 模式 --network=none 容器有独立的Network namespace,但没有对齐进行任何网络设置,如分配veth pair和网络连接,配置IP等。
bridge 模式 --network=bridge 当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。(默认为该模式)

2.1、host模式

# 如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

# 使用 host 模式的容器可以直接使用宿主机的 IP 地址与外界通信,容器内部的服务端口也可以使用宿主机的 端口,不需要进行 NAT,host 最大的优势就是网络性能比较好,但是 docker host 上已经使用的端口就不能再 用了,网络的隔离性不好。

2.2、containe模式

# 这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。 新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个 容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

2.3、none模式

# 使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络 配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

#这种网络模式下容器只有 lo 回环网络,没有其他网卡。none 模式可以在容器创建时通过--network=none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

2.4、bridge模式

# 当 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 查看。
posted @ 2022-10-16 21:28  大胡萝卜没有须  阅读(111)  评论(0编辑  收藏  举报