Docker

  • OCI(Open Container Initiative):旨在围绕容器格式和运行时制定一个开放的工业化标准。目前 OCI 主要有三个规范:运行时规范 runtime-spec ,镜像规范 image-spec 以及不常见的镜像仓库规范 distribution-spec 。

    • 镜像规范 image-spec 决定了镜像按照什么标准来构建,以及构建完镜像之后如何存放<—>Dockerfile 则决定了镜像的 layer 内容以及镜像的一些元数据信息
    • OCI 容器镜像规范主要包括以下几块内容

      • layer:以 layer (镜像层)保存的文件系统,每个 layer 保存了和上层之间变化的部分,layer 应该保存哪些文件,怎么表示增加、修改和删除的文件等。

        1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1603262/1593410156282-4539c0b9-b6cf-42cd-8c6a-6fd0e92096f2.png#align=left&display=inline&height=82&margin=%5Bobject%20Object%5D&name=image.png&originHeight=106&originWidth=596&size=14576&status=done&style=none&width=463)
      • image config 保存了文件系统的层级信息(每个层级的 hash 值,以及历史信息),以及容器运行时需要的一些信息(比如环境变量、工作目录、命令参数、mount 列表),指定了镜像在某个特定平台和系统的配置

      • manifest 镜像的 config 文件索引。manifest 文件中保存了很多和当前平台有关的信息,例如有哪些 layer 以及额外的 annotation 信息。
      • image manifest index =Manifest List
  • Dockerfile
  • 镜像工厂

    • docker build 构建镜像的流程大概就是:

      1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1603262/1593413030254-1476e7d6-2a01-4f9a-9f7e-1e65ddde5cab.png#align=left&display=inline&height=328&margin=%5Bobject%20Object%5D&name=image.png&originHeight=473&originWidth=891&size=58982&status=done&style=none&width=617)
    • 基础镜像

以debian:buster基础镜像为例

  1. FROM scrach //自从 Docker 1.5 版本开始,该指令并不进行任何操作,即不会创建一个镜像层
  2. ADD rootfs.tar.xz/ //自动把 rootfs.tar.xz 解压到 / 目录下,由此产生的一层镜像就是最终构建的镜像真实的 layer 内容
  3. CMD "bash" //指定这镜像在启动容器的时候执行的应用程序

image.png

  • 镜像存放
    • 本地存放
      • 当构建完一个镜像之后,镜像就存储在了 Docker 本地存储目录,默认情况下为 /var/lib/docker
    • registry 存储
  • 镜像搬运
    • docker pull 就和使用 git clone 一样效果,将远程的镜像仓库拉取到本地来给容器运行时使用

image.png

  • docker push
    • push 推送一个镜像到远程的 registry 流程恰好和 pull 拉取镜像到本地的流程相反

      镜像格式

  • UnionFS:个不同文件系统联合(堆叠)在一起,呈现为一个文件系统;和一般的 FHS 规定的那种树装组织方式不同
    • FHS:任何一个文件系统都怪在在树上的一个挂载点,根据路径可以指到一个确定的文件系统,如/usr/local/ 下面的路径都在一个文件系统上,而其他 /usr 就会在另一个文件系统上
    • Union FS:多层堆叠,写的文件会停留在最上层,如图中修改过的 /etc/passwd 就会在最上的可写层,其他的文件就要去下面的层中去找—->允许同一个目录中的不同文件在不同层中,这样,Live CD 操作系统跑起来就像真正的本地操作系统一样可以读写所有路径了

image.png

  • 存在的问题:初始化好系统之后的工作的精髓就在于怎么更平滑地安装和升级、确保没有依赖问题,又不额外占据太多的空间—>解决这个问题的基础就是 rpm/deb 这样的包以及包之间的依赖关系—>“A 依赖 B 和 C,但 B 却和 C 冲突”
    • Docker跳出这个思路
      • 完整的操作系统就是一个包,而且如果在开发、测试、部署时都保持同样完整、不变的操作系统环境,那么也就没有那么多依赖性导致的问题了
      • 这样的完整的操作系统不可变(镜像),可以用 AUFS 这样的 UnionFS 在上面放一个可写层,应用可以在运行时写东西到可写层,一些动态生成的配置也可以放在可写层
      • 如果一些应用软件镜像,它们共用同一部分基础系统,那么,把这些公共部分,放在 UnionFS 的下层作为只读层,这样他们可以给不同的应用使用;当然,如果两个应用依赖的东西不一样,那它们就用不同的基础层,也不需要互相迁就了,自然没有上面的依赖性矛盾存在了
      • 一个镜像可以包含多个层,这样,更方便应用可以共享一些数据,节省存储和传输开销

image.png