[Docker]容器镜像

 1、rootfs的基础知识

Mount namespaces 隔离的是文件系统挂接点,它使每个容器能看到不同的文件系统层次结构,即每当创建一个新容器时,希望容器进程看到的文件系统时一个独立的隔离环境,而不是继承自宿主机的文件系统。  

  Mount Namespace修改的是容器进程对文件系统挂载点的认知。这意味着只有在挂载操作(mount)发生之后,进程的视图才会发生改变,而在此之前,新创建的容器会直接继承宿主机的各个挂载点。因而在创建新进程时,除了声明要启用的Mount  Namespace之外,还可以告诉容器进程有哪些目录需要重新挂载。因此在容器启动之前重新挂载它的整个根目录“/”,这时由于Mount Namespace的存在,这个挂载对宿主机不可见。

  在Linux系统里,chroot(change root file system,改变进程的根目录到指定位置)命令可以完成这个工作

chroot $HOME/test /bin/bash    //将使用$HOME/test目录作为/bin/bash进程的根目录

  为了能够让容器的这个根目录看起来更真实,一般会在这个容器的根目录下挂载一个完整操作系统的文件系统,比如Ubuntu16.04的ISO。这样在容器启动之后,在容器里执行:“ls /”查看根目录下的内容,就是Ubuntu16.04的所有目录和文件

  而挂载在容器根目录上,用来为容器进程提供隔离后执行环境的文件系统,就是容器镜像,也叫rootfs(根文件系统)。需要注意的是rootfs只是一个操作系统所包含的文件、配置和目录,并不包括操作系统的内核。在Linux操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。即只包括了操作系统的躯壳,并不包括操作的系统的灵魂。

  实际上同一台机器上的所有容器都共享宿主机操作系统的内核。因此在配置内核参数、加载额外的内核模块以及跟内核进行直接的交互时的操作和依赖的对象都是宿主机操作系统的内核,它对于该机器上的所有容器来说都是一个全局变量。这是容器的主要缺陷之一。

2、因此Docker项目最核心的原理实际上是为待创建的用户进程:

    1)、启用Linux Namespace

    2)、设置指定的Cgroups参数

    3)、切换进程的根目录(change root)

3、容器的一致性

  由于rootfs里打包的不只是应用,而是整个操作系统的文件和目录,即应用以及它运行所需要的所以依赖都被封装在了一起。(对一个应用来说,操作系统本身是他运行所需要的最完整的依赖库)

  容器镜像“打包操作系统”的能力赋予了容器的一致性:无论在本地、云端还是在一台任何地方的机器,用户只需要解压打包好的容器镜像,那么这个应用运行所需要的完整的执行环境就被重现处理了。

  但是这里有一个问题,难度每开发一个应用或升级现有的应用都需要重复制作一次rootfs吗?

  答案肯定不是的,可以采用增量的方式去做这些修改。Docker在镜像设计中,引入了层(layer)的概念,也就是说用户制作镜像每一步操作都会生成一个层,即一个增量的rootfs

  它是使用联合文件系统(Union File System,将多个不同位置的目录联合挂载到同一个目录下)实现的。

docker run -d ubuntu:latest sleep 3600   //启动一个容器

  Docker会从DockerHub上拉取一个Ubuntu镜像到本地,这个镜像就是Ubuntu操作系统的rootfs,它的内容是Ubuntu操作系统的所有文件和目录。Docker镜像使用的rootfs往往由多层组成

        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:a30b835850bfd4c7e9495edf7085cedfad918219227c7157ff71e8afe2661f63",
                "sha256:6267b420796f78004358a36a2dd7ea24640e0d2cd9bbfdba43bb0c140ce73567",
                "sha256:f73b2816c52ac5f8c1f64a1b309b70ff4318d11adff253da4320eee4b3236373",
                "sha256:6a061ee02432e1472146296de3f6dab653f57c109316fa178b40a5052e695e41",
                "sha256:8d7ea83e3c626d5ef1e6a05de454c3fe8b7a567db96293cb094e71930dba387d"
            ]
        },

  可以看出这个Ubuntu镜像实际上由五层组成,这五层就是五个增量rootfs,每一层都是Ubuntu操作系统文件与目录的一部分,而是用镜像时,Docker会把这些增量联合挂载在一个统一的挂载点上

  这个容器的rootfs如下图所示的三部分组成:

    

    

      1)只读层

      它是这个容器的rootfs最下面的五层,对应的是Ubuntu:latest镜像的五层,它们的挂载方式都是只读(ro+wh, readonly+whiteout),这些层以增量的方式分别包含了Ubuntu的一部分

      2)可读写层

      它是这个容器的rootfs最上面的一层,它的挂载方式是:rw(read write)。在没有写入文件之前,这个目录是空的,而一旦在容器里做了写操作,修改产生的内容会以增量的方式出现在这个层中。

      那要是删除只读层的文件呢?AuFS会在读写层创建一个whiteout文件,把只读层里的文件“遮挡起来”

      所以可读写层的作用,就是专门用来存放修改rootfs后产生的增量,增、删、改都发生在这里,当使用完这个被修改得容器之后,还可以使用docker commit和push指令,保存这个被修改过的可读写层并上传到Docker Hub上。而与此同时,原先的只读层里的内容不会有任何变化

      3)Init层

      以-init层结尾的层,夹在只读层和读写层之间。Init层是Docker项目单独生成的一个内部层,专门用来存放/etc/hosts,/etc/resolv.conf等信息。需要这样一层的原因是这些文件本来属于只读的Ubuntu镜像的一部分,但是用户需要在容器启动时写入一些指定的值(如hostname),所以就需要在可读写层对它们进行修改,可是这些修改往往只对当前容器有效,并不需要在执行docker commit时把这些信息连同可读写层一起提交。因此Docker在修改这些文件以后,以一个单独的层挂载了出来。

      4)既然容器的rootfs是以只读的方式挂载的?那么如何在容器里修改镜像的内容呢?

       上面读写层通常也称为容器层,下面的只读层称为镜像层,所有的增删查改操作都只会作用在容器层,相同的文件上层会覆盖掉下层。知道这一点,就不难理解镜像文件的修改,比如修改一个文件的时候,首先会从上到下查找有没有这个文件,找到,就复制到容器层中,修改,修改的结果就会作用到下层的文件,这种方式也被称为copy-on-write。       

