docker核心技术以及实现原理
设计docker核心技术以及底层实现原理,比如命名空间、CGroups,存储驱动,容器网络
docker核心技术的支撑是什么
- namespaces
- cGroups(control groups)
- union filesystem
docker出现的原因
Docker的出现一定是因为目前的后端在开发和运维阶段确实需要一种虚拟化技术解决开发环境和生产环境一致的问题,通过Docker我们可以将程序运行的环境也纳入到版本控制中,排除因为环境造成不同运行结果的可能。
Namespaces
命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。Docker就是通过Linux的Namespaces对不同的容器实现了隔离。
网络
Docker虽然可以通过命名空间创建一个隔离的网络环境,但是Docker中的服务任然需要与外界相连才能发挥作用,
每一个使用docker run启动的容器其实都具有单独的网络命名空间,Docker为我们提供了四种不同的网络模式:
- Host
- Container
- None
- Bridge(默认)
docker之bridge网桥模式
docker网桥模式下的作用
- 分配隔离的网络命名空间
- 为所有的容器设置IP地址
- docker服务启动后在宿主机上创建虚拟网桥docker0,随后在该主机上启动的全部容器在默认情况下都与该网桥相连
启动容器网桥模式下,创建网络的过程:
- 首先创建一对虚拟网卡,两个虚拟网卡组成数据通道,其中一个放在创建的容器中,会加入到名为docker0网桥中。
查看当前网桥的接口
wangfeng@wangfeng-PC:~$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02423bdf4596 no vethd7f45fd
wangfeng@wangfeng-PC:~$
- docker0为每一个容器分配一个新的ip地址并讲docker0的IP地址设置为默认的网关。网桥docker0通过iptables中的配置与宿主机上的网卡相连,所有符合条件的请求都会通过iptables转发到docekr0并由网桥分发给对应的机器。
查看docker容器内部的网关
# 查看路由表也就可以看到网关了
/ # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 176.17.0.1 0.0.0.0 UG 0 0 0 eth0
176.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
/ #
# 下面命令也可以看到
#
/ # ip route show
default via 176.17.0.1 dev eth0
176.17.0.0/16 dev eth0 src 176.17.0.2
/ #
CGroups
Namespace命名空间提供的是文件系统、网络、与宿主机之间的进程的相互隔离,而CGroups提供的是物理资源上的隔离,比如CPU、内存、磁盘IO、网络带宽。
UnionFS
Linux 的命名空间和控制组分别解决了不同资源隔离的问题,前者解决了进程、网络以及文件系统的隔离,后者实现了 CPU、内存等资源的隔离,但是在 Docker 中还有另一个非常重要的问题需要解决 - 也就是镜像。
Docker 镜像其实本质就是一个压缩包,我们可以使用下面的命令将一个 Docker 镜像中的文件导出:
wangfeng@wangfeng-PC:~/docker$ pwd
/home/wangfeng/docker
wangfeng@wangfeng-PC:~/docker$ ll
总用量 4
drwxr-xr-x 12 wangfeng wangfeng 4096 8月 19 15:09 rootfs
wangfeng@wangfeng-PC:~/docker$ docker export $(docker create busybox) | tar -C rootfs -xvf -
# 你可以看到这个 busybox 镜像中的目录结构与 Linux 操作系统的根目录中的内容并没有太多的区别,可以说 Docker 镜像就是一个文件。
wangfeng@wangfeng-PC:~/docker$ ls rootfs/
bin dev etc home proc root sys tmp usr var
wangfeng@wangfeng-PC:~/docker$
存储驱动
Docker 中的每一个镜像都是由一系列只读的层组成的,Dockerfile 中的每一个命令都会在已有的只读层上创建一个新的层。
当镜像被 docker run 命令创建时就会在镜像的最上层添加一个可写的层,也就是容器层,所有对于运行时容器的修改其实都是对这个容器读写层的修改。
容器和镜像的区别就在于,所有的镜像都是只读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器。
不同的存储驱动在存储镜像和容器文件时也有着完全不同的实现,常见docker存储驱动有:
- devicemapper
- overlay2
# 查看当前系统Docker使用了哪种存储驱动
root@wangfeng-PC:/var/lib/docker/containers# docker info | grep Storage
Storage Driver: overlay2
root@wangfeng-PC:/var/lib/docker/containers#