news 2026/9/30 8:55:35

Docker(七) Docker镜像

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker(七) Docker镜像

Docker 镜像是什么

  • Docker image 本质上是一个 read-only只读文件, 这个文件包含了文件系统、源码、库文件、依赖、工具等一些运行 application 所必须的文件. (类似纳戒, 可随时随地使用炼丹)
  • 我们可以把 Docker image 理解成一个模板, 可以通过这个模板实例化出来很多容器. ( image 和 container 就类似 类与对象 的关系, )
  • image 里面是一层层文件系统 Union FS。联合文件系统,可以将几层目录挂载到一起,形成一个虚拟文件系统.
    每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker镜像中每一层文件系统都是只读的。

Docker 镜像由多个只读 layer 组成,每一层只保存相对于下一层的文件变化。

举例:

layer1 Ubuntu 基础层 / ├── bin/ │ └── bash ├── etc/ │ ├── os-release │ └── example.conf 内容:version=1 ├── usr/ │ └── bin/ │ └── apt └── var/ └── log/ └── apt/ └── history.log Layer 2 Nginx 安装层 / ├── etc/ ← 与 Layer 1 重合 │ ├── nginx/ │ │ └── nginx.conf │ └── example.conf 内容:version=2 ├── usr/ ← 与 Layer 1 重合 │ └── sbin/ │ └── nginx └── var/ ← 与 Layer 1 重合 ├── log/ │ └── nginx/ │ └── access.log └── www/ └── html/ └── index.html 内容:Welcome to nginx! Layer 3 · 自定义网页层 / └── var/ ← 与前两层重合 └── www/ ← 与 Layer 2 重合 └── html/ └── index.html 内容:Hello Docker!

最终容器看到的, 同名目录合并内容,同名文件由上层遮盖下层. 比如etc目录下不重叠的部分(os-release和nginx)被合并, 重叠的部分(example.conf)被更高层覆盖:

为什么设计镜像

主要有两个目的:

  1. 为了屏蔽环境差异解决云端和本地一致性的问题
    由于开发环境和测试环境不一致, 所以在应用部署到一个新环境时, 如果通过手工或写一些脚本的方式进行部署, 用户为每个应用打包过程比较繁琐,需要配置和给中修改等操作,非常费劲, 还可能出错。
  2. 加速软件分发速度, 节省存储空间.
    如果有一天需要把软件部署到十个机器上, 但是这些机器的环境都不一样, 每个环境重新部署一次很麻烦, 而如果目标机器上安装了Docker, 只需要运行几行命令就可以把仓库里发布的镜像一键部署上去.

如果一台 Ubuntu 的机器上存了成千上万份docker镜像, 那所占的空间会非常大, 但是如果所有镜像都是基于Ubuntu,多个容器不需要各自复制一份完整的 ubuntu文件系统, 只需要共享一份即可.

docker 最大的贡献就是定义了容器镜像的分层的存储格式, docker 镜像技术的基础是联合文件系统(UnionFS), 其文件系统是分层的. 这样既可以充分利用共享层, 又可以减少存储空间占用.

打包的缺点:

  1. 如果我们一个软件可能就200K, 但是打包上OS之后多了几十M, 那软件就变大了, 但是这个问题相比于解决环境差异来说, 是相对可控的.
  2. 分层带来的问题: OverlayFS 需要按照层的优先级查找文件:如果上层存在同名文件,就使用上层版本;如果不存在,再考虑下层。因此,层数较多时,某些首次文件查找操作可能产生额外开销。如果我们要找最下层的一个文件, 可能我们要从上到下找一遍, 到最后一层才找到, 可能有性能损失.

Docker 镜像命令

Docker镜像命令概述:

命令别名功能备注
docker imagesdocker image ls / docker image list列出本地镜像必须掌握
docker tagdocker image tag给镜像打标签,可用于推送镜像仓库必须掌握
docker pulldocker image pull从镜像仓库拉取镜像和镜像仓库命令相同,也可以归类为镜像操作命令,必须掌握
docker pushdocker image push推送镜像到仓库和镜像仓库命令相同,也可以归类为镜像操作命令,必须掌握
docker rmidocker image rm / docker image remove删除本地镜像必须掌握
docker builddocker image build通过 Dockerfile 制作镜像必须掌握
docker savedocker image save将指定镜像保存成 tar 归档文件必须掌握
docker loaddocker image load导入使用 docker save 命令导出的镜像必须掌握
docker image inspect—查看镜像详细信息必须掌握
docker historydocker image history查看镜像历史—
docker importdocker image import从归档文件 docker export 中创建镜像—
docker image prune—删除不使用的镜像—

