【Docker】六、镜像

159 阅读10分钟

镜像是什么?

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

所有的应用直接打包成Docker镜像就可以直接运行起来!

如何得到镜像:

  • 从远程仓库下载
  • 他人拷贝给你
  • 自己制作一个镜像--DockerFile

Docker镜像加载原理

UnionFS(联合文件系统) UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite serveral directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行集成,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

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

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等。 image.png

平时我们安装进虚拟机的Ubuntu都是好几个G,为什么Docker这里才不过100M?

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

  • 虚拟机分钟级启动,容器是秒级启动。

分层理解

分层的镜像 我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!

image.png

Docker镜像为什么要采用这种分层结构呢? 最大的好处莫过于资源共享了。比如有多个镜像都是从相同的Base镜像构建而来,name宿主机只需要在磁盘上保留一份Base镜像,同时内存中也只需要加载一份Base镜像。这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

查看镜像分层方式可以通过docker image inspect命令!

root@lsMusKVEqm:~# docker image inspect tomcat:latest
[
    {
        "Id": "sha256:fb5657adc892ed15910445588404c798b57f741e9921ff3c1f1abe01dbb56906",
        "RepoTags": [
            "tomcat:latest"
        ],
        "RepoDigests": [
            "tomcat@sha256:9dee185c3b161cdfede1f5e35e8b56ebc9de88ed3a79526939701f3537a52324"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-12-22T17:07:13.333084424Z",
        "Container": "de0900b3a6caf902ccdaa1c7871d244e29978119ad8a1cce799cf47f1717b679",
        "ContainerConfig": {
            "Hostname": "de0900b3a6ca",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8080/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/tomcat/bin:/usr/local/openjdk-11/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/usr/local/openjdk-11",
                "LANG=C.UTF-8",
                "JAVA_VERSION=11.0.13",
                "CATALINA_HOME=/usr/local/tomcat",
                "TOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-lib",
                "LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-lib",
                "GPG_KEYS=A9C5DF4D22E99998D9875A5110C01C5A2F6059E7",
                "TOMCAT_MAJOR=10",
                "TOMCAT_VERSION=10.0.14",
                "TOMCAT_SHA512=c2d2ad5ed17f7284e3aac5415774a8ef35434f14dbd9a87bc7230d8bfdbe9aa1258b97a59fa5c4030e4c973e4d93d29d20e40b6254347dbb66fae269ff4a61a5"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"catalina.sh\" \"run\"]"
            ],
            "Image": "sha256:6e2683bf6f13f0050833b6807871b4980142835747139a2c2ae91b274787e399",
            "Volumes": null,
            "WorkingDir": "/usr/local/tomcat",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "20.10.7",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "8080/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/tomcat/bin:/usr/local/openjdk-11/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/usr/local/openjdk-11",
                "LANG=C.UTF-8",
                "JAVA_VERSION=11.0.13",
                "CATALINA_HOME=/usr/local/tomcat",
                "TOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-lib",
                "LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-lib",
                "GPG_KEYS=A9C5DF4D22E99998D9875A5110C01C5A2F6059E7",
                "TOMCAT_MAJOR=10",
                "TOMCAT_VERSION=10.0.14",
                "TOMCAT_SHA512=c2d2ad5ed17f7284e3aac5415774a8ef35434f14dbd9a87bc7230d8bfdbe9aa1258b97a59fa5c4030e4c973e4d93d29d20e40b6254347dbb66fae269ff4a61a5"
            ],
            "Cmd": [
                "catalina.sh",
                "run"
            ],
            "Image": "sha256:6e2683bf6f13f0050833b6807871b4980142835747139a2c2ae91b274787e399",
            "Volumes": null,
            "WorkingDir": "/usr/local/tomcat",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 679618222,
        "VirtualSize": 679618222,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/2e5ec2eae3581b50f1e1de6f065cf9a958baefd94fbe2ab09a0a1421d971eae1/diff:/var/lib/docker/overlay2/4732a4e541162ea267cf28c15f4ae5e4eb3456e6e2b24a1617d6fd62d8449611/diff:/var/lib/docker/overlay2/e64d171dad9de41503655666c6a957e0383bf2f4fe11bea4be1d3fdec2f697b2/diff:/var/lib/docker/overlay2/ba664e9ced7d8929ce5f56cfb29b10c678d288454a533621af69fe6683a45313/diff:/var/lib/docker/overlay2/cb1d42e4f1a96f1ef53c622c74b047ac25686b194db370d2b6de797edd2adf82/diff:/var/lib/docker/overlay2/0010703ad4397e04c60476842569babbfbad8cf4607a1bdc51c0436f183f54c1/diff:/var/lib/docker/overlay2/d350c024843d8f437368a4f5582422ccbd1caa776f1124c6103d9bd0cbefe507/diff:/var/lib/docker/overlay2/fb00a5fb19c27a299f1049263b7f4f7cce456f8838a9546e443a3e4684b4baec/diff:/var/lib/docker/overlay2/625bd08d2f12a7027866da14ce84a823a60308a06b8d0644c71cf2050847c2e7/diff",
                "MergedDir": "/var/lib/docker/overlay2/39c956fa57377278b4d021d818a8c8886c7091e8ee28defc144d1c56a741fb94/merged",
                "UpperDir": "/var/lib/docker/overlay2/39c956fa57377278b4d021d818a8c8886c7091e8ee28defc144d1c56a741fb94/diff",
                "WorkDir": "/var/lib/docker/overlay2/39c956fa57377278b4d021d818a8c8886c7091e8ee28defc144d1c56a741fb94/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:11936051f93baf5a4fb090a8fa0999309b8173556f7826598e235e8a82127bce",
                "sha256:31892cc314cb1993ba1b8eb5f3002c4e9f099a9237af0d03d1893c6fcc559aab",
                "sha256:8bf42db0de72f74f4ef0c1d1743f5d54efc3491ee38f4af6d914a6032148b78e",
                "sha256:26a504e63be4c63395f216d70b1b8af52263a5289908df8e96a0e7c840813adc",
                "sha256:f9e18e59a5651609a1503ac17dcfc05856b5bea21e41595828471f02ad56a225",
                "sha256:832e177bb5008934e2f5ed723247c04e1dd220d59a90ce32000b7c22bd9d9b54",
                "sha256:3bb5258f46d2a511ddca2a4ec8f9091d676a116830a7f336815f02c4b34dbb23",
                "sha256:59c516e5b6fafa2e6b63d76492702371ca008ade6e37d931089fe368385041a0",
                "sha256:bd2befca2f7ef51f03b757caab549cc040a36143f3b7e3dab94fb308322f2953",
                "sha256:3e2ed6847c7a081bd90ab8805efcb39a2933a807627eb7a4016728f881430f5f"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

image.png

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

这一层就是我们通常说的容器层,容器之下的都叫镜像层。

commit镜像

# docker commit 提交容器成为一个新的副本
# 命令和git原理类似
# docker commit -m="commit info" -a="author" 容器id 目标镜像名:[t=TAG]

实战测试

  1. 启动一个tomcat镜像 暴露8080端口
docker run -it -p 8080:8080 tomcat

# 退出容器
Ctrl + P + Q

curl localhost:8080
# 此时会返回404,是因为刚安装的tomcat镜像webapps目录下面是空的

# 所以我们需要从webapps.dist目录下面拷贝文件到webapps下面
root@lsMusKVEqm:~# docker exec -it 6f4674913fb1 /bin/bash
root@6f4674913fb1:/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

cp -r webapps.dist/* webapps/
# 将文件拷贝到webapps目录下

# 再退出容器访问即可正常
curl localhost:8080

如果暴露端口的话外界也可以访问

image.png

2.由于官方提供的tomcat每次都需要以上步骤比较麻烦,我们自己可以将修改过的镜像进行提交

root@lsMusKVEqm:~# docker commit -m="add webapps application" -a="GY_Joker" 6f4674913fb1 tomcat_gyj:1.0.0
sha256:8ee67166756f36a1c44963e57c6952d434e1bdff375ebe83720bdfe250f6f331
root@lsMusKVEqm:~# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
tomcat_gyj   1.0.0     8ee67166756f   7 seconds ago   680MB
tomcat       latest    fb5657adc892   8 days ago      680MB
nginx        latest    f6987c8d6ed5   10 days ago     141MB
mysql        5.7       c20987f18b13   10 days ago     448MB
ubuntu       latest    ba6acccedd29   2 months ago    72.8MB
root@lsMusKVEqm:~# 

如果想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像。相当于虚拟机的快照功能!