[docker] 镜像部分补充
这里补充一下比较少用的,关于镜像的内容
检查镜像
bash
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> ca61c1748170 2 hours ago 1.11GB
node latest 5212d7dd5bd4 3 days ago 1.1GB
mysql latest 374f9fbf70c1 5 days ago 632MB
这里可以看到,<none>
,也就是新建的 node-app 其实比 node 原生的镜像要大 0.01GB,换算一下大概就是 10MB,而这 10MB 的大小差距来源于 node-app 需要下载的依赖。
这是因为 docker 是基于 layered filesystem
去实现的,下一个 layer 的操作会基于当前 layer,而 node-app,也就是一个基于 node 实现的 web server 本质上还是一个 node 项目,因此它不会从 0 开始重新构建一个 node 镜像,再基于新建的 node 镜像去构建当前的 web server。
它只会基于已经构建好的 node------即 image id 为 5212d7dd5bd4
的这个镜像,并基于这一层 layer,继续向上搭建 web server。也因此,<none>
会比 node
要大一些。想要证明这一点非常简单,可以使用 inspect
去查看当前的镜像:
bash
❯ docker image inspect 5212d7dd5bd4
[
{
"Id": "sha256:5212d7dd5bd47bdb28f596750f68fbb475ad051bdba32f5a1d2e6a750069aa81",
"RepoTags": [
"node:latest"
],
"RepoDigests": [
"node@sha256:162d92c5f1467ad877bf6d8a098d9b04d7303879017a2f3644bfb1de1fc88ff0"
],
"Parent": "",
"Comment": "",
"Created": "2024-04-11T12:21:21.646446739Z",
"Container": "5814b0bd41a0adc4f07e9b6449a5afd4f92a40770b89ffeb3f60b0335b0928c5",
"ContainerConfig": {
"Hostname": "5814b0bd41a0",
"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",
"NODE_VERSION=21.7.3",
"YARN_VERSION=1.22.19"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"node\"]"
],
"Image": "sha256:85f0ffd6a031d8a604f7d534e731d4a412a792c39344c2fb4005affe1aba99ba",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.23",
"Author": "",
"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",
"NODE_VERSION=21.7.3",
"YARN_VERSION=1.22.19"
],
"Cmd": [
"node"
],
"Image": "sha256:85f0ffd6a031d8a604f7d534e731d4a412a792c39344c2fb4005affe1aba99ba",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1101251706,
"VirtualSize": 1101251706,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/0120615c0012670dc3d352cdeaeedd8e3aa8dc0008a0a166369f8ee2cffe8bac/diff:/var/lib/docker/overlay2/feef30efd0b7c390e12a4998aa5f08aa13c9fad586ae627bf1626f3b56affb26/diff:/var/lib/docker/overlay2/56e0d197241406562c57c96728af909a7d8c8fded6080d526c72f07ea7384814/diff:/var/lib/docker/overlay2/785fbe8456bd460a93d2c60aa7938899fd06d047b9de9be072ddfa581d1e0605/diff:/var/lib/docker/overlay2/315f0f6be659e15ff235095c3783fffcb93221f209c3076c9d1771687a208b85/diff:/var/lib/docker/overlay2/2ef691d415b3ccd00315d51ad1116bbb516f174b23ecd0d203fe7c4e311a6d9a/diff:/var/lib/docker/overlay2/07b75e22620844e3c3b138f5299a34dcd0f00710ec3fefe1c1640fcc824fc50b/diff",
"MergedDir": "/var/lib/docker/overlay2/67d833bc973de2206a5db2442e0724fcf61f158e7e72a905ffff103357d6ac53/merged",
"UpperDir": "/var/lib/docker/overlay2/67d833bc973de2206a5db2442e0724fcf61f158e7e72a905ffff103357d6ac53/diff",
"WorkDir": "/var/lib/docker/overlay2/67d833bc973de2206a5db2442e0724fcf61f158e7e72a905ffff103357d6ac53/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:c5bb35826823702969891b025087135cceefb084dec1452af5a6fb2938bd9a13",
"sha256:51a9318e6edf3a8fc69a835bb72afad53bd7fe585b9729d588c3def0dc77ba59",
"sha256:2353f7120e0e42dcaa9600a35b3bd17cf6de488379c0be841a239a6562efd7b9",
"sha256:893507f6057f8f0532ae8907fb5470f4a0181181bdbe139c2706d47cc4a88600",
"sha256:3e81cc85b636db8bd382419d540e21e06331c3f1749750219c961c4c309c0068",
"sha256:47181ad0eb6656ac1818b39c8f0300718530f27aa9bcbc9fc5da7cfa8e37fd29",
"sha256:9f017d2bee1ce5a4a4f2516d22d910b595061870a2228051c07547596162a321",
"sha256:3a72264cad047850514e368525894bb1268ac10fcc850d9f2afaaf1ad805e29c"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
❯
这个指令会返回一个 JSON 对象,其中 Layers
这个对象包含构建当前 node 镜像的所有 layers,也就是所有步骤。通过对比另一个 web app 可以看到,node 镜像中的 layer,也出现在了 web app 里:
bash
❯ docker image inspect ca61c1748170 | grep "Layers" -A 13
"Layers": [
"sha256:c5bb35826823702969891b025087135cceefb084dec1452af5a6fb2938bd9a13",
"sha256:51a9318e6edf3a8fc69a835bb72afad53bd7fe585b9729d588c3def0dc77ba59",
"sha256:2353f7120e0e42dcaa9600a35b3bd17cf6de488379c0be841a239a6562efd7b9",
"sha256:893507f6057f8f0532ae8907fb5470f4a0181181bdbe139c2706d47cc4a88600",
"sha256:3e81cc85b636db8bd382419d540e21e06331c3f1749750219c961c4c309c0068",
"sha256:47181ad0eb6656ac1818b39c8f0300718530f27aa9bcbc9fc5da7cfa8e37fd29",
"sha256:9f017d2bee1ce5a4a4f2516d22d910b595061870a2228051c07547596162a321",
"sha256:3a72264cad047850514e368525894bb1268ac10fcc850d9f2afaaf1ad805e29c",
"sha256:d642d5d9404c1015981a4357654edb6e62585f0a3e360dedc32b9a1054905306",
"sha256:d980b0bad384d2f6427264b6ffebd615253c4222bb80111c3950246195c3fd00",
"sha256:27b4fb3629cd609719595a766d142f4780c327deb369f2f5ffca8655dba3e0f6",
"sha256:122bdc195ee2719f701a4144dc2f19f8f429701e823909308762a75492b93d70"
]
可以看到,node 里出现的 8 层 layers,在 web server 里也出现了,下面 grep 一下第一层 layer 的 hash 值:
bash
❯ docker image inspect ca61c1748170 | grep "c5bb35826823702969891b025087135cceefb084dec1452af5a6fb2938bd9a13"
"sha256:c5bb35826823702969891b025087135cceefb084dec1452af5a6fb2938bd9a13",
我个人是觉得 docker 和乐高积木挺像的,都以最小的标准单位去进行构筑
重命名镜像
语法为 docker tag <old_image> <new_image>
⚠️:虽然这里说的是重命名,但是实际上 docker 是会以 new_image
为镜像名去创建一个新的拷贝,同时保留旧的镜像
分享镜像
主要有两个方式可以分享镜像
everyon has a image can create containers based on the image
分享 dockerfile
还是以 node 为案例,这是 github 上,node 的 dockerfile:
这里还是通过一系列的 instructions 去打包一个新的 node 镜像
分享打包好的镜像
另一个简单一点的方法就是将镜像打包好,推到某个远程上,然后以供分享。这样的优势是不用一步一步的 build 这个 image
推镜像
主要有两个推镜像的地方,第一个是 docker hub,这是 docker 官方支持的镜像库。另外一个是私有库,比如说我们公司用的 nexus
共享的方式就是使用 docker push <image_name>
,这样就可以把本地建好的镜像推到远程让人下载
主要的步骤也是很简单,首先需要在 docker hub 上创建一个 repo:
填写必要的信息,和本地维持一致
随后终端上推上去就行了:
bash
❯ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ga/node-app latest ca61c1748170 24 hours ago 1.11GB
mysql latest 374f9fbf70c1 6 days ago 632MB
❯ docker push ga/node-app:latest
The push refers to repository [docker.io/ga/node-app]
122bdc195ee2: Preparing
27b4fb3629cd: Preparing
d980b0bad384: Preparing
d642d5d9404c: Preparing
3a72264cad04: Preparing
9f017d2bee1c: Waiting
47181ad0eb66: Waiting
3e81cc85b636: Waiting
893507f6057f: Waiting
2353f7120e0e: Waiting
51a9318e6edf: Waiting
c5bb35826823: Waiting
denied: requested access to the resource is denied
我这里权限拒绝了,因为没有登录,所以 docker 认为我没有 repo 的权限,这时候可以使用 docker login
登陆,完成验证:
和 inspect 中提到的 layer 结构一样,docker 不会将整个镜像全都推到 docker hub 上,它会查看每一层 layer 是否已经存在 reference,随后只推变动的部分。比如说这里的 node-app 是基于 node 实现的,那么 docker 就会发现 node:latest
这个镜像已经存在,那么它就不会把构建 node 的 layer 推上去,它只会推 repo 上不存在对应 hash 的 layer
拉镜像
这个语法为:docker pull node:20-bookworm-slim
,一般很少用,因为 docker run
就会自动拉取镜像里