Docker系列(三)-Docker的镜像讲解

镜像是什么?

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需要的所有内容,包括代码,运行时(一个程序在运行或者在被执行的依赖)、库,环境变量和配置文件。

所有的应用直接打包成docker镜像,就可以直接跑起来!!!

如何获取镜像:

  • 从远程仓库下载
  • 向其他人获取
  • 自己制作一个镜像DockerFile
镜像加载的原理

联合文件系统

UnionFS(联合文件系统):Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持文件系统的修改作为一次提交来一层层的叠加,溶蚀可以将不同的目录挂在到同一个虚拟文件系统(Virtual File Systems(VFS))下。Union文件系统时Docker镜像的基础。镜像可以通过分层进行继承,基于基础的镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有的底层的文件和目录。

加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含 bootloader 和 Kernel , bootloader 主要是引导加 kernel, Linux刚启动时会加载 bootfs 文件系统,在 Docker 镜像的最底层是 bootfs 。这一层与我们典型的 Linux/Unix系统是一样的,包含 boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs 。

rootfs(root file system),在 bootfs之上。包含的就是典型 Linux系统中 的 /dev,/proc,/bin,/etc 等标准目录和文件。 rootfs就是各种不同的操作系统发行版,比如 Ubuntu, Centos 等等。
在这里插入图片描述
平时我们安装进虚拟机的CentOS系统好几个G,为什么Docker这里才231M?

[root@VM-0-16-centos /]# docker images
centos                latest    5d0da3dc9764   5 weeks ago     231MB

对于一个精简的OS,rootfs可以很小,只需要包含最基础的命令,工具和程序就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同系统的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。

分层的理解

分层的镜像

我们可以下载一个镜像,观察镜像的下载日志,可以看到镜像在一层层的下载

[root@VM-0-16-centos /]# docker pull redis
Using default tag: latest
latest: Pulling from library/redis
7d63c13d9b9b: Pull complete 
a2c3b174c5ad: Pull complete 
283a10257b0f: Pull complete 
7a08c63a873a: Pull complete 
0531663a7f55: Pull complete 
9bf50efb265c: Pull complete 
Digest: sha256:a89cb097693dd354de598d279c304a1c73ee550fbfff6d9ee515568e0c749cfe
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest

思考:为什么Docker镜像要使用分层结构呢?

最大的好处莫过于资源的共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需要在磁盘上存一份base镜像,同时内存里面也只需要加载一份base镜像,这样就可以给所有的容器服务了,而且镜像的每一层都是可以恭喜的。

查看镜像分层的方式可以使用:docker image inspect redis:latest

