两个关键词带你了解容器技术的实现


通过前面的文章,我们可以得出以下几点事实:

  • 容器技术的兴起源于 Paas 技术的普及
  • Docker 公司发布的 Docker 项目具有里程碑式的意义
  • Docker 项目通过容器镜像,解决了应用打包这个根本性难题

但是一个关键性问题还没有搞清楚——容器,到底是怎么一回事?

接下来我将通过两个关键词,给大家揭开容器技术的神秘面纱

关键词1:隔离

前面的文章提到过,容器其实是一种”沙盒“技术

”沙盒“就像是一个集装箱一样,把你的应用”装起来“,这样,应用与应用之间,就因为有了边界而不至于相互干扰;而被装进集装箱的应用,也可以被方便地搬来搬去,这不就是 PaaS 最理想的状态嘛

Docker 公司的标志,是一头鲸鱼上背着集装箱,那一个个集装箱,代表着一个个容器

在这里插入图片描述
应用之间互不干扰,说起来简单,但要用技术手段去实现他们,可能大多数人就无从下手了

我们知道,程序其实就是存储在磁盘上的一个个二进制文件,一旦被加载到内存中交给 CPU 去执行,就成了一个个进程

总的来说,程序是存储在磁盘上的二进制文件、是静态的,而进程就是程序的运行时,是动态的

容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造一个”边界“,将进程隔离起来

那么怎么才能将进程隔离起来呢?答案是——Namespace 技术

Namesapce 技术通过修改进程视图来实现进程间的隔离

举个例子:

在我的 Linux 操作系统上有 Docker 项目正在运行,我的操作系统环境是 CentOS 7

我们先以终端形式启动一个容器,并在容器里执行 /bin/bash

docker exec -it myApp /bin/sh/

这样,我的 CentOS 7 就变成了一个宿主机,而这个我启动的容器,就在宿主机上面运行着

我们在容器里执行 ps 命令

PID  USER   TIME COMMAND
1    root   0:00 /bin/sh
10   root   0:00 ps

我们可以看到,容器里只有两个进程在运行,一个是最开始执行的 /bin/bash (PID=1),另一个是刚刚执行的 ps

可以看到,容器里面的进程被 Docker 隔离在了一个跟宿主机完全不同的世界当中

究竟是怎么做到的呢?

一般情况下每当我们在宿主机上运行一个 /bin/bash 程序,操作系统都会为其分配一个 PID(例如 PID=100),PID 是进程的唯一标识。(PS:PID为1则意味着这个进程是第一个进程,是后面所有进程的爹)

在这里插入图片描述
当我们通过 Docker 把这个 /bin/bash 程序(假设 PID =100)运行在一个容器当中的时候,Docker就会给这个 /bin/bash 施加一个“障眼法”——让它看不到前面 99 个进程,让它误以为自己就是第一个进程(即 PID=1)

这种技术,就是 Linux 里面的 Namespace 机制

这种机制,其实就是对被隔离应用的进程空间做了手脚,使得这些进程只能看到重新计算过的进程编号,比如 PID=1。可实际上,他们在宿主机的操作系统真实的进程空间里,还是原来的第 100 号进程

而每个 Namespace 里的应用进程,都会认为自己是当前容器里的第 1 号进程,它们既看不到宿主机里真正的进程空间,也看不到其他 PID Namespace 里的具体情况

除了我们介绍的 PID Namespace ,Linux 操作系统还提供了 Mount 、UTS、IPC、Network和User 这些 Namespace,用来对各种不同的进程上下文进行“障眼法”

比如,Mount Namespace,用于让被隔离进程只看到当前 Namespace 里的挂载点信息;Network Namespace,用于让被隔离进程看到当前 Namespace 里的网络设备和配置

以上这些,便是 Linux 容器技术最基本的实现原理之一

总结:

  • Docker 容器这个听起来很深奥的概念,其实就是在创建容器进程时,指定了这个进程所需要启用的一组 Namespace 参数,这样容器就只能“看到”当前 Namespace 所限定的资源、文件、设备、状态或者配置,而对于宿主机以及其他不相关的程序,它就完全看不到了
  • 容器其实就是一种特殊的进程,将这些进程通过 Namespace 机制进行隔离,就仿佛运行在一个个“容器/沙盒”里面,与世隔绝

关键词2:限制

我们知道,Linux 通过 Namespace 机制将容器进程隔离起来,让它们只能再他们的空间里运行

但对于宿主机来说,这些被“隔离”的进程(容器)跟其他进程并没有太大的区别

我们站在宿主机的角度上来看,这些被“隔离”的进程(容器)本质上跟其他进程没有什么区别,这些容器使用的是同一个宿主机的操作系统内核

这就会导致一个问题——隔离得不彻底

尽管你在容器里通过 Mount Namespace 单独挂载其他不同版本的操作系统,比如 CentOS 或 Ubuntu,但这并不能改变容器共享宿主机内核的事实

这表明你想在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的

其次,还会导致另一个问题——在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,最典型的例子就是:时间

如果你在容器里修改了时间,那么整个宿主机的时间都会被修改。所以说,在容器里部署应用的时候,“什么能做,什么不能做”是需要考虑的一个问题

所以说,我们除了对容器要进行**“隔离”,我们还需要对容器进行“限制”**

我们接着引用上面的例子,虽然容器里的 1 号进程在“障眼法”的干扰下只能看到容器里的情况,但是在宿主机上,它是 100 号进程,它去宿主机上的其他进程之间是平等的竞争关系

即虽然 100 号进程被隔离起来,但是它能够使用到的资源(CPU、内存等)是可以随时被宿主机上的其他进程(或者其他容器)占用的,当然,这个 100 号进程自己也可能把所有资源吃光

Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能

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

想了解更多关于 Linux Cgroups 的知识 ,请翻阅下面的文档:

Linux资源管理之cgroups简介 - 美团技术团队 (meituan.com)

总结:

  • 一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制
  • 容器是一个“单进程”模型。这就意味着,在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼Linux运维

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值