docker images, docker tag, docker pull, docker push

见 Dokcer(六) Docker镜像仓库

docekr rmi

功能: 删除镜像.
语法

dockerrmi[OPTIONS]IMAGE[IMAGE...]

别名: docker image rm, docker image remove

关键参数:

  • -f :强制删除;
  • –no-prune :不移除该镜像的过程镜像,默认移除;

如果镜像没有容器在使用, 正常删除即可:

root@zzy-virtual-machine:/var/lib/containerddockerimages i Info → U In Use IMAGE ID DISK USAGE CONTENT SIZE EXTRA busybox:1.35.0 98ad9d1a2be36.55MB2.15MB busybox:1.37.0 bdf57e528e456.77MB2.22MB busybox:1.38.0 fd7dc98638c86.81MB2.23MB root@zzy-virtual-machine:/var/lib/containerddockerrmi busybox:1.35.0 Untagged: busybox:1.35.0 Deleted: sha256:98ad9d1a2be345201bb0709b0d38655eb1b370145c7d94ca1fe9c421f76e245a

如果镜像在被容器使用, 正确的删除方法是, 先删除容器, 再删除镜像:

# 容器在被使用, 不能直接删除镜像root@zzy-virtual-machine:/var/lib/containerddockerrmi busybox:1.35.0 Error response from daemon: conflict: unable to delete busybox:1.35.0(must be forced)- container b2285fde9b98 is using its referenced image 98ad9d1a2be3# 先删除容器root@zzy-virtual-machine:/var/lib/containerddockerrmb2285fde9b98 b2285fde9b98# 删除镜像root@zzy-virtual-machine:/var/lib/containerddockerrmi busybox:1.35.0 Untagged: busybox:1.35.0 Deleted: sha256:98ad9d1a2be345201bb0709b0d38655eb1b370145c7d94ca1fe9c421f76e245a

如果镜像在被容器使用, 对repository:tag执行docker rmi -f时会发现只成功Untagged, 并没有Deleted, 虽然我们docker images已经查不到镜像, 但 image 对象仍可能存在,并继续被已有容器引用:

root@zzy-virtual-machine:/var/lib/containerddockerrmi-fbusybox:1.35.0 Untagged: busybox:1.35.0# 98ad9d1a2be3其实是之前busybox:1.35.0的镜像IDroot@zzy-virtual-machine:/var/lib/containerddockerps-aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ca360b22a99c 98ad9d1a2be3"sh"59seconds ago Exited(0)38seconds ago peaceful_allen

然后强制删除 Image ID 后出现 Deleted,表示 image 对象已从 Docker 镜像存储中删除; 但容器仍然存在, 容器 snapshot 所需的数据不会因此被粗暴删除

root@zzy-virtual-machine:/var/lib/containerddockerrmi 98ad9d1a2be3 Error response from daemon: conflict: unable to delete 98ad9d1a2be3(must be forced)- image is being used by stopped container ca360b22a99c root@zzy-virtual-machine:/var/lib/containerddockerrmi-f98ad9d1a2be3 Deleted: sha256:98ad9d1a2be345201bb0709b0d38655eb1b370145c7d94ca1fe9c421f76e245a
# 此时容器依然存在root@zzy-virtual-machine:/var/lib/containerddockerps-aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ca360b22a99c 98ad9d1a2be3"sh"3minutes ago Exited(0)2minutes ago peaceful_allen# 容器删除了, 相关 layer/snapshot 已经完全没人引用, 才能够回收对应存储空间root@zzy-virtual-machine:/var/lib/containerddockerrmca360b22a99c ca360b22a99c

所以我们还是按照先删除容器, 再删除镜像的顺序进行删除.

最后来一个场景:
已经有一个镜像busybox:1.37.0, 然后我给它打了两个tag, 分别是cutettsx/test:v1.0和cutettsx/test:v2.0:

root@zzy-virtual-machine:/var/lib/containerddockertag busybox:1.37.0 cutettsx/test:v1.0 root@zzy-virtual-machine:/var/lib/containerddockertag busybox:1.37.0 cutettsx/test:v2.0 root@zzy-virtual-machine:/var/lib/containerddockerimages i Info → U In Use IMAGE ID DISK USAGE CONTENT SIZE EXTRA busybox:1.37.0 bdf57e528e456.77MB2.22MB cutettsx/test:v1.0 bdf57e528e456.77MB2.22MB cutettsx/test:v2.0 bdf57e528e456.77MB2.22MB