原文地址:https://www.cnblogs.com/yuxiaoba/p/9613209.html

时间: 2024-11-10 11:32:31

[Docker]容器镜像的相关文章

运行docker容器镜像

docker容器可以理解为在盒中运行的进程. 这个盒包含了该进程运行所必须的资源,包括文件系统.系统类库.shell 环境等等. 但这个盒默认是不会运行任何程序的. 1.运行镜像之前,可以先查看本地有那些镜像. # docker images 2.最简单的运行镜像的命令: # docker run 镜像名称 3.查看运行中的容器: # docker ps 4.查看所有的容器镜像 # docker ps -a 5.刚开始使用 Docker ,运行完一个容器,再次运行这个容器,原来的容器内的内容已经

HyperLedger/Fabric SDK使用Docker容器镜像快速部署上线

HyperLedger/Fabric SDK Docker Image 该项目在github上的地址是:https://github.com/aberic/fabric-sdk-container (感谢Star). 这是一个基于fabric-sdk-java的项目,该项目的主要目的是简化HyperLedger/Fabric开发人员在SDK应用层上的工作流程,使得开发和部署更加简单. 该项目使用方便,只需要你的服务器上部署有Docker及docker compose环境即可,通过docker-c

使用Aliyun Docker 容器镜像/注册表服务

1.前往阿里云容器镜像服务创建相关资源. 2.登录你的仓库,账户名+公共地址 docker login --username=xxxxxxxxx@aliyun.com registry.cn-hangzhou.aliyuncs.com 3.推送镜像上Aliyun镜像注册表. docker login --username=ap2337h2v@aliyun.com registry.cn-hangzhou.aliyuncs.com docker tag [ImageId] registry.cn-

Docker容器——镜像管理,端口映射,容器互联

docker镜像的分层  Dockerfile 中的每个指令都会创建一个新的镜像层: 镜像层将会被缓存和复用: 当 Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效: 某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效: 镜像层是不变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然包含该文件 docker镜像 是应用发布的标准格式 可支撑一个docker容器的运行 docker镜像的创建方法 基于已有镜像创建 基于

Docker容器镜像删除

好吧,本来认为删除镜像是一件很容易的事情,但刚开始上手,还是有点百思不得其解.删着删着,发现果然很容易.分享下本人的心得: 分两种情况:那么要删除镜像,首先得删除容器,删除容器时,确保容器已停止运行:2 :删除容器和删除镜像的命令略微有点差别:删除容器(rm),删除镜像(rmi).整个过程如下: 1 查询当前镜像(docker image): 可以看到,当前镜像有nginx和tomcat.我想删除tomcat镜像,它的IMAGE ID 为:41a54fe1f79d 2 查询容器(docker p

docker容器镜像等相关文件目录迁移

迁移目的: 默认装在系统盘的,一般云服务器系统盘40G左右很容器就满了,这个时候必须做迁移了 首先记录一条清理镜像的命令 # 以下命令清除无用的镜像 docker image prune -a -f # 容器因有回滚的需求,只做手动删除!! 以下方法亲手验证可行 docker默认存储目录是/var/lib/docker,下面操作用systemctl,不用service,因为用service的话有个地方会不生效 systemctl stop docker 在大空间的磁盘上创建目录 mkdir -p

Docker 容器, 镜像, 及注册

When using Docker, a developer creates an app or service and packages it and its dependencies into a container image. An image is a static representation of the app or service and its configuration and dependencies. To run the app or service, the app

Docker 容器镜像删除

停止所有的container,这样才能够删除其中的images: docker stop $(docker ps -a -q) 如果想要删除所有container的话再加一个指令: docker rm $(docker ps -a -q)

关于docker容器和镜像的区别

引自:https://blog.csdn.net/shenmerenya/article/details/78522206 docker的整个生命周期有三部分组成:镜像(image)+容器(container)+仓库(repository): 如下图所示,容器是由镜像实例化而来,这和我们学习的面向对象的概念十分相似,我们可以把镜像看作类,把容器看作类实例化后的对象. [html] view plain copy docker 的镜像概念类似虚拟机的镜像.是一个只读的模板,一个独立的文件系统,包括