searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

容器基本原理探析

2023-06-27 08:03:21
7
0

提到“容器”,大家应该都不陌生,不是什么特别新鲜的技术了,受众也越来越广了,但是会用就真的理解吗?以下几个相关问题你真的能做到了然于胸吗?

  1. “容器”是怎么把自己隔离开的呐?
  2. “容器”能使用宿主机的全部资源吗?
  3. “容器”有自己的文件系统吗?
  4. “容器”与虚拟机有什么区别?

引言

要想真正理解容器,就必须先了解其发展历程,因为容器也是操作系统功能逐渐强大过程中催生的神器。这里我们只关注几个关键技术时间节点。

时间 事件 作用
1979年UNIX V7 引入chroot系统调用 修改进程根目录,隔离每个进程的文件访问
2006年Google 引入Process Container(CGroups) 对进程的资源(CPU, memory, 磁盘, network)进行限制&隔离
2008年LXC LinuX Containers 使用cgroups和Linux namespaces实现第一个Linux容器
2013年Docker LibContainer 容器镜像完善了容器管理生态,开始普及
2018年Kubernetes 开放&规范 容器化如火如荼

现在,我们知道了几个关键名词了,那么他们是怎么协作产生容器的呐,为了清晰些,先放个大体的关系图在这里,然后我们下面分开探讨下。

一、容器是一种特殊的进程

容器是通过 Linux 的 NamespaceCgroup 等系统控制实现的一套隔离环境。运行中的容器就是一组开启了多个 Namespace(PID/Mount/Network等)进行隔离 的特殊应用进程,然后通过 Cgroups 来控制这个特殊进程对宿主机各个资源(CPU/内存等)的使用限制。

1. NAMESPACE 隔离

来看下我们部署的一个demo应用。

你没看错它的进程pid是1,这时你会想这是什么神仙进程,pid是1的不一般都是系统级的初始化进程吗?这正是容器的隔离环境使出的“一叶障目”的伎俩。 其实你看到的只是容器想让你看到的,实际上在其宿主机的操作系统里,这个demo进程只是一个再普通不过的进程。这里记得这个真实的pid,后续我们还会再次看到它。

这便是通过 Linux 的 PID Namespace 来实现的,我们都知道创建子进程可以调用clone系统调用,要实现PID Namespace的隔离,只需要在进行clone系统调用时加上CLONE_NEWPID参数即可。

int container_pid = clone(container_main, container_stack+STACK_IZE, CLONE_NEWPID | SIGCHLD, NULL); 

这样创建出来的进程就实现了Pid Namespace的隔离,我们看到的进程信息就与宿主机完全分隔开了。 类似的,可以通过clone时增加相应的 Namespace 控制参数进行“隔离”,如CLONE_NEWNET控制Network Namespace、CLONE_NEWNS控制Mount Namesapce等。感兴趣的可以自己试一下。

2. CGROUP 限制

Linux Cgroups是用来限制、控制和分离一个进程组的资源的,包括 CPU、内存、磁盘、网络带宽等等。

我们可以通过'mount -t cgroup'命令在机器的/sys/fs/cgroup目录下一探究竟。

可以看到操作系统的相关资源限制都在这里了,它们是以文件系统的方式存在的。具体到某种类型的资源比如CPU,进入cpu子目录就可以看到详细的控制维度。接下来我们一起来看下我们创建的demo应用的相关限制。

我们会发现/sys/fs/cgroup/cpu下有个docker文件夹,后面的一串数字是容器id,可以通过'docker ps'进行查看。这个目录下面有很多cpu相关的限制维度,具体的含义大家可以自行搜索更准确些,注意最下面有个tasks文件,它里面存储的正是我们的应用进程在宿主机里真实的进程PID,通过控制这个进程的相关资源来对容器进行资源限制。

