Docker起源与容器技术原理

Docker起源

在说Docker之前先说一下“容器”,“容器”这个概念从来就不是什么新鲜的东西,也不是Docker公司发明的。即使在当时最热门的PaaS项目Cloud Foundry中,容器也只是其中最底层、最没人关注的一部分。

Docker起源与容器技术原理

那正好以Cloud Foundry为例,来解说一下PasS技术。PasS之所以被大家接受是因为它提供了一种“应用托管”的能力。在当时,虚拟机和云计算已经是比较普遍的技术和服务了,主流用户普遍的用法就是租一批AWS或者OpenStack的虚拟机,然后像之前托管物理机那样,使用脚本或者手工部署应用。部署过程难免会碰到云主机与本地环境不一致的问题,所以当时云厂商们比的就是谁能带来更好的“上云”体验。而PaaS开源项目的出现就是当时解决这个问题的最佳方案。


只需一条命令就能把本地应用部署到云上,像Cloud Foundry 这样的PasS项目最核心的组件就是一套应用的打包和分发机制。由于在虚拟机上启动很多个应用,会调用操作系统的Cgroups和Namespace机制为每个应用单独创建一个称作“沙盒”的隔离环境,然后在”沙盒”中启动这些应用进程。这样就实现了多个应用互不干涉的在虚拟机运行起来的目的。

cf push "我的应用"

这正是PasS的核心能力,运行应用的“沙盒”就是所谓的“容器”。

事实上,Docker项目确实与Cloud Foundry的“沙盒”大部分功能和实现原理都是一致的,可以偏偏就是剩下的小部分不一致,成了Docker项目迅速发展的不二法宝。

Docker起源与容器技术原理

这个功能,就是Docker镜像。Docker给PasS前辈们来了一次“降维打击”,其实是提供了一种非常便利的打包机制。这种机制直接打包了应用运行所需的整个操作系统,从而保证了本地和云端高度一致。对开发者们来说,带来了前所未有的快感。人们自然用脚投票,直接宣告了PasS时代的结束。

Docker起源与容器技术原理

容器编排”战争”

虽然Docker项目在开发者中一日千里,但是Docker公司还是有些担忧的。他们明白用户最终要部署的是代码、是项目甚至的数据库。只有那些能为用户提供平台层能力的工具,才会真正成为开发者关心和愿意付费的产品。而Docker只是底层容器工具。

Docker起源与容器技术原理

在2014年12月,Docker公司随即发布了Swarm,Swarm最大的亮点就是完全可以使用Docker原本的容器管理API来完成集群管理。

docker run -H "Swarm集群API地址" "我的容器"

Kubernetes诞生

在2014年6月,基础设施领域的领先者Google公司突然发力,正式宣告了一个名叫Kubernates项目诞生。这个项目如同当年Docker项目的横空出世一样,再一次改变了容器领域的格局。

Docker起源与容器技术原理

而Kubernetes开始整个社区”民主化“架构,从API到容器运行时的每一层,Kubernetes项目都为开发者暴露出可以扩展的插件机制,鼓励用户通过代码的方式介入到Kubernates项目的每一个阶段。很快整个容器社区催生出大量、基于Kubernetes API和扩展接口二次创作比如:

  • 热度很高的微服务治理项目 Istio;
  • 被广泛采用的有状态应用部署框架 Operator;
  • 还有想Rook 这样的开源创业项目;

不同于PasS化的路线,这是一次容器社区的繁荣,以Kubernates为核心的。

Docker话语权的分割-CNCF

由于Docker公司对Docker项目话语权比较大,容器领域的其他几位玩家开始商议如何”切割“Docker公司的话语权,而”切割“的手段就是成立一个中立的基金会,那就是名为CNCF的基金会。

Docker起源与容器技术原理

这个基金会目的很好理解,它希望以Kubernetes项目为基础,安装独立基金会方式运营的平台级社区,来对抗Docker公司为核心的容器商业生态。

