feat: add docker image cleanup script for benchmark images

This commit is contained in:
sora 2026-08-05 05:38:20 +00:00
parent ba2b5c1772
commit 0d7608c867

205
bash/cleanup_docker_images.sh Executable file
View File

@ -0,0 +1,205 @@
#!/bin/bash
# ============================================================
# 清理评测后遗留的 Docker 镜像
#
# 用途:
# SWE-bench、Terminal-Bench 等 benchmark 会拉取大量 Docker 镜像,
# 评测完后很占磁盘。本脚本按命名空间批量删除这些镜像。
#
# 用法:
# # 默认只预览,不会真的删除
# bash bash/cleanup_docker_images.sh --preset swe
#
# # 确认删除
# bash bash/cleanup_docker_images.sh --preset swe --yes
#
# # 删除 terminal-bench 镜像
# bash bash/cleanup_docker_images.sh --preset terminal --yes
#
# # 删除所有常见 benchmark 镜像
# bash bash/cleanup_docker_images.sh --preset all-bench --yes
#
# # 自定义匹配规则(支持多个,逗号分隔)
# bash bash/cleanup_docker_images.sh --pattern 'swebench/*,alexgshaw/*' --yes
#
# # 同时清理 dangling 镜像和未使用卷
# bash bash/cleanup_docker_images.sh --preset all-bench --yes --prune
# ============================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 预设的 benchmark 镜像命名空间
PRESET_SWE=('swebench/*')
PRESET_TERMINAL=('alexgshaw/*')
PRESET_ALL_BENCH=()
PRESET_ALL_BENCH+=("${PRESET_SWE[@]}")
PRESET_ALL_BENCH+=("${PRESET_TERMINAL[@]}")
DRY_RUN=1
PRESET=''
PATTERNS=''
PRUNE=0
usage() {
sed -n '7,34p' "$0"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--preset)
PRESET="${2:-}"
shift 2
;;
--pattern)
PATTERNS="${2:-}"
shift 2
;;
--yes)
DRY_RUN=0
shift
;;
--prune)
PRUNE=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
# 解析出要删除的 pattern 列表
PATTERN_LIST=()
if [[ -n "$PRESET" ]]; then
case "$PRESET" in
swe)
PATTERN_LIST+=("${PRESET_SWE[@]}")
;;
terminal)
PATTERN_LIST+=("${PRESET_TERMINAL[@]}")
;;
all-bench)
PATTERN_LIST+=("${PRESET_ALL_BENCH[@]}")
;;
*)
echo "ERROR: unknown preset '$PRESET'. Available: swe, terminal, all-bench"
exit 1
;;
esac
fi
if [[ -n "$PATTERNS" ]]; then
IFS=',' read -ra CUSTOM_PATTERNS <<< "$PATTERNS"
PATTERN_LIST+=("${CUSTOM_PATTERNS[@]}")
fi
if [[ ${#PATTERN_LIST[@]} -eq 0 ]]; then
echo "ERROR: 请指定 --preset 或 --pattern"
usage
exit 1
fi
echo "============================================================"
echo "清理目标 pattern:"
for p in "${PATTERN_LIST[@]}"; do
echo " - $p"
done
echo "============================================================"
# 收集所有匹配且没有被运行中容器使用的镜像 ID
MATCHED_IMAGES=()
RUNNING_IMAGES=$(docker ps --format '{{.Image}}' | sort -u)
for pattern in "${PATTERN_LIST[@]}"; do
while IFS= read -r img; do
[[ -z "$img" ]] && continue
repo="${img%:*}"
# 检查是否有运行中容器在使用该镜像
if echo "$RUNNING_IMAGES" | grep -qx "$img"; then
echo "SKIP (running container uses): $img"
continue
fi
# 避免重复
if [[ ! " ${MATCHED_IMAGES[*]} " =~ " ${img} " ]]; then
MATCHED_IMAGES+=("$img")
fi
done < <(docker images --format '{{.Repository}}:{{.Tag}}' --filter=reference="$pattern")
done
if [[ ${#MATCHED_IMAGES[@]} -eq 0 ]]; then
echo "没有匹配到可删除的镜像"
exit 0
fi
echo ""
echo "匹配到 ${#MATCHED_IMAGES[@]} 个镜像:"
for img in "${MATCHED_IMAGES[@]}"; do
size=$(docker images --format '{{.Size}}' "$img" | head -1)
echo " $img ($size)"
done
# 计算标记总大小(注意共享层会被多次计算,仅作参考)
TOTAL_SIZE_GB=$(docker images --format '{{.Size}} {{.Repository}}:{{.Tag}}' \
| awk -v img_list="${MATCHED_IMAGES[*]}" '
BEGIN {
n = split(img_list, imgs, " ");
for (i=1; i<=n; i++) target[imgs[i]] = 1;
}
{
size = $1;
img = $2;
if (!(img in target)) next;
unit = substr(size, length(size)-1);
val = substr(size, 1, length(size)-2);
if (unit == "GB") sum += val * 1024 * 1024 * 1024;
else if (unit == "MB") sum += val * 1024 * 1024;
else if (unit == "kB") sum += val * 1024;
}
END {
printf "%.2f", sum / 1024 / 1024 / 1024;
}')
echo ""
echo "标记总大小约: ${TOTAL_SIZE_GB} GB含共享层实际释放会小于该值"
if [[ "$DRY_RUN" -eq 1 ]]; then
echo ""
echo "当前是预览模式,不会删除。如需删除请加上 --yes"
exit 0
fi
echo ""
echo "开始删除..."
FAILED=0
for img in "${MATCHED_IMAGES[@]}"; do
if docker rmi -f "$img" >/dev/null 2>&1; then
echo " DELETED $img"
else
echo " FAILED $img"
FAILED=1
fi
done
if [[ "$PRUNE" -eq 1 ]]; then
echo ""
echo "清理 dangling 镜像和未使用卷..."
docker image prune -f
docker volume prune -f
fi
echo ""
echo "============================================================"
if [[ "$FAILED" -eq 0 ]]; then
echo "清理完成"
else
echo "部分镜像删除失败"
fi
echo "============================================================"