分别用cutettsx/test:v1.0和cutettsx/test:v2.0启动两个容器然后退出, 注意看docker ps -a的IMAGE列:

root@zzy-virtual-machine:/var/lib/containerddockerrun-itcutettsx/test:v1.0sh/# exitroot@zzy-virtual-machine:/var/lib/containerddockerrun-itcutettsx/test:v2.0sh/# exitroot@zzy-virtual-machine:/var/lib/containerddockerps-aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9048e0faf36c cutettsx/test:v2.0"sh"10seconds ago Exited(0)5seconds ago musing_lichterman 8353e9f0f04d cutettsx/test:v1.0"sh"16seconds ago Exited(0)12seconds ago compassionate_shamir

然后docker rmi cutettsx/test:v1.0删除掉一个镜像, 可以发现虽然镜像在被使用, 但是删除并没有报错, 而是Untagged成功, 但是并没有Deleted, 因为之前docker tag只是打了个标签, 底层依然是被引用的镜像; 然后docker ps -a之后, 发现对应容器的IMAGE列从cutettsx/test:v1.0变成bdf57e528e45, 这其实就是busybox:1.37.0的镜像ID:

root@zzy-virtual-machine:/var/lib/containerddockerrmi cutettsx/test:v1.0 Untagged: cutettsx/test:v1.0 root@zzy-virtual-machine:/var/lib/containerddockerps-aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9048e0faf36c cutettsx/test:v2.0"sh"About a minute ago Exited(0)About a minute ago musing_lichterman 8353e9f0f04d bdf57e528e45"sh"About a minute ago Exited(0)About a minute ago compassionate_shamirdockerimages|grepbusybox:1.37.0 busybox:1.37.0 bdf57e528e456.77MB2.22MB U

删除cutettsx/test:v2.0, 也是类似的现象

dockerrmi cutettsx/test:v2.0 Untagged: cutettsx/test:v2.0 root@zzy-virtual-machine:/var/lib/containerddockerps-aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9048e0faf36c bdf57e528e45"sh"2minutes ago Exited(0)2minutes ago musing_lichterman 8353e9f0f04d bdf57e528e45"sh"2minutes ago Exited(0)2minutes ago compassionate_shamir

最后我们试图删除镜像bdf57e528e45, 才报错, 因为我们这已经是最后一个镜像ID, 这之后我们要删除镜像, 就只能先删除容器, 再删除镜像了 :

dockerrmi bdf57e528e45 Error response from daemon: conflict: unable to delete bdf57e528e45(must be forced)- image is being used by stopped container 8353e9f0f04d
# 删除容器root@zzy-virtual-machine:/var/lib/containerddockerrm9048e0faf36c 8353e9f0f04d 9048e0faf36c 8353e9f0f04d# 删除镜像root@zzy-virtual-machine:/var/lib/containerddockerrmi bdf57e528e45 Untagged: busybox:1.37.0 Deleted: sha256:bdf57e528e45e4433820e045b29b4597825a1c9e38353532d90a01445013f82e

docker save

功能: 将指定镜像保存成 tar 归档文件。
语法:

dockersave[OPTIONS]IMAGE[IMAGE...]

别名: docker image save
关键参数: -o :输出到的文件。

# 保存一个镜像sudodockersave-omybusybox1.tar busybox:1.37.0# 保存多个镜像sudodockersave-omybusybox2.tar busybox:1.37.0 busybox:1.38.0
zzy@zzy-virtual-machine:~$ ll-hmybusybox* -rw-------1root root2.2M9月2819:34 mybusybox1.tar -rw-------1root root4.3M9月2819:34 mybusybox2.tar

docker load

功能: 导入使用 docker save 命令导出的镜像。
语法:

dockerload[OPTIONS]

别名:

dockerimage load

关键参数:

  • –input , -i : 指定导入的文件,代替 STDIN
  • –quiet , -q : 精简输出信息

首先可以看到, 我们没有busybox相关的镜像:

sudodockerimages i Info → U In Use IMAGE ID DISK USAGE CONTENT SIZE EXTRA centos:7 be65f488b776 301MB76.1MB U cutettsx/test:1.23.3 f4e3b6489888 214MB56.9MB cutettsx/test:v1.0 fd7dc98638c86.81MB2.23MB hello-world:latest 5e230903533223.5kB7.08kB nginx:1.24.0 f6daac2445b0 218MB60.1MB U

然后把我们刚才docker save的tar包给docker load出来:

zzy@zzy-virtual-machine:~$sudodockerload-imybusybox2.tar Loaded image: busybox:1.37.0 Loaded image: busybox:1.38.0

发现busybox:1.37.0和busybox:1.38.0镜像都出现了:

