镜像是什么?
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
所有的应用直接打包成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等。
平时我们安装进虚拟机的Ubuntu都是好几个G,为什么Docker这里才不过100M?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host(主机)的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不用的发现版可以共用bootfs。
- 虚拟机分钟级启动,容器是秒级启动。
分层理解
分层的镜像 我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
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"
}
}
]
特点 Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层。
commit镜像
# docker commit 提交容器成为一个新的副本
# 命令和git原理类似
# docker commit -m="commit info" -a="author" 容器id 目标镜像名:[t=TAG]
实战测试
- 启动一个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
如果暴露端口的话外界也可以访问
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来提交,获得一个镜像。相当于虚拟机的快照功能!