前言: 容器大战
2013年前: 大战前夕——一片祥和
虚拟化技术已经深入人心,以aws与openstack为主的云平台已经非常成熟。
PaaS理念也得到了普及,cloud foundry成为当时PaaS的标准
cloud foundry吸引了包括百度、京东、华为、IBM 等一大批国内外技术厂商,开启了以开源 PaaS 为核心构建平台层服务能力的变革。“PaaS 的时代就要来了!”
PaaS公司有:Cloud foundry、Heroku、Pivotal、Red Hat
PaaS 项目被大家接纳的一个主要原因,就是它提供了一种名叫“应用托管”的能力。
docker镜像出来前,PaaS项目最核心的组件就是应用的打包和分发机制,它为每种主流编程语言都定义了一种打包格式。
用户通过指令把应用的可执行文件和启动脚本打进一个压缩包内,上传到云上的存储中,云服务通过调度器选择一个可以运行这个应用的虚拟机,通知这个机器上的Agent把应用压缩包下载下来启动,
并且会调用操作系统的Cgroups和Namespace机制为每一个应用单独创建一个称作“沙盒”的隔离环境。
但这种打包功能逐渐成为用户口中的“鸡肋”。不仅需要为每种语言、每种框架,甚至每个版本的应用维护一个打好的包,而且本地和线上的环境不一致,需要不断试错修改配置,这个过程对于用户来说很痛苦。
2013年: 容器大战——一鸣惊人
2013年3月,一家创业公司dotCloud开源了它的产品Docker,解决应用构建、分发与发布的问题,它的最大改进是引入了镜像构建。
Cloud Foundry 的首席产品经理 James Bayer 做了一次详细对比:Docker 使用的还是老技术 Cgroups 和 Namespace ,没有什么特别的新东西,掀不起什么浪。
Docker一经发布,便得到的社区的追捧,各大厂商也都相继合作,推出基于Docker的PaaS产品,它的一个小创新,却给迷茫已久的PaaS指明了前进的道路。
2013年6月:Redhat开始了基于Docker的容器平台Openshift的研发
2013年10月:RedHat正式与dotCloud合作
2013年:CoreOS成为Docker项目的贡献者,并在短时间内成为了 Docker 项目中第二重要的力量
2013年10月:Google发布了自己所用Linux容器系统的开源版本lmctfy(Let Me Container That For You)
面对Docker的强势崛起,Imctfy毫无招架之力,很快关停了该项目,并希望与Docker公司合作共同推进一个中立的容器运行时库作为Docker项目的核心依赖。
Docker拒绝了与Google的合作,不久发布了一个容器运行时库 Libcontainer。
2014年: 容器大战——三国鼎立
2014年-2015年:Docker 项目的迅速走红催生出了一个非常繁荣的“Docker 生态”。
Docker 生态创业公司们的春天,大量围绕着 Docker 项目的网络、存储、监控、CI/CD,甚至 UI 项目纷纷出台,也涌现出了很多 Rancher、Tutum 这样在开源与商业上均取得了巨大成功的创业公司。
2014年6月6日:Google发布了一个名叫 Kubernetes 项目,并早早与RedHat建立合作关系,共同维护推广。
面对着如日中天,而又野心勃勃的Docker,Google 终于坐不住了。大家一致认为:Docker作为底层技术,对终端用户影响力终究有限,容器之战最终仍旧会落在PaaS之争上。借助于RedHat在开源软件上的经验与优势,Google 强势推出了自己的杀手级产品Kubernetes。
2014年6月10日:Docker 1.0版本发布
2014年7月:Docker 收购 Orchard 掀起了收购的序幕 ,将Fig项目更名为compose
Fig 项目之所以受欢迎,在于它在开发者面前第一次提出了“容器编排”(Container Orchestration)的概念。
2014年10月15日:Azure云和Docker共同举办了Docker全球开发者大会。微软与Docker正式达成合作关系
2014年12月:CoreOS公司与Docker公司决裂,推出了自己研制的 Rocket(后来叫 rkt)容器
2014年12月:Docker公司发布Swarm项目,重新加入PaaS项目战场。三国鼎立形成
coreos公司的rkt打不开局面,Fleet集群管理项目更是少有人问津,coreos公司完败。
RedHat公司作为Docker的贡献者也与Docker公司决裂,只剩下Openshfit上一代Paas平台,被Mesos与Swarm碾压。
2015年: 容器大战——论持久战
Mesosphere 公司发布了一个名为 Marathon 的项目,它是Mesos的私有PaaS,很快就成为了 Docker Swarm 的一个有力竞争对手。
虽然不能提供像 Swarm 那样的原生 Docker API,Mesos 社区却拥有一个独特的竞争力:超大规模集群的管理经验。
2015年:3月Docker公司收购SocketPlane、Kitematic,10月收购Tutum。Docker在公有市场,企业化的私有市场都有了完善的解决方案
2015年4月8日:Google和CoreOS宣布了一个新项目Tectonic。Google投资了CoreOS $1200万,CoreOS正式投入Google阵营
2015年5月:Docker公司正式进驻中国
2015年6月:Linux基金会成立OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准
2015年6月22日:由 Docker 公司牵头,CoreOS、Google、RedHat 等公司共同宣布,Docker 公司将 Libcontainer 捐出,并改名为 RunC 项目
2015年7月:谷歌与Linux基金会以及众多行业合作伙伴准备共同建立一个云计算基金会(CNCF),Kubernetes1.0发布
2015年7月:Openshift Enterprise V3发布,结合Docker与K8s
2015年:传言微软希望40亿美元收购Docker,以摆脱对K8s的依赖,最终没成
2016年: 容器大战——背水一战
2016年:微软公司也于2016年正式推出Windows容器
2016年:Docker公司放弃现有的 Swarm 项目,将容器编排和集群管理功能全部内置到 Docker 项目当中。Docker希望利用广大的Docker用户群,实现Swarm的普及,但是适得其反,Docker变得很复杂,稳定性下降
K8s的战略则恰愉相反,整个社区推行“民主化”,从 API 到容器运行时的每一层,Kubernetes 项目都为开发者暴露出了可以扩展的插件机制,鼓励用户通过代码的方式介入到 Kubernetes 项目的每一个阶段。很快Docker的Swarm败下阵来,丢失了开发者的支持。
这一次容器社区的繁荣,是一次完全以 Kubernetes 项目为核心的“百花争鸣”。
Docker的背水一战,并没有挽回局势,败局已定。
2017年: 容器大战——清扫战场
2017年1月:Kubernetes 1.5发布,引入了Container Runtime Interface(CRI)API,支持可插拔的容器运行时
2017年3月29日:Docker将 Docker 项目的容器运行时部分 Containerd 捐赠给 CNCF 社区
2017年4月:Docker 开源社区版改名为 Moby
2017年8月10日:redhat发布 Openshift 3.6版本
2017年10月:Docker公司在自己的Docker 企业版中内置 Kubernetes 项目
2018年: 容器大战——天下一统
2018年1月30日,RedHat 宣布斥资 2.5 亿美元收购 CoreOS
2018年3月28日,Docker 公司的 CTO Solomon Hykes 宣布辞职
至此容器武林重归太平,K8S稳坐武林盟主之位。
2019年: 容器大战——最终归属
2019年5月,红帽OpenShift 4发布
2019年7月,蓝色巨人IBM官方宣布,正式完成对红帽(Red Hat)的收购,耗资340亿美元(约合人民币2340亿元)
2019年11月,Mirantis收购了Docker的企业业务和团队
Docker作为一家创业公司,通过开源社区的运作取得了巨大的成功之后,雄心勃勃,直面天下武林世家的竞争与围剿,孤身一人对抗整个云计算产业的压力,最后以惨败收场,前景堪忧。
但是也因此容器技术在短短几年间深入人心,得到了飞速的发展。
containerd
container架构
containerd 是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性,containerd 可以负责干下面这些事情:
- 管理容器的生命周期(从创建容器到销毁容器)
- 拉取/推送容器镜像
- 存储管理(管理镜像及容器数据的存储)
- 调用 runc 运行容器(与 runc 等容器运行时交互)
- 管理容器网络接口及网络

