而 Docker 镜像功能解决了打包这个根本性问题。所谓 Docker 镜像(不是Docker容器),其实就是一个压缩包。但是这个压缩包里的内容,却不止应用的可执行文件和启动脚本。大多数 Docker 镜像是直接由一个完整操作系统的所有文件和目录构成的,所以这个压缩包里的内容跟你本地开发和测试环境用的操作系统是完全一样的。
这种打包机制直接打包了应用运行所需要的整个操作系统,所需要的所有依赖,从而保证了本地环境和云端环境的高度一致,避免了用户通过“试错”来匹配两种不同运行环境之间差异的痛苦过程。
容器其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把你的应用“装”起来的技术。这样,应用自己运行在一个独立空间中;应用与应用之间,就因为有了边界而不至于相互干扰;而被装进集装箱的应用,也可以被方便地搬来搬去。
Docker 容器的本质是一种特殊的进程。这个进程是应用所有进程的父进程。容器技术通过环境隔离和资源限制,从而为进程创造出一个沙盒。 Namespace 技术用来实现环境隔离,Cgroups 技术用来实现资源限制, rootfs 机制(也经常被称为容器镜像)为进程提供了文件系统。
形象地说,我们可以把创造沙盒比作造房子,把进程作为生活在屋子里的人。Cgroups 规定了这个房子的面积,这个人能使用多少资源(CPU、内存、网络带宽等)。Namespace 建造了这个房子的四周墙壁和屋顶,把人与外界环境隔离开来。rootfs 机制建造了这个房子的地下室, 存放着生活必需用品(应用所需文件,应用运行所需要的依赖和整个操作系统)。
l Docker容器是进程,Docker镜像是压缩包。
l Docker容器通过Docker镜像来创建。
l Docker镜像是Docker生命周期的构建和打包阶段。
l Docker容器是Docker生命周期的启动和执行阶段。
Linux提供了六种 namespace,用于不同环境的隔离,分别是:PID, Mount,UTS,IPC,Network,User。
Namespace 实际上是一种“障眼法”。比如,在某一个PID Namespace中的应用进程,看不到宿主机里真正的进程空间,也看不到其他 PID Namespace 里的具体情况,所以他会认为自己是当前容器里的第1号进程。
Mount Namespace,用于让被隔离进程只看到当前 Namespace 里的挂载点信息;Network Namespace,用于让被隔离进程看到当前 Namespace 里的网络设备和配置。
虽然进程被隔离了起来,但是它与所有其他的进程之间依然是平等的竞争关系。它自己能使用的资源(CPU,内存)随时会被其他进程(或者其他容器)占用,他自己也可能吃光资源,所以需要进行资源限制。
Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
rootfs 是用来辅助 Mount Namespace 进行文件系统的环境隔离的。rootfs 就是挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统。常见的 rootfs会包含 /bin,/dev,/etc,/home,/lib等等。
因为 Mount Namespace 修改的,是容器进程对文件系统“挂载点”的认知。但是,这也就意味着,只有在“挂载”这个操作发生之后(如果不进行挂载,容器进程看见的文件系统和宿主机是完全一样的),进程的视图才会被改变。所以,Mount Namespace 需要与 rootfs 协同运作才能为进程构建出一个完善的文件系统隔离环境。
为了便于维护和能够复用已有的基础容器镜像,Docker 公司做了个小创新,将 rootfs 变成了增量 rootfs(这样,用户只需要维护相对于基础镜像修改的增量内容),所以一层的地下室变成了多层地下室,每一层都包含着应用所需要的一部分文件。(原来是一个大地下室,如果出问题了,需要维修整个地下室。但是现在把大地下室拆分成了多层小地下室,现在只需要维修特定的一层小地下室就可以了。)在用户制作镜像时,每一步操作,都会生成一个层,也就是一个增量 rootfs。
Docker 使用 C/S 架构,Client 通过接口与 Server 进程通信实现容器的构建,运行和发布。client和server可以运行在同一台主机,也可以通过跨主机实现远程通信。
Docker由五个部分组成:Docker Client 客户端、Docker Daemon守护进程、Docker Registry仓库、Docker Container容器和 Docker Iamge镜像。
Docker Client 负责向服务端(Docker Daemon守护进程)发起请求。
Docker Registry 负责存储 Docker镜像。
Docker Daemon 负责 从 Docker Registry 下载 Docker镜像 和 通过 Docker镜像 启动 Docker 容器。
一个 Docker 容器的启动过程(即 Client 运行 docker run 命令后):
1) Docker daemon 接收到 Client请求;
2) 优先查找本地镜像,如果本地没有,Docker daemon 会从远端镜像仓库拉取所需镜像;
3) 启动 Linux Namespace 配置,设置指定的 Cgroups 参数,挂载 rootfs(容器镜像),切换进程的根目录;
4) 容器运行
容器和镜像有什么区别呢?
" A container is a runnable instance of an image."
一个容器是基于镜像创建的一个运行实例,有运行、重新启动、已暂停、已退出四种状态
Docker 网络模型
多台物理主机之间的容器是怎么通信的?
主机 A 和主机 B 的网卡都连着物理交换机的同一个vlan ,这样网桥一和网桥三就相当于在同一个物理网络中了,而容器一、容器三、容器四也在同一物理网络中了,他们之间可以相互通信,而且可以跟同一vlan 中的其他物理机器互联。
为什么有时候把旧镜像里的东西删了,镜像也没有变小呢?
rootfs 联合文件系统,它只是操作系统的所有文件和目录,并不包含内核。