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



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

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

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

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

    关键词1:隔离

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

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

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

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

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

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

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

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

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

    举个例子:

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

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

    docker exec -it myApp /bin/sh/
    
    • 1

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

    我们在容器里执行 ps 命令

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

    我们可以看到,容器里只有两个进程在运行,一个是最开始执行的 /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 这样的软件来代替应用本身作为容器的启动进程
  • 相关阅读:
    ExcelPatternTool 开箱即用的Excel工具包现已发布!
    一款好的软件,软件测试必不可少...
    VSCode编写OpenCV
    Springboot的自动配置原理
    k8s-实战——Harbor镜像仓库的部署
    2.9.C++项目:网络版五子棋对战之业务处理模块的设计
    视频文件采用哪种格式占的空间最小
    进阶指针(一)
    机器学习笔记 - 什么是 MLOps?
    【C++】类和对象
  • 原文地址:https://blog.csdn.net/s_alted/article/details/127812176