大家好,我是张晋涛。
本周 Docker 就发布 10 周年了,为了庆祝这个里程碑,我将会发布一系列文章,涉及 Docker,CI/CD, 容器等各个方面。
“Docker 可谓是开启了容器化技术的新时代,现在无论大中小公司基本上都对容器化技术有不同程度的尝试,或是已经进行了大量容器化的改造。伴随着 Kubernetes 和 Cloud Native 等技术和理念的普及,也大大增加了业务容器化需求。而这一切的推进,不可避免的技术之一便是构建容器镜像。
”
Docker 镜像是什么
在真正实践之前,我们需要先搞明白几个问题:
Docker 镜像是什么
Docker 镜像的作用
容器和镜像的区别及联系
Docker 镜像是什么
这里,我们以一个 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:f81bf5a8b57d6aa1824e4edb9aea6bd5ef6240bcc7d86f303f197a2eb77c430f
Status: Downloaded newer image for debian:latest
root@860f21595fb6:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
看终端的日志,Docker CLI 首先会查找本地是否有 debian
的镜像,如果没有则从镜像仓库(若不指定,默认是 DockerHub)进行 pull; 将镜像 pull 到本地后,再以此镜像来启动容器。
我们可以先退出此容器,来看看 Docker 镜像到底是什么。用 docker image ls
来查看已下载好的镜像:
(MoeLove) ➜ docker image ls debian
REPOSITORY TAG IMAGE ID CREATED SIZE
debian latest 72b624312240 2 weeks ago 124MB
用 docker image save
命令将镜像保存成一个 tar 文件:
(MoeLove) ➜ mkdir debian-image
(MoeLove) ➜ docker image save -o debian-image/debian.tar debian
(MoeLove) ➜ ls debian-image/
debian.tar
将镜像文件进行解压:
(MoeLove) ➜ tar -C debian-image/ -xf debian-image/debian.tar
(MoeLove) ➜ tree -I debian.tar debian-image/
debian-image/
├── 72b6243122405be2c5c5e7e20d410f4c8fe301e1ce84cc60ea591b63167750e6.json
├── 7a66e59f40fd03d0e7bfaebe419af6a2c409ef8f513d037e3b1ebb8cbc803ec2
│ ├── VERSION
│ ├── json
│ └── layer.tar
├── manifest.json
└── repositories
1 directory, 6 files
可以看到将镜像文件解压后,包含的内容主要是一些配置文件和 tar 包。
接下来我们来具体看看其中的内容,并通过这些内容来理解镜像的组成。
manifest.json
(MoeLove) ➜ cd debian-image/
(MoeLove) ➜ cat manifest.json | jq
[
{
"Config": "72b6243122405be2c5c5e7e20d410f4c8fe301e1ce84cc60ea591b63167750e6.json",
"RepoTags": [
"debian:latest"
],
"Layers": [
"7a66e59f40fd03d0e7bfaebe419af6a2c409ef8f513d037e3b1ebb8cbc803ec2/layer.tar"
]
}
]
注意:在实际存储时,是不包含换行的,这里为了便于展示所以使用了 jq
工具进行格式化。
manifest.json
包含了镜像的顶层配置,它是一系列配置按顺序组织而成的;以现在我们的 debian
镜像为例,它至包含了一组配置,这组配置中包含了 3 个主要的信息,我们由简到繁进行说明。
RepoTags
RepoTags
表示镜像的名称和 tag ,这里简要的对此进行说明:RepoTags
其实分为两部分:
Repo
: Docker 镜像可以存储在本地或者远端镜像仓库内,Repo 其实就是镜像的名称。 Docker 默认提供了大量的官方镜像存储在 Docker Hub 上,对于我们现在在用的这个 Docker 官方的 debian 镜像而言,完整的存储形式其实是docker.io/library/debian
,只不过 docker 自动帮我们省略掉了前缀。Tag
: 我们可以通过repo:tag
的方式来引用一个镜像,默认情况下,如果没有指定 tag (像我们上面操作的那样),则会 pull 下来最新的镜像(即:latest)
Config
Config
字段包含的内容是镜像的全局配置。我们来看看具体内容:
(MoeLove) ➜ cat 72b6243122405be2c5c5e7e20d410f4c8fe301e1ce84cc60ea591b63167750e6.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"
],
"Image": "sha256:f8f185aa88c5b07710b327c1c8fd02c8d264bdcce11877d337b9d5c739015cea",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "f41eadbc246cbece89086679da07f3b0d1508234aab4932acab7cbdc8ae63a9c",
"container_config": {
"Hostname": "f41eadbc246c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"Attac