# 镜像
# 标识符
每个 Docker 镜像有三种标识符:
<image_id>
:取自其十六进制哈希值的开头 n 位。- 因为未指定完整的哈希值,只能用于在本机标识镜像,不能在 pull、push 时标识镜像。
<image>@<digest>
:镜像名加完整的哈希值。- 默认采用 SHA256 哈希算法,因此
<digest>
格式为sha256:<hash>
。
- 默认采用 SHA256 哈希算法,因此
<image>[:tag]
:镜像名加标签,由用户自定义。- tag 通常用于表示镜像的版本号。
- 省略 tag 时,默认取值为 latest 。
- 制作镜像时,通常将 latest 标签指向最新一个版本,便于用户拉取。
- 正式使用时,建议不要拉取镜像的 latest 版本,否则在不同时间拉取的 latest 版本可能不同。
悬空镜像(dangling images):一些只有 ID 的镜像,没有镜像名和标签,而是名为
<none>:<none>
。
# 查看
docker
image
ls # 显示本机的镜像(默认不显示悬空镜像)。可简写为 docker images 命令
-a # 显示所有的镜像
history <image> # 显示镜像的构建步骤(按时间倒序排列),包含每个步骤增加的 layer 大小
--no-trunc
rm <image>... # 删除本机的镜像(只能删除未被容器使用的),可简写为 docker rmi 命令
prune # 删除所有悬空镜像
-a # 删除所有未被容器使用的镜像
tag <image>[:tag] <image>[:tag] # 给镜像添加另一个镜像名和标签。如果已有镜像占用目标标签,则将其标签改为 <none>
# 拉取
docker
pull <image>[:tag] # 从镜像仓库拉取镜像,即下载镜像
--platform <os/arch> # 拉取指定平台的镜像。默认只拉取匹配本机操作系统的镜像
push <image>[:tag] # 推送镜像到镜像仓库
search <image> # 在远程镜像仓库中搜索某个镜像
login <domain> # 登录一个镜像仓库。登录凭证会保存在 $HOME/.docker/config.json 中
-u <username>
-p <password>
例:
docker pull nginx:1.20 # 拉取镜像 docker pull nginx # 相当于 docker pull nginx:latest docker tag nginx:1.20 nginx:test # 添加标签
例:拉取镜像的过程
[[email protected] ~]# docker pull nginx:1.20 1.20: Pulling from library/nginx # 开始从镜像仓库拉取镜像 e5ae68f74026: Pull complete # 拉取镜像中的一个 layer ,如果本机已存在则不会拉取 2dc3587e7d0c: Pull complete b8258363a4a3: Pull complete 963807cfb489: Pull complete 5faf54adf667: Pull complete 07bd53fd2d21: Pull complete Digest: sha256:71a1217d769cbfb5640732263f81d74e853f101b7f2b20fcce991a22e68adbc7 # 检验整个镜像的哈希值 Status: Downloaded newer image for nginx:1.20 docker.io/library/nginx:1.20
- 拉取每个 layer 时,分为多个步骤:
Downloading # 下载 layer 的压缩包 Download complete # 下载完毕 Extracting # 解压 layer 并导入,存储在宿主机上 Pull complete # 拉取完毕
- 拉取每个 layer 时,分为多个步骤:
可以将宿主机上存储的 docker 镜像,推送到镜像仓库服务器进行存储。
- 默认采用官方镜像仓库 docker.io ,允许未登录用户 pull 公开镜像。
- 官方还提供了 Web 页面 hub.docker.com ,用于搜索镜像。
- 用户也可以自己部署仓库服务器,比如 harbor 。
- 为了区分不同的镜像仓库,需要在镜像名的前面加上仓库地址:
docker pull harbor.test.com/project1/nginx # 使用指定的镜像仓库,格式为 <仓库域名>/<命名空间>/<镜像名>
- 默认采用官方镜像仓库 docker.io 的 library 命名空间中的镜像,因此以下三种写法的指向相同:
docker pull nginx docker pull docker.io/nginx docker pull docker.io/library/nginx
- 默认采用官方镜像仓库 docker.io ,允许未登录用户 pull 公开镜像。
# 导出
- Docker 镜像由一组 layer 和配置文件组成,在宿主机上存储为一些零散文件,可以用以下命令导出:
docker save -o image.tar <image>... # 将镜像打包成 tar 格式 docker save <image>... | gzip > image.tgz # 打包并压缩,大概压缩到 40% 大小 docker load -i image.tar # 导入镜像
- 例:
[[email protected] ~]# docker save -o nginx.tar nginx:latest [[email protected] ~]# ls -lh total 131M -rw-------. 1 root root 131M Mar 28 16:04 nginx.tar [[email protected] ~]# tar -tf nginx.tar 28d499c51144128e64b6ffefa6c714bbfaf3e55772b080d1b0636f1971cb3203/ # 每个目录对应一层 layer 。目录名是此时导出文件的哈希值,并不等于 layer.tar 的哈希值 28d499c51144128e64b6ffefa6c714bbfaf3e55772b080d1b0636f1971cb3203/VERSION # 该 layer 的格式规范,目前为 1.0 28d499c51144128e64b6ffefa6c714bbfaf3e55772b080d1b0636f1971cb3203/json # 该 layer 的配置文件,记录了其 id、父级 layer 的 id、构建时的 container_config 28d499c51144128e64b6ffefa6c714bbfaf3e55772b080d1b0636f1971cb3203/layer.tar # 该 layer 包含的所有文件 40aef34ac16b8c7eee6da1869452f5c9b9963ab583415d4999565738c719ded9/ 40aef34ac16b8c7eee6da1869452f5c9b9963ab583415d4999565738c719ded9/VERSION 40aef34ac16b8c7eee6da1869452f5c9b9963ab583415d4999565738c719ded9/json 40aef34ac16b8c7eee6da1869452f5c9b9963ab583415d4999565738c719ded9/layer.tar 456351a127e9a9ce4cc79f7f6ad9f401d1714e514780f1603fa0b263119e329b/ 456351a127e9a9ce4cc79f7f6ad9f401d1714e514780f1603fa0b263119e329b/VERSION 456351a127e9a9ce4cc79f7f6ad9f401d1714e514780f1603fa0b263119e329b/json 456351a127e9a9ce4cc79f7f6ad9f401d1714e514780f1603fa0b263119e329b/layer.tar 9000127bc2e7878a10491bb7a16a4b5874e4bdf6a01952d14211fad55defdd0a/ 9000127bc2e7878a10491bb7a16a4b5874e4bdf6a01952d14211fad55defdd0a/VERSION 9000127bc2e7878a10491bb7a16a4b5874e4bdf6a01952d14211fad55defdd0a/json 9000127bc2e7878a10491bb7a16a4b5874e4bdf6a01952d14211fad55defdd0a/layer.tar b526b761d738d1fba0774ea5af56ae1e664c812c6ce75743d74773cb3867bf7b/ b526b761d738d1fba0774ea5af56ae1e664c812c6ce75743d74773cb3867bf7b/VERSION b526b761d738d1fba0774ea5af56ae1e664c812c6ce75743d74773cb3867bf7b/json b526b761d738d1fba0774ea5af56ae1e664c812c6ce75743d74773cb3867bf7b/layer.tar b8cf2cbeabb915843204ceb7ef0055fecadd55c2b0c58ac030e01fe75235885a.json # 一个以镜像哈希值为名的 JSON 文件,记录该镜像的详细配置 c0b073121bb2a6106dae6af85ade7274253f26626661e6e3cb20b0fa7fb59475/ c0b073121bb2a6106dae6af85ade7274253f26626661e6e3cb20b0fa7fb59475/VERSION c0b073121bb2a6106dae6af85ade7274253f26626661e6e3cb20b0fa7fb59475/json c0b073121bb2a6106dae6af85ade7274253f26626661e6e3cb20b0fa7fb59475/layer.tar manifest.json # 镜像的内容清单,记录了镜像名、tag、JSON 配置文件的路径、各个 layer 的路径 repositories
- docker pull 命令会根据 manifest.json 文件拉取镜像的各个 layer 。如果本机已存在,则不必下载。
- JSON 配置文件的内容示例:
{ "architecture": "amd64", "config": { // 记录该镜像的配置,主要由 Dockerfile 决定 "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "80/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.20.2", "NJS_VERSION=0.7.0", "PKG_RELEASE=1~bullseye"], "Cmd": ["nginx", "-g", "daemon off;"], "Image": "sha256:8e9a1b312fca0584850ce522438997f952010118d95f408add7eed34b8a2462d", "Volumes": null, "WorkingDir": "", "Entrypoint": ["/docker-entrypoint.sh"], "OnBuild": null, "Labels": { "maintainer": "NGINX Docker Maintainers \[email protected]\u003e" }, "StopSignal": "SIGQUIT" }, "container": "d9a5e6a8c2e78750b6e1cf3e1c62542d0d9bac5e5d714744a652974b20b3f987", // 记录构建镜像时的最后一个中间容器 "container_config": { "Hostname": "d9a5e6a8c2e7", ... }, "history": [{ // 记录该镜像的构建步骤,按时间顺序排列 "created": "2021-11-17T02:20:41.91188934Z", "created_by": "/bin/sh -c #(nop) ADD file:a2405ebb9892d98be2eb585f6121864d12b3fd983ebf15e5f0b7486e106a79c6 in / " }, ... { "created": "2021-11-17T10:39:44.423437008Z", "created_by": "/bin/sh -c #(nop) CMD [\"nginx\" \"-g\" \"daemon off;\"]", "empty_layer": true }], "os": "linux", "rootfs": { // 记录组成该镜像的各个 layer 的哈希值。创建容器时需要按先后顺序载入这些 layer ,生成 RootFS 文件系统 "type": "layers", "diff_ids": ["sha256:e1bbcf243d0e7387fbfe5116a485426f90d3ddeb0b1738dca4e3502b6743b325", "sha256:72e7342f59d8d99e69f1a39796e9023fee99f2b9c72bfe75cd7cc8c86b43c918", ...] } }
# 制作
Docker 镜像主要有两种制作方式:
将一个容器提交为镜像:
docker commit <container> <image>[:tag]
- 每次 commit 时,会在原镜像外部加上一层新的 layer 。因此 commit 次数越多,镜像的体积越大。
编写 Dockerfile 文件,然后根据它构建镜像。