Docker采用c/s架构,Docker守护进程( Daemon )作为服务端,接受来自客户端(命令行)的请求,并处理这些请求(创建、运行、分发容器) 。客户端和服务端既可以运行在一个机器上, 也可通过 socket 或者RESTful API来进行通信。
命名空间保证了容器之间彼此互不影响,通过不同资源的命名空间实现了资源的隔离。
控制组(cgroups)是 Linux 内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争。控制组可以提供对容器的内存、CPU、磁盘IO等资源的限制和审计管理。
联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备。Docker 中的网络接口默认都是虚拟的接口。虚拟接口的优势之一是转发效率较高。Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统看来就像是一个正常的以太网卡,只是它不需要真正同外部网络设备通信,速度要快很多。
Docker 创建一个容器的时候,会执行如下操作:
在 docker run 的时候通过 --net 参数来指定容器的网络配置,有4个可选值:
首先,启动一个/bin/bash容器, 指定--net=none参数。
- $ docker run -i -t --rm --net=none base /bin/bash
- root@63f36fc01b5f:/#
在本地主机查找容器的进程 id, 并为它创建网络命名空间。
- $ docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
- 2778
-
- $ pid=2778
- $ sudo mkdir -p /var/run/netns
- $ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
检查桥接网卡的 IP 和子网掩码信息。
- $ ip addr show docker0
- 21: docker0: ...
- inet 172.17.42.1/16 scope global docker0
- ...
创建一对“veth pair”接口 A 和 B,绑定 A 到网桥 docker0 ,并启用它。
- $ sudo ip link add A type veth peer name B
- $ sudo brctl addif docker0 A
- $ sudo ip link set A up
将B放到容器的网络命名空间, 命名为 eth0, 启动它并配置一个可用 IP( 桥接网段)和默认网关。
- $ sudo ip link set B netns $pid
- $ sudo ip netns exec $pid ip link set dev B name eth0
- $ sudo ip netns exec $pid ip link set eth0 up
- $ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
- $ sudo ip netns exec $pid ip route add default via 172.17.42.1