Docker起源与容器技术原理

在囊括了容器监控事实标准的Prometheus项目之后,CNCF社区迅速在成员项目中添加Fluentd、OpenTracing、CNI等一系列容器生态知名工具和项目。

Linux容器技术

容器的本质是一种特殊的进程,容器的核心就是通过约束和修改进程的动态表现,从而创造出一个“边界”世界。对于Docker等大多数容器来说,Linux的Namespace技术用来修改进程视图的主要方法,Linux的Cgroups技术则是用来制造约束的主要手段。

Docker起源与容器技术原理

让我们进入docker容器世界看看

docker run -it 容器名称 /bin/sh

or

docker exec -it 容器id /bin/sh

ps可以看到一个编号为1的进程(PID=1),而在这个容器中看到只有一个进程在运行,以及我们刚刚执行的ps,都已经被Docker隔离在一个与宿主机完全不同的世界当中。这到底是如何做到的呢?

原本我们系统执行运行一个业务进程,系统都分配一个进程编号,比如PID=100,这个进程编号是系统唯一的,就像是工号一样,然后Docker把PID=100的进程运行在容器当中,这时候Docker给PID=100的进程施了一个“障眼法”,让它看不到前面的其他进程,让它误任务自己是PID=1的进程。这种机制其实就是被隔离的空间做了手脚,实际上他们在宿主机上系统进程还是原来的PID=100。这种技术就是Linux的Namespace机制。

Namespace

Namespace的使用方式:其实只是Linux创建新进程的可选参数,我们知道Linux系统中创建进程是调用clone(),我们在参数中指定CLONE_NEWPID参数,这是新创建的这个进程会看到一个全新的进程空间,在这个进程空间里它的PID是1,之所以看到是因为这是一个“障眼法”,在宿主机进程空间这个进程还是PID=100。

除了PID Namespace,Linux操作系统还提供Mount、UTS、IPC、Network和User这些 Namespace,用来对各种不同进程上下文进行“障眼法”。这就是容器让你“看见”的基本原理。

所以DOcker容器这个听起来玄而又玄的概念,实际上是在创建容器进程时,指定了这个进程所需要启动的一组Namespace参数(资源、文件、设备、网络)。对于宿主和其他容器,它完全“看”不到。

所以说,容器其实就是一种特殊进程而已。

Cgroups

Linux Cgroups 的全称是Linux Control Group,它最主要的作用就是限制一个进程组能够使用的资源上线,包括CPU、内存、磁盘、网络带宽等待。此外,Cgroups还能够对进程进行优先设置、审计以及进程挂起和恢复等操作。

可以看到/sys/fs/cgroup下有很多诸如cpu、mem、cpuset子目录,这些都被Cgroups进行限制的资源种类。

ls /sys/fs/cgroup/cpu

根目录

为了能够让容器根目录看起来“真实”,我们一般会在这个容器的根目录挂载一个完整操作系统的文件系统,比如:Ubuntu16.04的ISO,这样容器启动后,我们在容器里通过执行”ls /”查看根目录下的内容,就是Ubuntu16.04的所有目录和文件。而你进入容器之后执行/bin/bash,就是/bin目录下的可执行文件,与宿主机的/bin/bash完全不同。

现在,可以理解对于Docker来说,最核心的原理实际上是未用户进程创建:

  1. Linux Namespace,让你可“看见”;
  2. 设置Cgroups参数,然你被“限制”;
  3. 挂载进程根目录(Change Root);
参考

https://docs.docker.com/get-started/overview/ https://www.redhat.com/zh/topics/containers/whats-a-linux-container https://draveness.me/understanding-kubernetes/ https://www.redhat.com/zh/topics/containers/kubernetes-architecture https://minikube.sigs.k8s.io/docs/start/ http://jartto.wang/2020/07/15/start-k8s/


原文始发于微信公众号(程序猿阿南):Docker起源与容器技术原理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/22343.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!