[root@VM-0-16-centos /]# docker image inspect redis:latest
[
    {
        "Id": "sha256:7faaec68323851b2265bddb239bd9476c7d4e4335e9fd88cbfcc1df374dded2f",
        "RepoTags": [
            "redis:latest"
        ],
        "RepoDigests": [
            "redis@sha256:a89cb097693dd354de598d279c304a1c73ee550fbfff6d9ee515568e0c749cfe"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-10-12T09:42:28.403526293Z",
        "Container": "10b9267d91b3a0b3d03e429697cf6edda84ecb6447d5c4a5d6054d8ed189c71a",
        "ContainerConfig": {
            "Hostname": "10b9267d91b3",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "6379/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.12",
                "REDIS_VERSION=6.2.6",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz",
                "REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"redis-server\"]"
            ],
            "Image": "sha256:77d41858d117f5fe9255dbff7861254660bb6789f3a74f69eebf0d432c214a52",
            "Volumes": {
                "/data": {}
            },
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "20.10.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "6379/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.12",
                "REDIS_VERSION=6.2.6",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz",
                "REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
            ],
            "Cmd": [
                "redis-server"
            ],
            "Image": "sha256:77d41858d117f5fe9255dbff7861254660bb6789f3a74f69eebf0d432c214a52",
            "Volumes": {
                "/data": {}
            },
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 112691012,
        "VirtualSize": 112691012,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/14a6106e40c47f3459afa14f12e41df8f55ce17725279be266f3841a510b3995/diff:/var/lib/docker/overlay2/9f81a5c66de6db7bb7f16ae91967ebb0dec55207e372f52863b84a0f76df9c1b/diff:/var/lib/docker/overlay2/00eaaea0a3d09c805d76dbbafc72443a3c2fa8648e8e70acffb16efe9c890a3b/diff:/var/lib/docker/overlay2/300cce4365acff9e0913ec088b05159ef35ba669b62002bce2cf0f7cf6106bf0/diff:/var/lib/docker/overlay2/33875f5fef9dfa2f79d73a001b6b4bbdff35a0c6d8e8075ca9b949204ec1ec67/diff",
                "MergedDir": "/var/lib/docker/overlay2/c748a98367cd2dd72d9eb24a3cd1098b465d37565241cf3e268b4f60a6e485be/merged",
                "UpperDir": "/var/lib/docker/overlay2/c748a98367cd2dd72d9eb24a3cd1098b465d37565241cf3e268b4f60a6e485be/diff",
                "WorkDir": "/var/lib/docker/overlay2/c748a98367cd2dd72d9eb24a3cd1098b465d37565241cf3e268b4f60a6e485be/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:e8b689711f21f9301c40bf2131ce1a1905c3aa09def1de5ec43cf0adf652576e",
                "sha256:b43651130521eb89ffc3234909373dc42557557b3a6609b9fed183abaa0c4085",
                "sha256:8b9770153666c1eef1bc685abfc407242d31e34f180ad0e36aff1a7feaeb3d9c",
                "sha256:6b01cc47a390133785a4dd0d161de0cb333fe72e541d1618829353410c4facef",
                "sha256:0bd13b42de4de0a0d0cc3f1f162cd0d4b8cb4ee20cbea7302164fdc6894955fd",
                "sha256:146262eb38412d6eb44be1710bfe0f05d3493831f82b1c2be8dc8d9558c9f033"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

这里就是镜像的分层信息
在这里插入图片描述

理解

所有的Docker镜像都起始于一个基础的镜像,当进行修改或新增的内容时,就会在当前的镜像创建新的镜像层。

举一个简单的例子:假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是镜像的第一层。如果再该镜像添加Python包,就会再基础的镜像之上创建第二个新的镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。

该镜像当前已经包含3个镜像层,如下图:
在这里插入图片描述
再添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图举一个例子:

每一个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
在这里插入图片描述
上图中的镜像层跟上面的图片中有差别,主要目的是便于展示文件。

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件这是因为文件7是文件5的一个更新版本。
在这里插入图片描述
这种情况下,上层镜像层长得文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新的镜像层添加到镜像中。

Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层的堆栈,并保证多镜像层对外展示为统一文件系统。

Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独特的性能特点。
在这里插入图片描述

特点

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层!
在这里插入图片描述

Commit镜像

如何提交一个新的容器镜像

docker commit 提交容器成为一个新的副本

# 命令和git原理类似
# docker commit -m="提交的描述信息" -a="作者" 容器ID  目标镜像名:[TAG]

实战测试:

# 1、启动一个tomcat,如果发现tomcat404可能是tomcat目录下webapps里面文件为空,解决方式参考:Docker常用命令>作业联系>Docker安装tomcat
[root@VM-0-16-centos /]# docker run -d -p 3344:8080 --name tomcat02 e81ee1ac2b97
736be05390b457d43b452f3facfd0855a6279c43888ff593599f267a66eed997
[root@VM-0-16-centos /]# docker ps
CONTAINER ID   IMAGE          COMMAND             CREATED         STATUS         PORTS                                       NAMES
736be05390b4   e81ee1ac2b97   "catalina.sh run"   8 seconds ago   Up 8 seconds   0.0.0.0:3344->8080/tcp, :::3344->8080/tcp   tomcat02
[root@VM-0-16-centos /]# 
[root@VM-0-16-centos /]# ls
bin  boot  data  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
[root@VM-0-16-centos /]# docker exec -it tomcat02 /bin/bash
root@736be05390b4:/usr/local/tomcat# ls
BUILDING.txt  CONTRIBUTING.md  LICENSE	NOTICE	README.md  RELEASE-NOTES  RUNNING.txt  bin  conf  lib  logs  native-jni-lib  temp  webapps  webapps.dist  work
root@736be05390b4:/usr/local/tomcat# 
root@736be05390b4:/usr/local/tomcat# 
root@736be05390b4:/usr/local/tomcat# cd webapps
root@736be05390b4:/usr/local/tomcat/webapps# ll
bash: ll: command not found
root@736be05390b4:/usr/local/tomcat/webapps# ls
root@736be05390b4:/usr/local/tomcat/webapps# 
root@736be05390b4:/usr/local/tomcat/webapps# cd ..
root@736be05390b4:/usr/local/tomcat# 
root@736be05390b4:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@736be05390b4:/usr/local/tomcat# cd webapps
root@736be05390b4:/usr/local/tomcat/webapps# ls
ROOT  docs  examples  host-manager  manager

# 2、当我们解决这个问题后,就相当于我们在原来的tomcat的镜像上面加了一层,我们可以重新打包镜像了
[root@VM-0-16-centos /]# docker commit -a="hecan" -m="测试" 736be05390b4 tomcat-test:1.0
sha256:4d9e4501ca5bd87dc36b48c86dbb20607bd6e60d867d14e8f63cdaee4946c8dc
[root@VM-0-16-centos /]# docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
tomcat-test           1.0       4d9e4501ca5b   11 seconds ago   685MB
tomcat                9.0       e81ee1ac2b97   11 days ago      680MB
tomcat                latest    4ce9babdd885   11 days ago      680MB
redis                 latest    7faaec683238   12 days ago      113MB
nginx                 latest    87a94228f133   13 days ago      133MB
centos                latest    5d0da3dc9764   5 weeks ago      231MB
portainer/portainer   latest    580c0e4e98b0   7 months ago     79.1MB
elasticsearch         7.6.2     f29a1ee41030   19 months ago    791MB

在这里插入图片描述
以后我们启动tocmat-test就可以使用最新的tomcat了,不需要再去复制webapps.dist里面的文件到webapps了!!!

鸣谢

本文为狂神说Docker学习笔记
学习地址:https://www.bilibili.com/video/BV1og4y1q7M4

Docker系列
上一章:Docker系列(二)-Dcoker的常用命令

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值