可以看到 Containerd 仍然采用标准的 C/S 架构,服务端通过 GRPC 协议提供稳定的 API,客户端通过调用服务端的 API 进行高级的操作。
总体来看 containerd 可以分为三个大块:Storage、Metadata 和 Runtime。

docker架构

- docker daemon: 简称dockerd,负责和 Docker Client 端交互,并管理 Docker 镜像和容器
- containerd: 负责集群节点上容器的生命周期管理,并向上为 Docker Daemon 提供 gRPC 接口
- containerd-shim: 一个真实运行容器的载体,每启动一个容器都会起一个新的containerd-shim的一个进程
- runc: Docker 公司按照 OCI 标准规范编写的一个操作容器的命令行工具,其前身是 libcontainer 项目
真正启动容器是通过 containerd-shim 去调用 runc 来启动容器的,runc 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程;
另外,即使在 containerd 和 dockerd 都挂掉的情况下,容器的标准 IO 和其它的文件描述符也都是可用的。
而 Docker 将容器操作都迁移到 containerd 中去是因为当前做 Swarm,想要进军 PaaS 市场,做了这个架构切分,让 Docker Daemon 专门去负责上层的封装编排,当然后面的结果我们知道 Swarm 在 Kubernetes 面前是惨败,然后 Docker 公司就把 containerd 项目捐献给了 CNCF 基金会,这个也是现在的 Docker 架构。
kubernetes在1.20开始弃用docker吗
我们知道 Kubernetes 提供了一个 CRI 的容器运行时接口,那么这个 CRI 到底是什么呢?这个其实也和 Docker 的发展密切相关的。
早期的kubernetes是直接通过代码方式调用docker api,后面 Google 就和 Red Hat 主导推出了 CRI 标准,用于将 Kubernetes 平台和特定的容器运行时(当然主要是为了干掉 Docker)解耦。
CRI(Container Runtime Interface 容器运行时接口)本质上就是 Kubernetes 定义的一组与容器运行时进行交互的接口,所以只要实现了这套接口的容器运行时都可以对接到 Kubernetes 平台上来。
不过 Kubernetes 推出 CRI 这套标准的时候还没有现在的统治地位,所以有一些容器运行时可能不会自身就去实现 CRI 接口,于是就有了 shim(垫片),一个 shim 的职责就是作为适配器将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上,其中 dockershim 就是 Kubernetes 对接 Docker 到 CRI 接口上的一个垫片实现。

