5.3 镜像管理
镜像&容器清理
<none>
:<none> iamge
: 它们代表中间映像,可以使用docker images -a
看到,它们不会导致磁盘空间问题,但这绝对是屏幕空间问题。<none>
:<none> —— dangling=true
(会导致磁盘空间问题),可用docker image prune
清除,可释放磁盘空间。
1. 批量删除 tag 为 None 的镜像
描述 :
原因 :有时候重新构建镜像(build) 的时候,该镜像正在被某容器使用中,那么在重新构建同名同版本镜像后,docker 保留原来的镜像,即容器还是用原来的,除非重启。那么原来的镜像名称变成 NONE,TAG 也成了 NONE。
解决方法:(4 种方法,慎用)
# 删除镜像
docker images|grep none|awk '{print $3}'|xargs docker rmi
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
# 清除 dangling 悬空镜像,下面二种清除方法
docker image prune
docker rmi $(docker images -f "dangling=true" -q)
2. 清理容器 (可以在镜像清理前操作)
# (推荐)删除停止的容器,可以回容器名。-a 显示所有 正在运行的容器要先停止 stop 才会被删除 rm
docker rm $(docker ps -a -q)
# 清理当前未运行的容器
docker container prune
# 停止正在运行的容器
docker stop $(docker container ls -q)
- 清理镜像和容器
# 清理已停止的容器、没有被容器使用的网络、悬空镜像、悬空构建缓存
$ docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all dangling build cache
镜像体积裁减
体积分析
Docker 镜像是由很多镜像层(Layers)组成的(最多 127 层), Dockerfile 中的每条指定都会创建镜像层,不过 只有 RUN
, COPY
, ADD
会使镜像的体积增加 。这个可以通过命令 docker history image_id
来查看每一层的大小。 这里我们以官方的 alpine:3.12 为例看看它的镜像层情况。
$ docker images |grep alpine
alpine latest 0ac33e5f5afa 5 weeks ago 5.57MB
redis alpine 3900abf41552 5 months ago 32.4MB
python 3.4-alpine c06adcf62f6e 3 years ago 72.9MB
$ docker image ls alpine
$ docker history
# 查看 redis 镜像图层组成,使用 redis 镜像 ID
$ docker history 3900abf41552
IMAGE CREATED CREATED BY SIZE COMMENT
3900abf41552 5 months ago /bin/sh -c #(nop) CMD ["redis-server"] 0B
<missing> 5 months ago /bin/sh -c #(nop) EXPOSE 6379 0B
<missing> 5 months ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
<missing> 5 months ago /bin/sh -c #(nop) COPY file:c48b97ea65422782… 377B
<missing> 5 months ago /bin/sh -c #(nop) WORKDIR /data 0B
<missing> 5 months ago /bin/sh -c #(nop) VOLUME [/data] 0B
<missing> 5 months ago /bin/sh -c mkdir /data && chown redis:redis … 0B
<missing> 5 months ago /bin/sh -c set -eux; apk add --no-cache --… 25.5MB
<missing> 5 months ago /bin/sh -c #(nop) ENV REDIS_DOWNLOAD_SHA=5b… 0B
<missing> 5 months ago /bin/sh -c #(nop) ENV REDIS_DOWNLOAD_URL=ht… 0B
<missing> 5 months ago /bin/sh -c #(nop) ENV REDIS_VERSION=6.2.6 0B
<missing> 5 months ago /bin/sh -c apk add --no-cache 'su-exec>=0.… 1.34MB
<missing> 5 months ago /bin/sh -c addgroup -S -g 1000 redis && addu… 4.7kB
<missing> 5 months ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 5 months ago /bin/sh -c #(nop) ADD file:9233f6f2237d79659… 5.58MB
说明:如上面示例,ADD, apk 命令会带来体积增长,CMD 命令并不占空间。
体积压缩方式
了解了镜像构建中体积增大的原因,那么就可以对症下药**:精简层数 或 精简每一层大小**。
精简层数的方法有如下几种:
1. RUN 指令合并 :指令合并是最简单也是最方便的降低镜像层数的方式。该操作节省空间的原理是在同一层中清理“缓存”和工具软件。
2. 多阶段构建 : 多阶段构建方法是官方打包镜像的最佳实践,它是将精简层数做到极致的方法。通俗点讲它是将打包镜像分成两个阶段,一个阶段用于开发,打包,该阶段包含构建 应用程序所需的所有内容;一个用于生产运行,该阶段只包含你的应用程序以及运行它所需的内容。这被称为“建造者模式”。两个阶段的关系有点像 JDK 和 JRE 的关系。使用多阶段构建肯定会降低镜像大小,但是瘦身的粒度和编程语言有关系,对编译型语言效果比较好,因为它去掉了编译环境中多余的依赖,直接使 用编译后的二进制文件或 jar 包。而对于解释型语言效果就不那么明显了。
精简每一层的方法有如下几种:
- 使用合适的基础镜像 (首 选 alpine,体积通常较小)Alpine 是一个高度精简又包含了基本工具的轻量级 Linux 发行版,基础镜像只有 4.41M,各开发语言和框架都有基于 Alpine 制作的基础镜像,强烈推荐使用它。进阶可以尝试使用 scratch 和 busybox 镜像进行基础镜像的构建。
- 删除 RUN 的缓存文件
Dockfile 最佳实践
- 编写.dockerignore 文件
- 一个容器只运行单个应用
- 基础镜像和生产镜像的标签不要使用 latest
- 设置 WORKDIR 和 CMD
- 使用 ENTRYPOINT,并用 exec 启动命令(可选)
- 相比 ADD,优先使用 COPY
- 设置默认的环境变量,映射端口和数据卷
- 使用 LABEL 设置镜像元数据
- 添加 HEALTHCHECK
小结
- 多使用 Dockerfile 生成新镜像,减少 commit 方式生成的镜像。每 commit 一次相当于在原有基础镜像上再增加内容(因为 docker 文件系统为 overlay,删除的文件目录仍会占用存储空间)。
本章参考
使用 Docker Stack 部署应用 https://zhuanlan.zhihu.com/p/182198031
Best practices for writing Dockerfiles. https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
Dockerfile 中 ENTRYPOINT 和 CMD 的区别和最佳实践 https://www.jianshu.com/p/54cfa5721d5f
Docker 镜像优化:从 1.16GB 到 22.4MB! https://zhuanlan.zhihu.com/p/427116788
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论