zzy@zzy-virtual-machine:~$sudodockerimages i Info → U In Use IMAGE ID DISK USAGE CONTENT SIZE EXTRA busybox:1.37.0 bdf57e528e456.77MB2.22MB busybox:1.38.0 fd7dc98638c86.81MB2.23MB centos:7 be65f488b776 301MB76.1MB U cutettsx/test:1.23.3 f4e3b6489888 214MB56.9MB cutettsx/test:v1.0 fd7dc98638c86.81MB2.23MB hello-world:latest 5e230903533223.5kB7.08kB nginx:1.24.0 f6daac2445b0 218MB60.1MB U

docker history

功能: 显示镜像历史
语法:

docker history [OPTIONS] IMAGE

别名:

docker image history

关键参数:

  • -H , --human :大小和日期采用人容易读的格式展现, 默认开了
  • –no-trunc :显示全部信息,不要隔断, 默认没开, 如果开启显示格式会很长, 不易读;
  • -q, --quiet: 只显示镜像 id 信息;

看一下busybox镜像的层数, 发现就只有一层:

sudodockerhistorybusybox:1.38.0 IMAGE CREATED CREATED BY SIZE COMMENT fd7dc98638c84months ago BusyBox1.38.0(glibc), Debian134.58MB

列名从左到右依次是层ID,层创建时间,创建的dockerfile命令,大小,注释

再看一下nginx镜像的层结构:

sudodockerhistorynginx:1.24.0 IMAGE CREATED CREATED BY SIZE COMMENT f6daac2445b03years ago CMD["nginx""-g""daemon off;"]0B buildkit.dockerfile.v0<missing>3years ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0<missing>3years ago EXPOSE map[80/tcp:{}]0B buildkit.dockerfile.v0<missing>3years ago ENTRYPOINT["/docker-entrypoint.sh"]0B buildkit.dockerfile.v0<missing>3years ago COPY30-tune-worker-processes.sh /docker-ent…16.4kB buildkit.dockerfile.v0<missing>3years ago COPY20-envsubst-on-templates.sh /docker-ent…12.3kB buildkit.dockerfile.v0<missing>3years ago COPY10-listen-on-ipv6-by-default.sh /docker…12.3kB buildkit.dockerfile.v0<missing>3years ago COPY docker-entrypoint.sh /# buildkit 8.19kB buildkit.dockerfile.v0<missing>3years ago RUN /bin/sh-cset-x&&addgroup --syst… 65MB buildkit.dockerfile.v0<missing>3years ago ENVPKG_RELEASE=1~bullseye 0B buildkit.dockerfile.v0<missing>3years ago ENVNJS_VERSION=0.7.12 0B buildkit.dockerfile.v0<missing>3years ago ENVNGINX_VERSION=1.24.0 0B buildkit.dockerfile.v0<missing>3years ago LABELmaintainer=NGINX Docker Maintainers<d… 0B buildkit.dockerfile.v0<missing>3years ago /bin/sh-c#(nop) CMD ["bash"] 0B<missing>3years ago /bin/sh-c#(nop) ADD file:5d6b639e8b6bcc011… 92.7MB

docker image prune

功能: 删除不使用的镜像。

什么是不使用的镜像?

  1. 只要容器不使用, 就认为是不使用的镜像(这种理解比较危险, 因为我可能后面还要用, 现在只是pull下来了).
  2. 虚悬镜像dangling image, (也叫空悬镜像)

语法:

dockerimage prune[OPTIONS]

关键参数:

  • -a , --all : 删除全部不使用的镜像.
    • 加上-a选项, 是指容器不使用的镜像.
    • 默认是指虚悬镜像
  • –filter filter: 指定过滤条件
  • -f, --force : 不提示是否删除

综合案例

案例一: 离线迁移

如果我们无法联网, 不能docker pull和docker push, 所以我们只能用docker save和docker load.
现在有两个服务器, 服务器1是Ubuntu, 服务器2是Windows, 首先确保两台服务器都安装了docker.

服务器 1 上将镜像保存为 tar 文件:

dockersave-omybusybox.tar busybox:1.38.0

服务器2 上获取该 tar 文件, 并加载:

