docker本身是一个进程,docker通过namespace实现进程间的视图隔离,在linux中无论线程进程最终会调用clone,我们clone一个容器进程执行/bin/bash,并传入需要隔离的类型比如:
- hostname隔离,那容器bash的hostname将与原先bansh的hostname相互独立;比如pid隔离,容器进程在容器内看将是1号进程,在外面则是另一个进程;
- network隔离,每个容器会有一个虚拟网卡,虚拟网卡对应mac地址,通过veth pair连到虚拟网桥,虚拟网桥连到物理网卡;再一个每个network有独立的tcp栈;
首先数据包到达三层路由器中的路由表找到下一跳ip,通过ARP表找到下一跳ip对应的出口mac地址,然后到二层网桥通过mac地址表(FDB表)找出出口mac地址对应的物理出口;
docker run -itd --privileged=true --name lcptest 镜像地址
docker exec -it a2a55881d351 /bin/bash
route del -net default netmask 0.0.0.0 gw 172.17.0.1
网络就不通了
cni官方提供如bridge等的plugins,但是没解决跨主机通信,容器之间的跨机通信可以通过bridge网络或overlay网络来完成,前者是每个node上建立路由表,进行相互路由,如flannel的host-gw方式;另一种方式是overlay网络,如flannel的udp,vxlan;
开源网络插件对比 :flannel是overlay network, 主要是L2(VXLAN)。 calico主要是L3,用BGP路由。cilium也主要是L3。cilium的话在每个node上有个daemonSet叫cilium-agent. 这个cilium agent是用来管理BPF的,性能强悍。查找cni等起源 ps -ef | grep kubelet
- mount隔离,不同用户看到的根目录挂载到不同的宿主机路径。当我们对根目录/ 重新挂载,那么他将会与宿主机上的根目录完全独立;chroot其实是linux里的第一个namespace隔离。而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。像docker容器里有一个完整的rootfs(根文件系统),包括/bin,/etc,/proc等,完全不同于宿主机/bin,/etc,/proc;
构想象成一棵树,目录(挂载点)就是树枝,磁盘分区就是篮子,挂载就是把篮子挂在树枝上,这样你沿着树枝就能进到篮子里获取篮子里的内容。 mount --bind /home /test 即指的/test dentry指向的inode改为/home指向的inode,即将/home(所指向的磁盘分区)挂载到了/test上;
在docker镜像出来之前,pass平台有个问题就是代码在这个物理机上跑的好好的,因为环境不一致,放到另一个物理机上就不行了,因此我们需要一个可以把所有环境都固定的不可变基础层,让代码在哪台机器上跑都一样(一次构建,处处运行)。首先我们想到的是虚拟机镜像,但是有个问题,太大了包含了操作系统,而且虚拟机之间相互隔离,文件不能写时复制。这时docker镜像横空出世,他的镜像共用底层的操作系统,并且对于文件管理引入层的概念,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs文件,那处于底部的层就可以被复用,节省大量存储空间和构建上传下载时间。如何将层联合成一个文件,用到了联合文件系统(Union File System)的能力;他解决了paas的最痛点,这也才有了后来的容器技术爆发和k8s的火爆,真正的万物起源;