Docker镜像与容器清理脚本
安全清理Docker无用资源,包括停止的容器、悬空镜像、未使用的镜像、构建缓存和未使用的卷,释放磁盘空间,支持预览模式
详细内容
#!/bin/bash
# ==========================================
# Docker镜像与容器清理脚本
# 用途:安全清理Docker无用资源,释放磁盘空间
# 使用方法:
# bash docker_cleanup.sh # 预览模式(只显示不删除)
# bash docker_cleanup.sh --yes # 确认执行清理
# ==========================================
# ========== 配置 ==========
DRY_RUN=true # 默认预览模式
KEEP_IMAGES_DAYS=7 # 保留最近N天内使用过的镜像
KEEP_CONTAINERS_HOURS=24 # 保留最近N小时内停止的容器
LOG_FILE="/var/log/docker_cleanup.log"
# ==========================
mkdir -p "$(dirname "$LOG_FILE")"
log_msg() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
if [ "$1" = "--yes" ] || [ "$1" = "-y" ]; then
DRY_RUN=false
fi
check_docker() {
if ! command -v docker >/dev/null 2>&1; then
echo "❌ Docker未安装"
exit 1
fi
if ! docker info >/dev/null 2>&1; then
echo "❌ Docker服务未运行"
exit 1
fi
}
human_size() {
local bytes=$1
if [ "$bytes" -lt 1024 ]; then
echo "${bytes}B"
elif [ "$bytes" -lt 1048576 ]; then
echo "$((bytes / 1024))KB"
elif [ "$bytes" -lt 1073741824 ]; then
echo "$((bytes / 1048576))MB"
else
echo "$((bytes / 1073741824))GB"
fi
}
check_docker
echo "=========================================="
echo " Docker资源清理工具"
echo " 模式: $([ "$DRY_RUN" = true ] && echo '预览模式(不删除)' || echo '执行模式(将删除)')"
echo " 时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "=========================================="
# 清理前磁盘使用
BEFORE=$(docker system df 2>/dev/null)
echo ""
echo "【清理前 Docker 磁盘使用】"
echo "$BEFORE"
TOTAL_FREED=0
# 1. 清理停止的容器
echo ""
echo "【1/5】清理停止的容器..."
STOPPED_CONTAINERS=$(docker ps -a -q --filter "status=exited" --filter "status=created" 2>/dev/null)
if [ -z "$STOPPED_CONTAINERS" ]; then
echo " ✅ 没有停止的容器"
else
COUNT=$(echo "$STOPPED_CONTAINERS" | wc -l)
echo " 发现 $COUNT 个停止的容器:"
docker ps -a --filter "status=exited" --filter "status=created" --format " {{.Names}} ({{.Image}}) - {{.Status}}" 2>/dev/null
if [ "$DRY_RUN" = false ]; then
FREED=$(docker rm $STOPPED_CONTAINERS 2>/dev/null | wc -l)
echo " ✓ 已删除 $FREED 个容器"
else
echo " [预览] 将删除 $COUNT 个容器"
fi
fi
# 2. 清理悬空镜像(dangling images)
echo ""
echo "【2/5】清理悬空镜像..."
DANGLING_IMAGES=$(docker images -q -f "dangling=true" 2>/dev/null)
if [ -z "$DANGLING_IMAGES" ]; then
echo " ✅ 没有悬空镜像"
else
COUNT=$(echo "$DANGLING_IMAGES" | wc -l)
echo " 发现 $COUNT 个悬空镜像"
if [ "$DRY_RUN" = false ]; then
docker rmi $DANGLING_IMAGES 2>/dev/null
echo " ✓ 已删除悬空镜像"
else
echo " [预览] 将删除 $COUNT 个悬空镜像"
fi
fi
# 3. 清理未使用的镜像
echo ""
echo "【3/5】清理未使用的镜像(保留${KEEP_IMAGES_DAYS}天内使用过的)..."
UNUSED_IMAGES=$(docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" 2>/dev/null | while read repo id; do
# 检查是否有容器在使用
if ! docker ps -a --filter "ancestor=$id" --format "{{.ID}}" 2>/dev/null | grep -q .; then
echo "$id"
fi
done | sort -u)
if [ -z "$UNUSED_IMAGES" ]; then
echo " ✅ 所有镜像都在使用中"
else
COUNT=$(echo "$UNUSED_IMAGES" | wc -l)
echo " 发现 $COUNT 个未使用的镜像:"
docker images --format " {{.Repository}}:{{.Tag}} ({{.Size}})" 2>/dev/null | while read line; do
id=$(echo "$line" | awk '{print $1}')
if echo "$UNUSED_IMAGES" | grep -q "$id"; then
echo "$line"
fi
done
if [ "$DRY_RUN" = false ]; then
echo "$UNUSED_IMAGES" | xargs docker rmi 2>/dev/null
echo " ✓ 已删除未使用的镜像"
else
echo " [预览] 将删除 $COUNT 个未使用的镜像"
fi
fi
# 4. 清理构建缓存
echo ""
echo "【4/5】清理构建缓存..."
BUILD_CACHE_SIZE=$(docker builder du 2>/dev/null | tail -1 | awk '{print $1}')
if [ -z "$BUILD_CACHE_SIZE" ] || [ "$BUILD_CACHE_SIZE" = "0B" ]; then
echo " ✅ 没有构建缓存"
else
echo " 构建缓存大小: $BUILD_CACHE_SIZE"
if [ "$DRY_RUN" = false ]; then
docker builder prune -f 2>/dev/null
echo " ✓ 已清理构建缓存"
else
echo " [预览] 将清理构建缓存"
fi
fi
# 5. 清理未使用的网络
echo ""
echo "【5/5】清理未使用的网络..."
UNUSED_NETS=$(docker network ls --filter "type=custom" -q 2>/dev/null | while read net; do
if ! docker network inspect "$net" --format '{{range .Containers}}{{.Name}}{{end}}' 2>/dev/null | grep -q .; then
echo "$net"
fi
done)
if [ -z "$UNUSED_NETS" ]; then
echo " ✅ 没有未使用的网络"
else
COUNT=$(echo "$UNUSED_NETS" | wc -l)
echo " 发现 $COUNT 个未使用的网络"
if [ "$DRY_RUN" = false ]; then
echo "$UNUSED_NETS" | xargs docker network rm 2>/dev/null
echo " ✓ 已删除未使用的网络"
else
echo " [预览] 将删除 $COUNT 个网络"
fi
fi
# 清理后磁盘使用
echo ""
echo "【清理后 Docker 磁盘使用】"
docker system df 2>/dev/null
echo ""
echo "=========================================="
if [ "$DRY_RUN" = true ]; then
echo " 预览完成,未删除任何资源"
echo " 确认清理请执行: bash $0 --yes"
else
echo " 清理完成!"
fi
echo "=========================================="
适配环境
适配系统:CentOS 7+,Ubuntu 18.04+,Debian 10+
依赖环境:bash 4.0+
参数说明
[{"name": "KEEP_IMAGES_DAYS", "label": "\u4fdd\u7559\u6700\u8fd1N\u5929\u4f7f\u7528\u8fc7\u7684\u955c\u50cf", "default": "7"}, {"name": "DRY_RUN", "label": "\u9884\u89c8\u6a21\u5f0f(true=\u53ea\u663e\u793a\u4e0d\u5220\u9664)", "default": "true"}]