# Windows系统下用scp把ubuntu下的mybusybox.tar拷贝过来scp用户名@192.168.xxx.xxx:/data/xxx/mybusybox.tar C:\Users\xxx# 此时Windows上什么镜像都没有dockerimages i Info → U In Use IMAGE ID DISK USAGE CONTENT SIZE EXTRA# docker load加载镜像dockerload-i.\mybusybox.tar Loaded image: busybox:1.38.0# 查看镜像dockerimages i Info → U In Use IMAGE ID DISK USAGE CONTENT SIZE EXTRA busybox:1.38.0 fd7dc98638c86.81MB2.23MB# 运行镜像, 发现可以正常使用dockerrun-itbusybox:1.38.0sh/# busybox ifconfigeth0 Link encap:Ethernet HWaddr E6:7B:96:82:24:74 inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:17 errors:0 dropped:0 overruns:0 frame:0 TX packets:3 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:1698(1.6KiB)TX bytes:126(126.0B)lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0(0.0B)TX bytes:0(0.0B)/# busybox lsbin dev etc home lib lib64 proc root sys tmp usr var /# busybox ping www.baidu.comPING www.baidu.com(180.101.51.73):56data bytes64bytes from180.101.51.73:seq=0ttl=63time=10.091ms64bytes from180.101.51.73:seq=1ttl=63time=15.014ms64bytes from180.101.51.73:seq=2ttl=63time=10.399ms ^C --- www.baidu.compingstatistics ---3packets transmitted,3packets received,0% packet loss round-trip min/avg/max=10.091/11.834/15.014 ms

案例二:

  1. 看看镜像在云端和本地是怎么存储的

nginx:1.21.1镜像在服务端的镜像大小为51.26 MB:

pull到本地之后, 发现占用200MB大小:

root@zzy-virtual-machine:/home/zzydockerimages|grepnginx nginx:1.21.1 a05b0cdd4fc1 200MB53.8MB

这说明服务端的镜像比拉到本地后占用空间小, 可以理解为服务端存储了一个压缩包, 下载到本地后被解压出来. 这样在服务端占用空间少, 而且传输文件也节省带宽.

  1. 服务端是否给1000个镜像, 就存放1000份

可以看到, 添加一个新的镜像(docker push cutettsx/test:v1)到我们的仓库的时候,如果 docker hub 发现已经有了是 mount 的,不是从本地推上去的;

然后把一个镜像打多个 tag (docker push cutettsx/test:v2), 推送给仓库, 可以看到是说层已经存在, 并不会重复存储

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 8:55:10

Paperclip:本地AI开发的轻量级进程胶水层设计与实践

1. 项目概述&#xff1a;Paperclip 不是回形针&#xff0c;而是一个被严重误读的 AI 工具链枢纽 “Paperclip”这个词在中文技术社区里&#xff0c;最近三个月搜索量暴涨了470%&#xff0c;但绝大多数人点进去后都愣住了——搜出来的不是 Office 文档里的那个金属小物件&#x…

作者头像 李华
网站建设 2026/9/30 8:54:30

AI误删生产库怎么防?中科热备云上容灾全流程解析

先说一个我亲历的场景。凌晨三点&#xff0c;一套AI运维Agent按巡检计划自动执行任务&#xff0c;因为某种流量异常触发了自动化处置逻辑&#xff0c;Agent判定某张业务表中的数据“可疑”&#xff0c;直接下了一条DROP TABLE。操作完成后&#xff0c;它在群里发了条消息&#…

作者头像 李华
网站建设 2026/9/30 8:54:18

模型驱动低代码平台:数据定义先行,项目才能越做越顺

很多团队选低代码平台&#xff0c;第一眼看的都是拖拽界面顺不顺手、控件多不多、长得够不够好看。这个切入点本身就有问题——真正决定一个低代码项目半年后是越做越顺还是越做越乱的&#xff0c;从来不是画界面有多快&#xff0c;而是平台背后是不是“数据模型驱动”的。数据…

作者头像 李华
网站建设 2026/9/30 8:53:00

Spring Boot自动配置排除实战:原理、四种方式与踩坑指南

Spring Boot 的自动配置&#xff08;AutoConfiguration&#xff09;是它最讨喜的特性之一&#xff0c;但也是很多人在项目里跟它斗智斗勇的地方。默认情况下&#xff0c;只要类路径里有对应的依赖&#xff0c;Spring Boot 就替你装配好一大堆 Bean&#xff0c;省事是真省事&…

作者头像 李华
网站建设 2026/9/30 8:52:55

Univer 在线表格引擎实战:Canvas 渲染与 Facade API 协同开发指南

1. 从“univer”这个标题说起&#xff1a;它到底是什么&#xff0c;能解决什么问题 第一次看到“univer”这个词&#xff0c;很多人会以为是“universe”的缩写&#xff0c;或者某个新出的前端框架。实际上&#xff0c;Univer 是一个开源的在线电子表格与文档协作引擎&#xff…

作者头像 李华