通常情况下,Dockerfile中的前三行指令一般是:
FROM 172.29.XX.151/base/jdk1.8.0_202 USER root RUN yum install -y python-devel gcc-* gcc openssh-clients && \yum clean all && \rm -rf /var/cache/yum
其中yum install、yum clean all、rm -rf /var/cache/yum一般是依赖文件的安装清除三件套。
1、yum install -y ……
安装镜像所需的依赖文件。
如果不知道哪些依赖是自己镜像所需的,可以通过不断build,根据报错提示安装对应的依赖:
1)command not found: xxx
说明缺少xxx命令,直接安装包含该命令的包:
yum install -y xxx
2)error while loading shared libraries:libxxx.so.x:cannot open shared object file
说明缺少系统库文件,需要安装包含该库的包。可通过yum provides "*/libxxx.so.x"查找包名,再安装:
yum provides "*/libssl.so.1.1"#假设结果显示包名为openssl-libs,安装该包即可 yum install -y openssl-libs
3)permission denied
可能是依赖包未安装导致的间接错误,先解决其他报错再来看。
清理
这种方式可能会由于多次build产生很多无用的新镜像、层文件,这属于开发阶段的正常现象,这些文件会占用磁盘空间,但可以通过主动清理命令定期删除,避免存储空间被过度占用。
1)最常用:docker system prune
#清理所有未被使用的镜像、层、容器、网络(不含存储卷) docker system prune#参数-a:删除所有未被容器引用的镜像(包含没有标签的中间层) docker system prune -a#参数-f:强制清理,无需确认 docker system prune -af
该方案可用于清理之前那种试错+安装的过程中产生的大部分冗余数据。
2)只删除特定镜像:docker rmi
如果要保留部分有用的镜像,可手动删除试错产生的临时镜像:
#查看所有镜像(包含中间层,带<none>标签的通常是build残留) docker images -a#删除指令镜像 docker rmi 镜像ID/镜像名:标签#删除所有带<none>标签的镜像(build过程中产生的中间层) docker rmi $(docker images -f "dangling=true" -q)
镜像标签为<none>的通常是build过程中,由于多次修改Dockerfile而产生的中间层。
如果删除时提示“镜像被容器引用”,可先删除引用该镜像的容器(docker rm 容器ID),再删除镜像。
2、yum clean all、rm -rf /var/cache/yum
dockerfile中通过yum install安装的依赖,默认会将安装包(.rpm)保存到容器内的绝对路径/var/cache/yum目录下。这是yum包管理器的默认行为,目的是为了后续重复安装同一软件时无需重新下载,提高效率。
1)缓存的具体路径
/var/cache/yum/ ├── <架构>(如 x86_64) │ └── 7(系统版本) │ ├── base(基础仓库) │ ├── extras(额外仓库) │ └── updates(更新仓库) │ └── packages(实际缓存的 .rpm 安装包)
当执行yum install <包名>时,下载的.rpm文件会被保存在对应仓库的packages目录下。
2)缓存的作用与问题
作用:重复安装同一软件时,yum会直接使用缓存的.rpm文件而无需重新下载,加快安装速度。
问题:这些缓存文件对运行中的容器没有作用,但会占用镜像空间(每层的RUN yum install都会保留这些缓存)。
3)清理缓存
为了减少镜像体积,必须在安装依赖之后清理这些缓存,且清理命令需与安装命令放在同一RUN指令中,否则缓存会被固化到上一层的镜像层中:
RUN yum install -y openssl-libs \&& yum clean all \ # 清理 yum 缓存(包括元数据和安装包)&& rm -rf /var/cache/yum/* # 彻底删除缓存目录(确保无残留)
后两行的yum clean all和rm -rf /var/cache/yum/*就是清理缓存的指令。
- yum clean all:yum自带的清理命令,删除.rpm安装包、仓库元数据;
- rm -rf /var/cache/yum/*:额外删除缓存目录本身,避免残留空目录或未清理干净的文件;
其实从作用上来看,rm -rf /var/cache/yum/基本覆盖了yum clean all的大部分功能,但在实际使用中,二者还是结合使用,这是因为yum包管理器有自己的缓存管理机制,yum clean all不仅会删除缓存rpm我呢间,还会更新yum内部的缓存索引,避免后续执行yum命令时因缓存文件被手动删除而出现异常。
组合使用yum clean all && rm -rf /var/cache/yum/已成为Docker社区的约定俗成的实践写法。
3、rpm文件的安装、使用时机
安装与删除
yum install安装的依赖会被正常使用,而rm -rf仅删除的是安装包缓存(.rpm),不影响已安装的依赖本身。
yum install的工作结果有两个:1)先从yum仓库下载对应软件的.rpm安装包(存到/var/cache/yum);2)执行安装过程:将软件的可执行文件、库、配置等解压并复制到对应目录(/usr/bin、/usr/lib、/etc)。类似于下载某个压缩文件并解压的过程。
rm -rf会将.rpm文件删除,相当于把压缩文件删除,但是已经解压完成的文件(即之前安装的依赖,如/usr/bin/curl、/usr/lib/libssl.so库文件等依然存在)。
使用
安装的依赖会在两个阶段被使用:
build(构建)阶段:如果后续的RUN指令需要调用这些依赖,如RUN curl http://example.com需要用curl命令,如果此时依赖已经安装,命令可以正常执行。
run(运行)阶段:容器启动后(执行CMD或ENTRYPOINT时),应用程序会调用这些依赖(如Node.js用用需要libssl库来寄哪里HTTPS连接),此时依赖早已存在于镜像的文件系统中,可直接使用。