Docker 网络实现
首先,要实现网络通信,机器需要至少一个网络接口(物理接口或虚拟接口)来收发数据包;此外,如果不同子网之间要进行通信,需要路由机制。
Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。 Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统看来就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要快很多。
Docker 容器网络就利用了这项技术。它在本地主机和容器内分别创建一个虚拟接口,并让它们彼此连通(这样的一对接口叫做 veth pair
)。
创建网络参数
Docker 创建一个容器的时候,会执行如下操作:
-
创建一对虚拟接口,分别放到本地主机和新容器中;
-
本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 veth65f9;
-
容器一端放到新容器中,并修改名字作为 eth0,这个接口只在容器的名字空间可见;
-
从网桥可用地址段中获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 veth65f9。
完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。
可以在 docker run
的时候通过 --net
参数来指定容器的网络配置,有4个可选值:
-
--net=bridge
这个是默认值,连接到默认的网桥。 -
--net=host
告诉 Docker 不要将容器网络放到隔离的名字空间中,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以跟主机其 它 root 进程一样可以打开低范围的端口,可以访问本地网络服务比如 D-bus,还可以让容器做一些影响整个主机系统的事情,比如重启主机。因此使用这个选项的时候要非常小心。如果进一步的使用--privileged=true
,容器会被允许直接配置主机的网络堆栈。 -
--net=container:NAME_or_ID
让 Docker 将新建容器的进程放到一个已存在容器的网络栈中,新容器进程有自己的文件系统、进程列表和资源限制,但会和已存在的容器共享 IP 地址和端口等网络资源,两者进程可以直接通过lo
环回接口通信。 -
--net=none
让 Docker 将新容器放到隔离的网络栈中,但是不进行网络配置。之后,用户可以自己进行配置。
四种单节点网络模式
1、bridge 模式
Docker 容器默认使用 bridge 模式的网络。其特点如下:
-
使用一个 linux bridge,默认为 docker0
-
使用 veth 对,一头在容器的网络 namespace 中,一头在 docker0 上
-
该模式下Docker Container不具有一个公有IP,因为宿主机的IP地址与veth pair的 IP地址不在同一个网段内
-
Docker采用 NAT 方式,将容器内部的服务监听的端口与宿主机的某一个端口port 进行“绑定”,使得宿主机以外的世界可以主动将网络报文发送至容器内部
-
外界访问容器内的服务时,需要访问宿主机的 IP 以及宿主机的端口 port
-
NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。
-
容器拥有独立、隔离的网络栈;让容器和宿主机以外的世界通过NAT建立通信
2、Host 模式
定义:
Host 模式并没有为容器创建一个隔离的网络环境。而之所以称之为host模式,是因为该模式下的 Docker 容器会和 host 宿主机共享同一个网络 namespace,故 Docker Container可以和宿主机一样,使用宿主机的eth0,实现和外界的通信。换言之,Docker Container的 IP 地址即为宿主机 eth0 的 IP 地址。其特点包括:
-
这种模式下的容器没有隔离的 network namespace
-
容器的 IP 地址同 Docker host 的 IP 地址
-
需要注意容器中服务的端口号不能与 Docker host 上已经使用的端口号相冲突
-
host 模式能够和其它模式共存
3、container 模式
定义:
Container 网络模式是 Docker 中一种较为特别的网络的模式。处于这个模式下的 Docker 容器会共享其他容器的网络环境,因此,至少这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此之外其他的容器存在网络隔离。
4、none 模式
定义:
网络模式为 none,即不为 Docker 容器构造任何网络环境。一旦Docker 容器采用了none 网络模式,那么容器内部就只能使用loopback网络设备,不会再有其他的网络资源。Docker Container的none网络模式意味着不给该容器创建任何网络环境,容器只能使用127.0.0.1的本机网络。
实验:
rhel7.3 172.25.12.250(物理机)
启动一个容器,不指定时,容器默认使用 bridge 模式
[root@foundation12 ~]# docker run -it --name web ubuntu
查看物理机
物理机桥接情况
设定为none 模式
[root@foundation12 ~]# docker run -it --name vm1 --net none ubuntu
查看PID:
[root@foundation12 ~]# docker inspect -f '{{.State.Pid}}' vm1
虚拟化网络都是基于netns 实现,netns 可以创建一个完全隔离的新网络环境,这个环境包括一个独立的网卡空间,路由表,ARP表,ip地址表,iptables等。总之,与网络有关的组件都是独立的。
ip [ OPTIONS ] netns { COMMAND | help }
ip netns list - show all of the named network namespaces 列出所有名称空间
ip netns add NETNSNAME - create a new named network namespace 创建一个新的名称空间
ip netns delete NETNSNAME - delete the name of a network namespace 删除一个名称空间
ip netns exec NETNSNAME cmd ... - Run cmd in the named network namespace 在网络名称空间中执行系统命令
eg:
[root@foundation12 netns]# ip link add name veth0 type veth peer name veth1 添加网口到namespace(创建端口对)
在当前namespace可以看到veth0和veth1
[root@foundation12 ~]# ip link list 查看端口对
[root@foundation12 netns]# brctl addif docker0 veth0 将veth0加入docker0这个网桥
默认网桥都是down的,置为up状态
[root@foundation12 netns]# ip addr
[root@foundation12 netns]# ip link set up veth0
[root@foundation12 netns]# ip link set up veth1
[root@foundation12 netns]# ip link set veth1 netns 4943 增加端口到namespace
查看net namespace
修改名字,添加IP和网关
[root@foundation12 netns]# ip netns exec 4943 ip link set veth1 name eth0
[root@foundation12 netns]# ip netns exec 4943 ip link set up eth0
[root@foundation12 netns]# ip netns exec 4943 ip addr add 172.17.0.100/24 dev eth0
[root@foundation12 netns]# ip netns exec 4943 ip route add default via 172.17.0.1
如下效果,none网络变得可以通信