Azure Ubuntu虚拟机Docker overlay2目录占用大量磁盘空间排查
Docker overlay2 目录占用超大磁盘空间问题排查与解决
问题背景
在Azure Ubuntu虚拟机上通过docker-compose运行两个自定义镜像,均为本地构建、打标签部署。近期磁盘耗尽,通过df、du工具排查发现/var/lib/docker/overlay2目录占用90GiB空间,其中约99%来自子文件夹的/diff目录——该目录包含node_modules、Gradle构建缓存这类本应仅在构建阶段存在的文件,且overlay2下有数百个镜像层,无法理解为何这些构建文件被持久化。
Spring Gradle后端Dockerfile
FROM gradle:7.3.1-jdk17 AS TEMP_BUILD_IMAGE COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle bootJar FROM eclipse-temurin:17 ENV ARTIFACT_NAME="application-name-0.0.1-SNAPSHOT.jar" ENV APP_HOME=/home/gradle/src VOLUME $APP_HOME/logs WORKDIR $APP_HOME ARG CERT="ApplicationNameSelfSigned.cer" #copy and import self signed vm certificate COPY --from=TEMP_BUILD_IMAGE /home/gradle/src/src/main/resources/ssl/$CERT $APP_HOME RUN keytool -importcert -file $CERT -alias $CERT -cacerts -storepass changeit -noprompt #copy app jar COPY --from=TEMP_BUILD_IMAGE /home/gradle/src/build/libs/$ARTIFACT_NAME . ENTRYPOINT ["java","-jar","application-name-0.0.1-SNAPSHOT.jar"]
Angular NPM前端Dockerfile
#stage 1 FROM node:18-alpine3.16 as node WORKDIR /app COPY . . RUN npm install RUN npm run build --prod #stage 2 dev FROM nginx:1.23.2-alpine as dev COPY --from=node /app/dist/application-name /usr/share/nginx/html COPY /nginx_azure_dev.conf /etc/nginx/conf.d/default.conf COPY /ssl/. /etc/nginx/ssl/live/application-url.com/ EXPOSE 80 443
已尝试docker system prune -a、停止并移除所有Docker相关内容,但磁盘空间仍未释放,当前使用overlay2存储驱动。
问题分析与解决方案
架构设置中的问题
- 构建缓存未有效利用:多阶段构建虽已使用,但前端
COPY . .后直接执行npm install,只要代码有变动就会重新安装依赖,生成新的node_modules镜像层;后端Gradle构建同理,每次构建都会重新生成构建缓存层,导致大量冗余层积累。 - 中间镜像未自动清理:构建过程中生成的临时阶段镜像(如
TEMP_BUILD_IMAGE、node阶段镜像),若未主动清理,会长期占用磁盘空间。 - overlay2的diff层特性:overlay2的diff目录存储镜像层与父层的差异文件,频繁构建生成的大量镜像层,即使后续被替换,旧的diff文件仍会留存,直到被彻底回收。
是否为预期行为?
这不是正常预期行为。多阶段构建的核心目标就是丢弃构建阶段的冗余文件,仅保留运行时必要内容。出现此问题是因为构建过程中生成的中间镜像、未被清理的旧镜像层未被正确回收。
解决办法
强制彻底清理Docker资源
- 停止所有容器:
docker stop $(docker ps -aq) - 删除所有容器:
docker rm $(docker ps -aq) - 删除所有镜像:
docker rmi $(docker images -aq) - 删除所有卷:
docker volume rm $(docker volume ls -q) - 执行深度清理:
docker system prune -a --volumes -f - 若仍有残留,需先停止Docker服务再手动清理overlay2目录:
sudo systemctl stop docker sudo rm -rf /var/lib/docker/overlay2/* sudo systemctl start docker
注意:手动清理前务必确认所有Docker资源已无保留必要,此操作会删除本地所有镜像、容器、卷等数据。
- 停止所有容器:
优化Dockerfile减少冗余层
- 前端Dockerfile优化:先复制
package.json和package-lock.json,利用构建缓存避免代码变动就重新安装依赖:#stage 1 FROM node:18-alpine3.16 as node WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build --prod #stage 2 dev FROM nginx:1.23.2-alpine as dev COPY --from=node /app/dist/application-name /usr/share/nginx/html COPY /nginx_azure_dev.conf /etc/nginx/conf.d/default.conf COPY /ssl/. /etc/nginx/ssl/live/application-url.com/ EXPOSE 80 443 - 后端Dockerfile优化:提前复制Gradle配置文件缓存依赖,构建后清理临时文件:
FROM gradle:7.3.1-jdk17 AS TEMP_BUILD_IMAGE COPY --chown=gradle:gradle build.gradle settings.gradle /home/gradle/src/ RUN gradle dependencies --no-daemon COPY --chown=gradle:gradle . /home/gradle/src WORKDIR /home/gradle/src RUN gradle bootJar --no-daemon FROM eclipse-temurin:17 ENV ARTIFACT_NAME="application-name-0.0.1-SNAPSHOT.jar" ENV APP_HOME=/app VOLUME $APP_HOME/logs WORKDIR $APP_HOME ARG CERT="ApplicationNameSelfSigned.cer" COPY --from=TEMP_BUILD_IMAGE /home/gradle/src/src/main/resources/ssl/$CERT $APP_HOME RUN keytool -importcert -file $CERT -alias $CERT -cacerts -storepass changeit -noprompt \ && rm -f $CERT # 清理临时证书文件 COPY --from=TEMP_BUILD_IMAGE /home/gradle/src/build/libs/$ARTIFACT_NAME . ENTRYPOINT ["java","-jar","application-name-0.0.1-SNAPSHOT.jar"]
- 前端Dockerfile优化:先复制
定期清理构建缓存
- 每次构建后执行
docker builder prune -f清理构建缓存,避免中间层积累。 - 可通过Azure控制台调整虚拟机磁盘大小,或使用Docker的
--storage-opt size参数限制镜像存储配额。
- 每次构建后执行
内容的提问来源于stack exchange,提问作者Jens
相关产品推荐
相关产品推荐