之前版本的架构:

对于 containerd1.0,需要一个名为 cri-containerd 的守护进程在 Kubelet 和 containerd 之间进行操作。
然而,cri-containerd 和 containerd1.0仍然是通过 grpc 进行交互的两个不同的守护进程。循环中的额外守护进程使用户理解和部署变得更加复杂,并引入了不必要的通信开销。
新的架构:

在 containerd1.1中,CRI-containerd 守护进程现在被重构为 containerdcri 插件。CRI 插件内置在 containerd1.1中,默认启用。不像 CRI-containerd,CRI 插件通过直接的函数调用与 containerd 交互。这种新的体系结构使集成更加稳定和高效,并消除了堆栈中的另一个 grpc 跳。
1.20 版本中将 kubelet 中内置的 dockershim 代码分离,将内置的 dockershim 标记为维护模式,当然这个时候仍然还可以使用 dockershim,目标是在 1.23/1.24 版本发布没有 dockershim 的版本(代码还在,但是要默认支持开箱即用的 docker 需要自己构建 kubelet,会在某个宽限期过后从 kubelet 中删除内置的 dockershim 代码)。
containerd的使用
containerd安装
点击查看containerd安装教程
containerd常用指令
镜像操作
1 | 拉取镜像 |
容器操作
1 | 创建容器(此方式创建的并非处于Running状态,只是一个静态的容器) |
任务
1 | 启动容器 |
命名空间
1 | 查看命名空间 |
Docker 其实也是默认调用的 containerd,事实上 Docker 使用的 containerd 下面的命名空间默认是 moby,而不是 default,所以假如我们有用 docker 启动容器,那么我们也可以通过 ctr -n moby 来定位下面的容器:
1 | ctr -n moby container ls |
同样 Kubernetes 下使用的 containerd 默认命名空间是 k8s.io,所以我们可以使用 ctr -n k8s.io 来查看 Kubernetes 下面创建的容器。
更多查看帮助:
1 | ctr |