Docker 内部机制:深入剖析

大家好!我是大聪明-PLUS

首先是物理服务器 ------价格昂贵且效率低下。后来出现了虚拟机,使得在单个硬件上运行多个相互隔离的操作系统成为可能。但隔离的成本仍然很高:需要完整的操作系统副本、数GB的磁盘空间,以及几分钟的启动时间。

容器是下一个发展阶段。既然可以使用内核内置机制隔离 进程本身,为什么还要虚拟化整个硬件并运行完整的操作系统呢?这种方法要轻量级得多,速度更快,效率也更高。

图像和容器

  • 镜像文件 是一种模板或蓝图。它是一组不可变的、只读的文件、指令和依赖项,用于定义你的应用程序。

  • 容器 是镜像的运行实例。它提供了一个隔离的环境,应用程序就在这个环境中实际运行。当从镜像创建容器时,会添加一个轻量级的可写层。应用程序运行时发生的所有更改都会保存到该层中。

但这个盒子里面究竟藏着什么呢?让我们一探究竟。

第一部分:容器的惊天秘密......它们根本不存在

事实上,从Linux内核的角度来看, 并不存在所谓的"容器 "。存在的只是普通的Linux进程。只不过,这是一个在特殊条件下运行的进程。

这些条件是由两种内核机制产生的:

  1. 命名空间
    命名空间限制了容器内部可见的资源和进程。本质上,它们为每组进程创造了一种错觉,即它们拥有全局资源的独立实例,无论是网络协议栈、进程树还是文件系统。
  • PID 命名空间: 容器内的进程认为自己是第一个也是主要的进程(PID 1),并且看不到容器外的进程。

  • 网络命名空间: 容器拥有自己的虚拟网卡、路由表和 iptables。

  • 挂载命名空间: 容器拥有自己的文件系统树,与主机系统隔离。

  • ......以及其他(UTS、IPC、用户)。

  1. 控制组(Cgroups
    )它们并不隔离,而是 限制和控制 资源。控制组回答"多少人?"这个问题。
  • 限制 CPU、内存和磁盘 I/O 的使用。

  • 他们不允许一个"贪婪"的容器拖垮整个系统。

结论: 容器是一个非常普通的进程(例如 nginx 或 bash),只是通过 命名空间 与其他进程隔离,并通过 cgroups设置限制。

第二部分:图像剖析

如果容器是一个进程,那么镜像就是运行该进程的指令。

容器镜像由两个主要部分组成:

  1. 根文件系统(rootfs) -- 一个目录树,其中包含运行应用程序所需的全部软件:二进制文件、库和设置。不多不少。

  2. 一个包含元数据(指令)的 JSON 文件 。它描述了要运行的进程(CMD)、要设置的环境变量、要打开的端口以及要挂载卷的位置。

它是如何存储和传输的? 很简单!

该工具 还会tarrootfs JSON 文件打包成一个单独的归档文件。这种格式也是镜像存储在 Docker 镜像仓库(例如 Docker Hub)中的格式。每个镜像层也是 tar一个包含文件系统更改的归档文件。

以下是实际操作中的样子**------nginx镜像清单:**

复制代码
`[
  {
    `"RepoTags"`: [`"nginx:latest"`],
    `"Layers"`: [
      `"blobs/sha256/eb5f13bce993..."`,  
      `"blobs/sha256/dab69e9f41e9..."`,  
      
    ],
    `"LayerSources"`: {
      `"sha256:129b375526fc..."`: {
        `"mediaType"`: `"application/vnd.oci.image.layer.v1.tar"`,  
        `"size"`: `5120`,
        `"digest"`: `"sha256:129b375526fc..."`
      }
    }
  }
]`

这样做时 docker pull,你只需下载并解压这些归档文件,Docker Engine就会从中构建一个现成的容器文件系统。

第三部分:如何协同工作:Docker架构

当你输入 docker run nginx 命令时,后台会启动一个由四个组件组成的庞大系统。

  1. Docker引擎
  • 这是一个高级守护进程,您可以通过 CLI(docker run、docker build)与其通信。

  • 它处理你的命令,管理网络和卷,但 它本身并不运行容器。它将这项任务委托给底层服务器。

  1. containerd
  • 这是管理容器生命周期的主要运行时环境。

  • 它负责下载图像、管理存储,并将启动指令传递给下一个链接。

  1. runc
  • 正是这个工具可以访问 Linux 内核,从而将进程、文件系统、网络和其他容器资源与主机系统隔离。

  • 在收到来自 containerd(config.json 和 rootfs)的指令后,runc 直接与 Linux 内核交互。

  • 它创建新的命名空间,配置 cgroups,最后在这个隔离环境中启动我们的目标进程(例如 nginx)。

    重要提示: runc 进程启动后,会认为其工作已完成并退出。

  1. containerd-shim
  • 当容器进程的父进程(runc)终止时,该容器进程会发生什么?它由 containerd-shim 负责处理。
  • 这是一个轻量级进程,它将成为容器进程的新父进程。

    为什么有必要这样做?

    • Containerd-shim 允许您在不停止正在运行的容器的情况下重启或升级 containerd。

    • 将标准输入/输出流(stdin、stdout、stderr)重定向回 Docker Engine。

    • 监控流程状态并报告其完成情况。

结果

你的docker run命令 至关重要:

这样最终你的机器上就只会有一个独立的Linux进程

现在你掌握了这个技巧,Docker 就变成了一个强大的工程系统。祝你容器化之旅一切顺利 :-)

相关推荐
cuijiecheng20188 小时前
Linux下inih库的使用
linux·运维·服务器
GIS瞧葩菜9 小时前
entity几何体轴编辑(沿 Z 轴平移)完整流程拆解
linux·运维·ubuntu
confiself10 小时前
GO环境配置
linux·运维·centos
爱装代码的小瓶子10 小时前
【c++与Linux基础】文件篇(4)虚拟文件系统VFS
linux·开发语言·c++
JiMoKuangXiangQu16 小时前
ARM64 进程虚拟地址空间布局
linux·arm64 虚拟地址布局
阳光九叶草LXGZXJ17 小时前
达梦数据库-学习-47-DmDrs控制台命令(LSN、启停、装载)
linux·运维·数据库·sql·学习
CQ_YM17 小时前
ARM之I2C
arm开发·单片机·嵌入式硬件·嵌入式
春日见17 小时前
如何避免代码冲突,拉取分支
linux·人工智能·算法·机器学习·自动驾驶
无垠的广袤18 小时前
【VisionFive 2 Lite 单板计算机】边缘AI视觉应用部署:缺陷检测
linux·人工智能·python·opencv·开发板
阿波罗尼亚18 小时前
Kubectl 命令记录
linux·运维·服务器