比如我们要控制应用程序只能使用宿主机的30%的 CPU,如果超了就异常退出,避免单个容器的一个死循环之类的神坑拖垮整个宿主机,那么我们要怎么控制呐?参考如下方法通过控制 cpu.cfs_quota_us 和 cpu.cfs_peroid_us 将相应的限制写入控制文件即可。 cgroup_cpu

二、容器有自己的文件系统吗?

正如上面通过 clone 系统调用来对容器进行 Namespace 的隔离一样,容器的文件系统则是通过 chroot 或者 pivot 这两个系统调用来实现的,通过修改容器的根目录视图让我们看起来容器是个被单独封装好的独立个体,对,看起来。 这样,容器的根目录就变成了一个隔离的子目录,为了让这个目录看起来更像一个系统,往往会在这个目录下增加一些系统的文件、目录和配置,比如 /bin,/etc 等。

其实容器的这种隔离的文件系统是通过 RootFS 也就是容器镜像来完成的。容器镜像通过分层(LAYER)的模式从操作系统所包含的文件目录到应用程序的环境依赖再到应用程序的可执行文件逐层增量进行制造。

​$ docker image insepct helloworld
  …………
      "RootFS": {
            "Type""layers",
            "Layers": [
                "sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc",
                "sha256:568944187d9378b07cf2e2432115605b71c36ef566ec77fbf04516aab0bcdf8e",
                "sha256:7ea2b60b0a086d9faf2ba0a52d4e2f940d9361ed4179642686d1d8b59460667c",
                "sha256:7a287aad297b39792ee705ad5ded9ba839ee3f804fa3fb0b81bb8eb9f9acbf88",
                "sha256:df402fd437a15a96bb81965df19fb46142a80a194b895d6ce837e7278c01f907",
                "sha256:fa71d4eaf80562e542edb884d98dc8da0acbbc704322e3862c2c0375007e014b",
                "sha256:df12cb3b13384a6026e5f4c7fc8eac163e1b7c58fbcbb6a8bd09e1154ceb027a"
            ]
        },

三、容器与虚拟机的区别

虚拟机受宠了那么多年,为啥被突如其来的容器蚕食了不少市场呐?我们来看下虚拟机的真实情况。

  1. 性能损耗较大。虚拟机一般都需要在物理实机上通过 Hypervisor 等技术实现硬件虚拟化,而且每个虚拟化出来的虚拟机都必须要安装完整的操作系统来进行控制,这部分本来就会对物理机的资源及性能带来不小的损耗。
  2. 应用程序依赖的操作系统环境要求较为严格。虚机时代开发者们要遵循的一个原则是尽量让自己的开发和测试环境与线上虚机的操作系统&软件环境依赖等都保持一致,否则看似一切就绪的应用一上线就可能会出现各种环境不一致导致的问题。

当然,虚拟机有其自身的优点,比如隔离更彻底等,我们在这里主要为了讲述容器的优势所以不对虚拟机做过多阐述。

与虚拟机相比,容器本身就是一种特殊的进程,所以不存在虚拟化带来的资源损耗和虚拟机的操作系统带来的存储空间的损耗。同时,借助于现下各种成熟的打包编排工具及容器镜像,使得开发者们只需要在自己的开发环境将应用程序及相关的环境依赖打包一起部署在容器里就不再需要担心这个软件版本不一致那个依赖不存在导致的线上故障了。

总结

明白了“容器”的核心原理-- Namespace 隔离+ Cgroup 资源限制+ RootFS 文件系统,现在看待一个容器进程是不是如同带了透视镜一般无比清晰呐!另外我们了解了容器相比于虚拟机而言的优势,也就明白了为什么大家越来越喜欢用容器进行线上部署了。

至于容器的具体编排及应用我们后续可以重点研究下时下受众最广的 Kubernetes,本文只是简单的探究了下容器的遮羞布后面的一小部分原理,更深层次的我们可以后面再一起探讨~~

