Docker buildx在AWS/EKS环境耗尽临时存储的问题求助
在AWS EKS环境中构建约5GB的Docker镜像时失败,Pod因临时存储耗尽被驱逐,错误日志如下:
14:42:59 unable to retrieve container logs for containerd://51da8f0270e5ed3529ec0ef5cf9e60cafc109ddb4e2baf334185efaf3494491d 14:42:59 jenkins-xxxxxxxxxxx Pod just failed (Reason: Evicted, Message: The node was low on resource: ephemeral-storage. Container builder was using 126387512Ki, which exceeds its request of 0. Container jnlp was using 40Ki, which exceeds its request of 0. )
该构建任务迁移到EKS已近一年,此前无异常。本地构建时仅占用/var/lib/docker下10GB空间,但EKS中构建5GB镜像却占用150GB存储仍未完成。
1. Dockerfile多阶段构建的中间层残留
当前Dockerfile包含多个构建阶段(ngcos-ubuntu、ngcos-python、ngcos-release-notes、ngcos-base等),多阶段构建最终仅保留目标镜像,但构建过程中所有中间阶段的镜像都会临时存储在节点上。尤其是ngcos-base阶段下载了两个Android NDK包(r21和r23c),每个NDK解压后大小约几十GB,叠加多个阶段的临时文件会导致存储占用急剧上升。
2. 构建缓存未及时清理
EKS中的Jenkins构建Pod未配置缓存清理策略,每次构建后残留的旧中间镜像、未使用的镜像层会持续占用临时存储,多次构建后逐步耗尽节点空间。
3. Docker-in-Docker(DinD)的存储放大效应
若构建使用DinD模式,Docker守护进程的存储目录(默认/var/lib/docker)会占用Pod临时存储。DinD不仅要存储镜像层,还要保存容器运行时的临时文件,加上镜像构建时的解压、编译等操作,会导致存储占用远大于最终镜像大小。而本地构建使用主机Docker守护进程,缓存和临时文件管理更高效。
4. Pod临时存储请求/限制缺失
错误日志显示容器的临时存储请求为0,EKS节点无法根据存储需求调度合适节点,也无法在存储不足时提前预警,最终导致Pod直接被驱逐。
1. 优化Dockerfile减少中间存储占用
- 合并RUN指令并清理临时文件:将独立的
RUN命令合并,同时在每个指令末尾清理下载的压缩包、apt缓存等临时文件。例如ngcos-base中NDK下载步骤可优化为:RUN wget -nv -nc "https://dl.google.com/android/repository/${ANDROID_R_NDK_VERSION}-${ANDROID_NDK_ARCH}.zip" && \ echo "${ANDROID_R_NDK_SHA256} ${ANDROID_R_NDK_VERSION}-${ANDROID_NDK_ARCH}.zip" | sha256sum --check --strict - && \ unzip -q -n "${ANDROID_R_NDK_VERSION}-${ANDROID_NDK_ARCH}.zip" && \ echo "" > $ANDROID_NDK_HOME/${ANDROID_R_NDK_VERSION}/Android.mk && \ rm -f "${ANDROID_R_NDK_VERSION}-${ANDROID_NDK_ARCH}.zip" RUN wget -nv -nc "https://dl.google.com/android/repository/${ANDROID_S_NDK_VERSION}-linux.zip" && \ echo "${ANDROID_S_NDK_SHA256} ${ANDROID_S_NDK_VERSION}-linux.zip" | sha256sum --check --strict - && \ unzip -q -n "${ANDROID_S_NDK_VERSION}-linux.zip" && \ echo "" > $ANDROID_NDK_HOME/${ANDROID_S_NDK_VERSION}/Android.mk && \ rm -f "${ANDROID_S_NDK_VERSION}-linux.zip" - 指定构建目标:使用
docker build --target仅构建所需的目标阶段,避免无用阶段占用存储。
2. 配置构建缓存清理策略
- 构建前清理本地缓存:在Jenkins构建脚本中添加
docker system prune -af命令,每次构建前清理无用镜像、容器和缓存层。 - 使用远程缓存:将Docker构建缓存存储到S3等远程存储,减少节点本地缓存占用。例如使用
buildx配合远程缓存:docker buildx create --use --name mybuilder docker buildx build --cache-to type=s3,region=us-east-1,bucket=my-cache-bucket --cache-from type=s3,region=us-east-1,bucket=my-cache-bucket -t my-image .
3. 优化DinD存储配置
- 挂载独立临时存储卷:为DinD容器挂载
emptyDir或EFS卷,避免占用节点根目录存储。在Jenkins Pod模板中配置:volumes: - name: docker-storage emptyDir: sizeLimit: 200Gi containers: - name: docker image: docker:dind volumeMounts: - name: docker-storage mountPath: /var/lib/docker - 替换为无守护进程构建工具:使用
kaniko替代DinD,直接在容器中构建镜像,无需启动Docker守护进程,降低存储和资源消耗。
4. 配置Pod临时存储请求与限制
在Jenkins构建Pod配置中添加临时存储的请求和限制,让EKS调度到有足够存储的节点:
resources: requests: ephemeral-storage: 100Gi limits: ephemeral-storage: 200Gi
5. 定期清理节点临时存储
配置EKS节点的定时CronJob,定期清理/var/lib/containerd或/var/lib/docker目录下的无用文件,避免节点存储长期占用。
内容的提问来源于stack exchange,提问作者Hank Ratzesberger

