干货!如何手动运行一个容器(一)

2022-06-23

54

作者:行云创新 周朋



每个刚涉足容器的人都会对容器的实现有所困惑,容器是如何实现的,是如何复用宿主机的资源,并且实现资源隔离的;下面会用shell创建一个容器,为大家展示一个容器的创建过程。



1.创建镜像


我们一般用 docker pull 从远端的镜像仓库获得镜像,镜像里面包含的是一个根文件系统,那如何通过一个镜像,手动创建一个容器呢?


首先,我们需要先获取一个镜像。



或者可以从 alpine 官方网站获取`mini rootfs filesystem`的 tarball,同样是一个文件系统,并没有明显差异。



2.启动容器


刚刚我们已经将文件系统解压到本地,现在我们可以使用本地的文件系统"启动"一个容器了,那如何启动一个简单的容器呢?


使用 chroot,chroot 主要是将程序运行环境切换到指定目录,当我们切换过去之后,在应用程序内,根目录"/"的位置变成了我们指定的目录了,所以这就是为什么我们需要在"1"中创建一个根文件系统。



好了,现在一个简单的容器已经创建完成了,我们可以体验一下我们的"容器"。



以上,你应该能理解一个容器的文件系统在宿主机上是如何存在的,当然,我们在使用 docker 的时候,当前容器的根文件系统会经过`overlay2` storage driver 一系列复杂的操作挂载到本机;但是那只是为了提高磁盘的利用率和获取容器镜像效率等等原因做的特殊优化,并不会影响容器文件系统的本质。


但是我们发现可以查看这个容器的网络(和宿主机共享),目录;但是不能查看进程,内存,磁盘信息,原因是是因为/proc是空的,/proc文件系统提供对系统中每个活动进程和线程状态的访问,我们必须要手动把它挂载到我们的容器里面。



然后我们能发现,能看到宿主机所有的进程、内存,磁盘信息,这不太像我们了解的容器,因为他的资源还没有隔离,资源隔离需要利用namespace和cgroup,这依然是Linux操作系统提供的能力。


3.利用namespace隔离进程资源


namespace 是 Linux kernel 提供的基本能力,它能对内核资源进行区分,让不同的进程的资源彼此隔离,该功能通过为一组资源和进程使用相同的命名空间来工作,但这些命名空间引用不同的资源。资源可能存在于多个空间中。此类资源的示例包括进程 ID、主机名、用户 ID、文件名以及与网络访问和进程间通信相关的一些名称。


我们将用 unshare 为我们的进程创建一个新的 namespace,并和宿主机的资源隔离。



好了,我们再次挂载文件系统/proc,查看这个容器。



他已经像是我们认知上的容器了,但是只是表面上看起来像;它只根据PID隔离了网络资源,没有隔离宿主机CPU、memory等资源,也并不能实现容器的网络通信,当然我们只是简单验证容器的创建过程,我们会在后面讲述Cgroup隔离资源的原理,但是我们并不会真的操作它,就像我们没有用`overlay2` storage driver挂载容器的跟文件系统一样,这些东西用shell命令做起来很繁琐,缺失它们,但是并不影响我们理解容器创建的过程。


以上一个简单的容器就创建完成了,虽然如上所述,它并没有隔离物理资源,但是只是想告诉你一个事实,容器的存在和虚拟化是有本质差异的,它本质是复用了Linux本身的各种能力创建的。


限于篇幅,剩下的内容我们将在后续的文章中更新。

更多技术干货,从这里获取


技术交流
我们建了一个云原生技术交流群,其中有来自Oracle、Citrix、华为、腾讯等国内外云计算专家,立即扫码,拉你进群。目前已有1000+开发者加入我们......
云原生厂商 云原生技术服务商
在云原生时代,行云创新致力于通过赋能开发者,实现企业快速迭代与交付,大幅提升创新效率。
免费试用