0条评论
作者已关闭评论
2****m
4文章数
0粉丝数
2****m
4 文章 | 0 粉丝
2****m
4文章数
0粉丝数
2****m
4 文章 | 0 粉丝
原创

容器基本原理探析

2023-06-27 08:03:21
7
0

提到“容器”,大家应该都不陌生,不是什么特别新鲜的技术了,受众也越来越广了,但是会用就真的理解吗?以下几个相关问题你真的能做到了然于胸吗?

  1. “容器”是怎么把自己隔离开的呐?
  2. “容器”能使用宿主机的全部资源吗?
  3. “容器”有自己的文件系统吗?
  4. “容器”与虚拟机有什么区别?

引言

要想真正理解容器,就必须先了解其发展历程,因为容器也是操作系统功能逐渐强大过程中催生的神器。这里我们只关注几个关键技术时间节点。

时间 事件 作用
1979年UNIX V7 引入chroot系统调用 修改进程根目录,隔离每个进程的文件访问
2006年Google 引入Process Container(CGroups) 对进程的资源(CPU, memory, 磁盘, network)进行限制&隔离
2008年LXC LinuX Containers 使用cgroups和Linux namespaces实现第一个Linux容器
2013年Docker LibContainer 容器镜像完善了容器管理生态,开始普及
2018年Kubernetes 开放&规范 容器化如火如荼

现在,我们知道了几个关键名词了,那么他们是怎么协作产生容器的呐,为了清晰些,先放个大体的关系图在这里,然后我们下面分开探讨下。

一、容器是一种特殊的进程

容器是通过 Linux 的 NamespaceCgroup 等系统控制实现的一套隔离环境。运行中的容器就是一组开启了多个 Namespace(PID/Mount/Network等)进行隔离 的特殊应用进程,然后通过 Cgroups 来控制这个特殊进程对宿主机各个资源(CPU/内存等)的使用限制。

1. NAMESPACE 隔离

来看下我们部署的一个demo应用。

你没看错它的进程pid是1,这时你会想这是什么神仙进程,pid是1的不一般都是系统级的初始化进程吗?这正是容器的隔离环境使出的“一叶障目”的伎俩。 其实你看到的只是容器想让你看到的,实际上在其宿主机的操作系统里,这个demo进程只是一个再普通不过的进程。这里记得这个真实的pid,后续我们还会再次看到它。

这便是通过 Linux 的 PID Namespace 来实现的,我们都知道创建子进程可以调用clone系统调用,要实现PID Namespace的隔离,只需要在进行clone系统调用时加上CLONE_NEWPID参数即可。

int container_pid = clone(container_main, container_stack+STACK_IZE, CLONE_NEWPID | SIGCHLD, NULL); 

这样创建出来的进程就实现了Pid Namespace的隔离,我们看到的进程信息就与宿主机完全分隔开了。 类似的,可以通过clone时增加相应的 Namespace 控制参数进行“隔离”,如CLONE_NEWNET控制Network Namespace、CLONE_NEWNS控制Mount Namesapce等。感兴趣的可以自己试一下。

2. CGROUP 限制

Linux Cgroups是用来限制、控制和分离一个进程组的资源的,包括 CPU、内存、磁盘、网络带宽等等。

我们可以通过'mount -t cgroup'命令在机器的/sys/fs/cgroup目录下一探究竟。

可以看到操作系统的相关资源限制都在这里了,它们是以文件系统的方式存在的。具体到某种类型的资源比如CPU,进入cpu子目录就可以看到详细的控制维度。接下来我们一起来看下我们创建的demo应用的相关限制。

我们会发现/sys/fs/cgroup/cpu下有个docker文件夹,后面的一串数字是容器id,可以通过'docker ps'进行查看。这个目录下面有很多cpu相关的限制维度,具体的含义大家可以自行搜索更准确些,注意最下面有个tasks文件,它里面存储的正是我们的应用进程在宿主机里真实的进程PID,通过控制这个进程的相关资源来对容器进行资源限制。

