Docker:OpenCamp 训练营 x CNB 平台 —— Learning Docker
壹 · 从物理机到容器革命
物理机时代
在以前,要上线一款应用,需要找运维团队申请资源。如果没有资源,要先去采购一些服务器,然后上架到机架上去,插上网线,插上磁盘,通上电,装上操作系统。
那个时代运维团队和开发团队是有界限的,开发工程师是不能登到服务器上去操作的,因此需要与运维团队做约定,在服务器上安装需要的环境、依赖等等。
如果应用比较复杂,比如前端有 node,后端有 java,最好的方式是每台机器部署独立的应用,互不打扰。按这样部署完网站上线之后,如果网站的用户量很好,服务器灯打满了是最好的。
但是如果用户量并没有达到理想的状态,服务器的资源使用率就非常低,造成成本上的浪费。这个时候一个方法是持续推广应用,另一个方法是合并,也就是把前端服务、后端服务合并到一起,让多个服务共同跑在一台机器上,这样也能提高服务器资源使用率。但是这样可能出现的一个问题是不同服务的依赖库会有冲突,需要设计一个很复杂的策略来把服务迁移到同一个机子上去。
虚拟机时代
在虚拟化技术出现之后,解决了物理机时代的一些痛点(硬件资源分配问题)。有了 KVM/XEN,我们可以把一台物理机资源层面切割成更小的力度,可以按需去索取服务器的配置(升配降配)。也是在这个时代,虚拟化催生了公有云。单台虚拟机通常用于测试,但是如果把多台物理机组合到一起,形成一个集群,就可以对用户提供一个购买资源的入口,这就是公有云。
这个阶段的一个典型架构是在一台机器上通过内核去做虚拟化,通常会有一个虚拟化层(VMware / KVM / XEN),在一台物理机上去虚出多个虚拟机,每个虚拟机就是一个独立的操作系统,有自己的内核,在内核之上再去叠加自己想要的依赖包,最终把应用部署起来。
在这个时候,DevOps 这个概念也流行起来了,从资源的开通、资源的配置到应用的配置,都可以通过代码的方式实现,可以调公有云的接口去把服务开通,然后调他们的一些功能特性,比如做一个虚拟机模板,把想要的操作系统打包进去,然后再去叠加一些带包的工具,批量部署你的应用,完全自动化掉。
容器时代
为什么需要容器呢?—— 其实源自于 linux 的内核层面,有一些关键的点催生了docker,即 namespace、cgroup 和 unionFS。
虽然在虚拟化时代大家都在用 DevOps 去服务自己的业务,但是这个过程还可以再去加快一点,我们为什么要在一台机器上再去虚出每个虚拟机都去跑自己的内核呢?内核也是需要消耗资源的,而且虚拟机操作系统的镜像文件也很大,拉下来去部署这个效率是有优化空间的,如果遇到双11这种要去大规模做升降配,很多台慢,影响就比较大了。
因此有一些团队在探索一个事情:把虚拟机内核这层取消掉,在内核之上构建一个虚拟化的环境,让应用独享一个空间,也可以做资源隔离,互不打扰。
docker 不仅做了环境隔离这套机制,他还有一个更大的贡献是做了一个 hub,大家可以去分享做好的软件。这个时候的架构就变成了:硬件之上还是内核,但内核之上就不需要虚拟化引擎了,直接起一个容器引擎,容器引擎之上再去起容器,每个容器都是独立的,有自己的环境、依赖包,部署自己的 app。
贰 · docker 依赖的底层技术
namespace、cgroups、unionFS 构成了容器的基石。docker 的核心并不是这三个,这三个技术是 linux 内核本身固有的东西,docker 只是把这三样东西做了一个封装,让用户去使用这三样东西的门槛降得很低。
在 docker 出来之前,一般需要手工调用linux内核的这些接口,创建一个 namespace,创建一个 cgroup 资源组,再去叠加一个 unionFS,最终才能启动一个容器。docker 是对这三个内核技术的封装。
namespace
在 linux 的内核里面可以创建一个子的命名空间,这个命名空间可以涵盖一些东西,比如用户系统、挂载点、用户名、进程 scope、网络管理、IPC,把这些东西每个都做成 namespace 之后,就可以起一个进程。这个进程虽然是跑在宿主机的内核之上,但是它是有自己的命名空间的。虽然宿主机可以同时管理到这两个 namespace,但是两个 namespace 之间是互相独立的,这个就为容器隔离奠定了基础。
容器本身就是一个 linux 进程,只是被隔离的一个特殊的进程。
cgroups
隔离了环境之后,还要隔离一个东西就是资源,要保证每个容器的资源不能超。如果一个容器资源超的很厉害的话,就会影响其他容器。所以必须有一个能够限制容器资源使用的一个东西—— cgroup,可以通过创建一个又一个的 cgroup 组,这个组里面可以设置一些策略,比如内存使用多少,cpu 使用多少,网络使用多少,IO 使用多少,然后把进程添加到组里面,这样就会受 cgroup 的管理了,不会再去跳出资源限制。
unionFS
该以什么样的环境去跑这个进程呢?希望是把环境也做到进程里面去,携带程序运行的所有环境的一个进程,由此引出 rootfs,是一个操作系统所包含的文件、配置和目录,但是不包括操作系统内核。unionFS 是一个分层的文件系统,可以把多个物理目录挂载到同一个逻辑目录下,因此可以按层去做缓存。有了分层之后,就可以把发行版这一块做成一层,把语言/依赖包做成一层,这样如果有多个容器的话,同一层的东西只需要下载一次,对真正变化的东西再去做下载。
叁 · docker 基础
查看 docker 版本
docker version
docker 是一个 CS 架构,即Client+Server。我们平时使用的 docker 客户端就相当于 client,他会有一个 docker 引擎(server),引擎会去帮我们做镜像构建、拉取镜像启动容器这些事情。
client和server是如何交互的?在linux里面两个进程交互的方式主要有:通过管道、共享内存、socket等,docker的CS交互用的是socket,客户端通过socket文件去跟docker的引擎做交互(ls -a /var/run/docker.sock)。
待整理、、、