背景
在长期运行的 Docker 服务器环境中,常见两类资产同时存在:
- 正在运行的服务栈(多个容器组成的应用)
- 暂时停用但未来仍会启用的服务(容器已删除,数据卷与镜像作为冷备保留)
如果仅依据“容器是否在运行”来判断镜像是否可删除,极易误删冷备镜像,给后续恢复带来额外成本。因此,有必要建立一套以服务栈(stack)为核心的镜像与容器管理方法。
本文记录一次完整的排查与整理过程,目标不是“尽可能删除”,而是确保不误删任何未来仍需使用的镜像。
一、基础原则
在该环境中采用如下原则:
- 容器运行状态不是删除依据
- stopped / exited 容器依然可能代表未来会恢复的服务
- 容器已删除 ≠ 服务已弃用
- 镜像分为三类资产
- 正在运行的服务镜像(Active)
- 冷备镜像(Cold Standby,未来会再用)
- 明确弃用镜像(Retired)
- 任何清理操作都必须由人工决策,而非自动推断
二、列出所有镜像(事实基线)
使用带 digest 的镜像列表作为“真实库存”:
docker images --digests
该输出用于确认:
- 系统中实际存在的镜像
- 是否存在多版本堆积
- 是否有本地构建镜像(digest 为
<none>)
三、列出所有容器(不区分运行/停止)
容器列表是“镜像引用关系”的唯一事实来源:
docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.CreatedAt}}'
在该环境中,当前不存在 exited 容器,所有服务均处于运行状态。但这并不改变后续判断逻辑。
四、用“栈(Compose Project)视角”理解容器结构
相比单个容器视角,“栈”更符合真实服务结构。通过 com.docker.compose.project 标签,可将容器按栈分组。
栈视图生成命令
docker ps --format '{{.Label "com.docker.compose.project"}}\t{{.Names}}\t{{.Image}}' \
| sort \
| awk -F'\t' '{
p=$1; if(p=="" ) p="(no-compose)";
if(p!=last){ if(NR>1) print ""; print "== " p " =="; last=p }
printf " - %-35s %s\n", $2, $3
}'
五、当前运行中的服务栈清单(严格脱敏)
为避免暴露具体应用指纹,本节仅以抽象栈类别记录容器结构与数量,不出现任何可被直接识别的服务名称、镜像名或项目名。
- Stack-A(单容器工具类):1 个容器
- Stack-B(实时通信类):4 个容器
- Stack-C(邮件系统类):18 个容器
- Stack-D(管理界面类):1 个容器
- Stack-E(即时通信类):2 个容器
- Stack-F(远程访问类):2 个容器
- Stack-G(本地构建类):1 个容器
- Stack-H(文档处理类):1 个容器
该视图仅用于说明“以栈为单位进行管理”的方法论,而非展示具体部署细节。