在真正实践之前,我们需要先搞明白几个问题:
这里,我们以一个 Debian 系统的镜像为例。通过 docker run --it debian
可以启动一个 debian
的容器,终端会有如下输出:
/ # docker run -it debian
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
c5e155d5a1d1: Pull complete
Digest: sha256:75f7d0590b45561bfa443abad0b3e0f86e2811b1fc176f786cd30eb078d1846f
Status: Downloaded newer image for debian:latest
root@dc7d057f7014:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root@dc7d057f7014:/#
看终端的日志,首先会查找本地是否有 debian
的镜像,如果没有则从镜像仓库(若不指定,默认是 docker.io)pull;pull 镜像成功后,再以此镜像来启动容器。
我们可以先退出此容器,来看看 Docker 镜像到底是什么。用 docker image ls
来查看已下载好的镜像:
/ # docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
debian latest 8d31923452f8 4 days ago 101MB
用 docker image save
命令将镜像保存成一个 tar 文件:
/ # mkdir debian-image
/ # docker image save -o debian-image/debian.tar debian
/ # ls debian-image/
debian.tar
将镜像文件进行解压:
/ # tar -C debian-image/ -xf debian-image/debian.tar
/ # tree -I debian.tar debian-image/
debian-image/
├── 8d31923452f8b79ae91b01568d28c90e7d667a9eaff9734c6faeb017b0efa8d0.json
├── b50334e3be68f82d0b94bb7d3cfe1789119c040c6c159759f57a19ad34547af3
│ ├── VERSION
│ ├── json
│ └── layer.tar
├── manifest.json
└── repositories
1 directory, 6 files
可以看到将镜像文件解压后,包含的内容主要是一些配置文件和 tar 包。
接下来我们来具体看看其中的内容,并通过这些内容来理解镜像的组成。
/debian-image # cat manifest.json | jq
[
{
"Config": "8d31923452f8b79ae91b01568d28c90e7d667a9eaff9734c6faeb017b0efa8d0.json",
"RepoTags": [
"debian:latest"
],
"Layers": [
"b50334e3be68f82d0b94bb7d3cfe1789119c040c6c159759f57a19ad34547af3/layer.tar"
]
}
]
注意:在实际存储时,是不包含空格的,这里为了便于展示所以使用了 jq 工具进行格式化。
manifest.json
包含了镜像的顶层配置,它是一系列配置按顺序组织而成的;以现在我们的 debian
镜像为例,它至包含了一组配置,这组配置中包含了 3 个主要的信息,我们由简到繁进行说明。
RepoTags
表示镜像的名称和 tag ,这里简要的对此进行说明:RepoTags
其实分为两部分:
Repo
: Docker 镜像可以存储在本地或者远端镜像仓库内,Repo 其实就是镜像的名称。 Docker 默认提供了大量的官方镜像存储在 Docker Hub 上,对于我们现在在用的这个 Docker 官方的 debian 镜像而言,完整的存储形式其实是 docker.io/library/debian
,只不过 docker 自动帮我们省略掉了前缀。Tag
: 我们可以通过 repo:tag
的方式来引用一个镜像,默认情况下,如果没有指定 tag (像我们上面操作的那样),则会 pull 下来最新的镜像(即:latest)Config
字段包含的内容是镜像的全局配置。我们来看看具体内容:
/debian-image # cat 8d31923452f8b79ae91b01568d28c90e7d667a9eaff9734c6faeb017b0efa8d0.json | jq
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"bash"
],
"ArgsEscaped": true,
"Image": "sha256:913ee5b96cb28ad1d43f11df4aeceee963fa07b53edccb3052a21939cae4a041",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "e896ef8effcc3a696087509347ad072bf1ccfbd88e2e9e7a59d20293196bafa3",
"container_config": {
"Hostname": "e896ef8effcc",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"bash\"]"
],
"ArgsEscaped": true,
"Image": "sha256:913ee5b96cb28ad1d43f11df4aeceee963fa07b53edccb3052a21939cae4a041",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
}