Docker镜像--镜像结构 镜像特性(copy-on-write)

文章目录

    • 镜像概念
      • 解释为什么镜像以MB为单位
      • 镜像的分层结构
        • 为什么docker镜像要采用这种分层结构呢?
    • copy-on-write (拷贝写实)
    • 镜像的构建
      • docker commit 构建镜像三部曲
    • 演示案例

镜像概念

镜像是docker容器的基石,容器是镜像的运行实例,有了镜像才能启动容器

  • 查看镜像信息
[root@foundation0 ~]# docker images rhel7
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7               latest              0a3eb3fde7fd        4 years ago         140 MB

在列出的信息中,可以看到几个字段信息:

  • 来源于哪个仓库,比如rhel7
  • 镜像的标签信息,比如latest
  • 镜像的ID号(唯一)
  • 创建时间

解释为什么镜像以MB为单位

为什么一个rhel7只有140MB
Linux操作系统由内核空间和用户空间组成(rootfs bootfs)
内核空间是kernel,Linux刚启动的时候会加载bootfs文件系统,之后bootfs会被卸载掉
用户空间的文件系统是rootfs,包括我们熟悉的/dev,/proc,/bin 等目录
对于base镜像来说,底层直接用host的kernel,自己只需要提供rootfs就行了
而对于一个精简版的os,rootfs可以很小,只需要包括最基本的命令,工具和程序就可以了

  • base镜像补充
  • base镜像提供的是最小安装的Linux发行版本
  • 支持运行多种Linux OS 不同的Linux发行版的区主要就是
    rootfs 比如Ubuntu 使用upstat 管理服务 apt管理软件包 而centos 7 使用systemd和yum 这些都是用户空间上的区别 Linux kernel差别不大
    注意
    容器的内核版本和宿主机的版本是一致的,可通过:
    uname -r来查看
  • 所有容器都共用host的kernel,在容器中没办法对kernel升级,如果容器对kernel有要求(比如某个应用只能在某个kernel版本下运行),则不建议用容器,这种场景虚拟机更适合

镜像的分层结构

  • 实际上,docker hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的
  • 新的镜像是从base镜像一层一层叠加生成的,每安装一个软件,就在现有的基础增加一层
    Docker镜像--镜像结构 镜像特性(copy-on-write)_第1张图片

为什么docker镜像要采用这种分层结构呢?

最大的一个好处是:共享资源

  • 比如:有多个镜像都从相同的base镜像构建而来,那么docker host只需在磁盘上保存一份base镜像:同时内存中也只需加载一份base镜像,就可以为所有容器服务了,而其镜像的每一层都可以被共享

那么一个疑问是:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如/etc下的文件,这时其他容器的/etc是否也会被修改???
答案是不会
修改会被限制在单个容器内
这就是我们接下来要学习的容器copy-on-write特性

copy-on-write (拷贝写实)

容器层是可写的

  • 当容器启动时,一个新的可写层被加载到镜像的顶部

  • 这一层通常被叫做“容器层”,“容器层”之下的都叫“镜像层”
    Docker镜像--镜像结构 镜像特性(copy-on-write)_第2张图片
    所有对容器的改动,无论添加,删除,还是修改文件都只会发生在容器层,只有容器层是可写的,容器层下面的所有镜像层都是只读的
    注意!!一个镜像层最多127层(镜像层最好不要太多)

  • 具体细节

  • 镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统,如果不同层中有一个相同路径的文件,比如/a,上层的/a会覆盖下层的/a,也就是说用户只能访问到山层中的文件/a,在容器层中,用户看到的是一个叠加之后的文件系统

  • 1.添加文件,在容器中创建文件时,新文件被添加到容器层中
    2.读取文件,在容器中读取某个文件时,docker会从上往下依次在各个镜像层中查找到此文件,一旦找到,打开并读入内存
    3.修改文件,在容器中修改已经存在的文件时,docker会从上往下依次在各个镜像层中查找到此文件,一旦找到,立即将其复制到容器层,然后修改
    4.删除文件,在容器中删除文件时,docker也是从上往下依次在镜像层中查找此文件,找到后,会在容器层中记录下此删除操作

  • 只有当修改的时候才复制一份数据,这种特性被称作copy-on-write

  • 可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改

这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享

  • -it 以交互式模式开启一个终端
docker run -it --name ubuntu 

run:创建并运行一个容器 -it:以交互式的形式 --name:给容器起个名字 ubuntu:镜像名称
我们可以看到 容器和虚拟机共享内核。到底怎么共享的呢?