比如我们要控制应用程序只能使用宿主机的30%的 CPU,如果超了就异常退出,避免单个容器的一个死循环之类的神坑拖垮整个宿主机,那么我们要怎么控制呐?参考如下方法通过控制 cpu.cfs_quota_us 和 cpu.cfs_peroid_us 将相应的限制写入控制文件即可。 cgroup_cpu

二、容器有自己的文件系统吗?

正如上面通过 clone 系统调用来对容器进行 Namespace 的隔离一样,容器的文件系统则是通过 chroot 或者 pivot 这两个系统调用来实现的,通过修改容器的根目录视图让我们看起来容器是个被单独封装好的独立个体,对,看起来。 这样,容器的根目录就变成了一个隔离的子目录,为了让这个目录看起来更像一个系统,往往会在这个目录下增加一些系统的文件、目录和配置,比如 /bin,/etc 等。

其实容器的这种隔离的文件系统是通过 RootFS 也就是容器镜像来完成的。容器镜像通过分层(LAYER)的模式从操作系统所包含的文件目录到应用程序的环境依赖再到应用程序的可执行文件逐层增量进行制造。

​$ docker image insepct helloworld
  …………
      "RootFS": {
            "Type""layers",
            "Layers": [
                "sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc",
                "sha256:568944187d9378b07cf2e2432115605b71c36ef566ec77fbf04516aab0bcdf8e",
                "sha256:7ea2b60b0a086d9faf2ba0a52d4e2f940d9361ed4179642686d1d8b59460667c",
                "sha256:7a287aad297b39792ee705ad5ded9ba839ee3f804fa3fb0b81bb8eb9f9acbf88",
                "sha256:df402fd437a15a96bb81965df19fb46142a80a194b895d6ce837e7278c01f907",
                "sha256:fa71d4eaf80562e542edb884d98dc8da0acbbc704322e3862c2c0375007e014b",
                "sha256:df12cb3b13384a6026e5f4c7fc8eac163e1b7c58fbcbb6a8bd09e1154ceb027a"
            ]
        },

三、容器与虚拟机的区别

虚拟机受宠了那么多年,为啥被突如其来的容器蚕食了不少市场呐?我们来看下虚拟机的真实情况。

  1. 性能损耗较大。虚拟机一般都需要在物理实机上通过 Hypervisor 等技术实现硬件虚拟化,而且每个虚拟化出来的虚拟机都必须要安装完整的操作系统来进行控制,这部分本来就会对物理机的资源及性能带来不小的损耗。
  2. 应用程序依赖的操作系统环境要求较为严格。虚机时代开发者们要遵循的一个原则是尽量让自己的开发和测试环境与线上虚机的操作系统&软件环境依赖等都保持一致,否则看似一切就绪的应用一上线就可能会出现各种环境不一致导致的问题。

当然,虚拟机有其自身的优点,比如隔离更彻底等,我们在这里主要为了讲述容器的优势所以不对虚拟机做过多阐述。

与虚拟机相比,容器本身就是一种特殊的进程,所以不存在虚拟化带来的资源损耗和虚拟机的操作系统带来的存储空间的损耗。同时,借助于现下各种成熟的打包编排工具及容器镜像,使得开发者们只需要在自己的开发环境将应用程序及相关的环境依赖打包一起部署在容器里就不再需要担心这个软件版本不一致那个依赖不存在导致的线上故障了。

总结

明白了“容器”的核心原理-- Namespace 隔离+ Cgroup 资源限制+ RootFS 文件系统,现在看待一个容器进程是不是如同带了透视镜一般无比清晰呐!另外我们了解了容器相比于虚拟机而言的优势,也就明白了为什么大家越来越喜欢用容器进行线上部署了。

至于容器的具体编排及应用我们后续可以重点研究下时下受众最广的 Kubernetes,本文只是简单的探究了下容器的遮羞布后面的一小部分原理,更深层次的我们可以后面再一起探讨~~

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0