[root@docker docker]# hostnamectl 
Static hostname: docker
         Icon name: computer-vm
           Chassis: vm
        Machine ID: e26d28698aed47fb9ec897d00ec96f27
           Boot ID: 4f549a312dff439b80de72c1c74a0682
    Virtualization: kvm
  Operating System: Red Hat Enterprise Linux Server 7.5 (Maipo)
       CPE OS Name: cpe:/o:redhat:enterprise_linux:7.5:GA:server
            Kernel: Linux 3.10.0-862.el7.x86_64
      Architecture: x86-64
  • [root@server3 sysctl.d]# docker run -it --name vm1 ubuntu
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
7413c47ba209: Pull complete 
0fe7e7cbb2e8: Pull complete 
1d425c982345: Pull complete 
344da5c95cec: Pull complete 
Digest: sha256:c303f19cfe9ee92badbbbd7567bc1ca47789f79303ddcef56f77687d4744cd7a
Status: Downloaded newer image for ubuntu:latest
Try 'uname --help' for more information.
  • root@b16f9eaab99e:/# uname -r 3.10.0-514.el7.x86_64
    可以见得 docker是对我们操作系统内核有一定的要求的
[root@docker docker]# docker run -it --name vm1 ubuntu 
root@4154d58490f2:/# ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr
root@4154d58490f2:/# touch file1 	#改变的是容器层 
root@4154d58490f2:/# touch file2

1.Copy-on-Write可写容器层
2.容器层意所有镜像层都是只读的
3.docker从上往下依次查找文件
4.容器层保存镜像变换的部分 并不会对镜像本身进行任何修改
5.一个镜像最多127层

镜像的构建

docker commit 构建镜像三部曲

  • 运行容器
  • 修改容器
  • 将容器保存为新的镜像
    缺点
  • 效率低 可重复性弱 容易出错
  • 使用者无法对镜像进行审计,存在安全隐患
  • 查看镜像
[root@server3 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              3556258649b2        2 weeks ago         64.2 MB
game2048            latest              19299002fdbe        2 years ago         55.5 MB
[root@server3 ~]# docker history ubuntu:latest  # 保存每一层的镜像修改
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
3556258649b2        2 weeks ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0 B                 
           2 weeks ago         /bin/sh -c mkdir -p /run/systemd && echo '...   7 B                 
           2 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' >...   745 B               
           2 weeks ago         /bin/sh -c [ -z "$(apt-get indextargets)" ]     987 kB              
           2 weeks ago         /bin/sh -c #(nop) ADD file:3ddd02d976792b6...   63.2 MB 

"missing“的意思是 这些操作不是在本机操作的 所有找不到 这并没有什么关系

演示案例

busybox:这个镜像非常的轻量级 适合我们在学习和实验中去使用

[root@server3 ~]# docker run -it --name test busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
ee153a04d683: Pull complete 
Digest: sha256:9f1003c480699be56815db0f8146ad2e22efea85129b5b5983d0e0fb52d9ab70
Status: Downloaded newer image for busybox:latest
/ # echo helloworld >testfile
/ # ls
bin       etc       proc      sys       tmp       var
dev       home      root      testfile  usr
/ # cat testfile 
helloworld
/ # exit #退出并停止运行 ctrl p+q 退出不停止运行
[root@server3 ~]# docker ps -a  #注意:我们只是退出了运行中的容器 并没有删除它
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                     PORTS               NAMES
6789012d8958        busybox             "sh"                About a minute ago   Exited (0) 5 seconds ago                       test
  • 将在后台保存的容器运行起来
docker start test 
  • 此命令可以进入在后台运行起来
[root@server3 ~]# docker attach test 的容器
  • 将我们所修改的容器保存
 [root@server3 ~]# docker commit test test:v1  #
sha256:c1a9c80bccb0b51e410cc90bbe56460c4b84e2119741aee133d99a45da702857
[root@server3 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                v1                  c1a9c80bccb0        5 seconds ago       1.22 MB
ubuntu              latest              3556258649b2        2 weeks ago         64.2 MB
busybox             latest              db8ee88ad75f        3 weeks ago         1.22 MB
game2048            latest              19299002fdbe        2 years ago         55.5 MB
  • 我们可以看到 相同的底层是共享的(在我们当前的文件系统之上是只保存一份的) 基于busybox构建的
[root@server3 ~]# docker history test:v1  
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
c1a9c80bccb0        24 seconds ago      sh                                              59 B                
db8ee88ad75f        3 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0 B                 
           3 weeks ago         /bin/sh -c #(nop) ADD file:9ceca008111a4dd...   1.22 MB 

缺点是:我们无法得知我们对这个容器到底做了什么操作 虽然它已经被保存了

[root@server3 ~]# docker rm 6789012d8958
Error response from daemon: You cannot remove a running container 6789012d89587629aa79031fdde5101671265849ed92b042f5e1dda7b7909f07. Stop the container before attempting removal or use -f
  • 可以强制删除正在运行中的容器
[root@server3 ~]# docker rm -f 6789012d8958
6789012d8958
[root@server3 ~]# docker rm -f 6789012d8958
6789012d8958
  • 可以看到 新运行的容器也是有我们之前所保存的数据的
[root@server3 ~]# docker run -it --name vm1 test:v1
/ # ls
bin       etc       proc      sys       tmp       var
dev       home      root      testfile  usr
/ # cat testfile 
helloworld

你可能感兴趣的:(Docker镜像--镜像结构 镜像特性(copy-on-write))