从零到一的高效运维实战指南
目录导读
-
为什么需要批量管理容器?
当容器数量超过两位数时,手动启停已成灾难,本文揭晓如何用脚本彻底解放生产力。
-
核心思路解析
从容器状态识别、操作策略到脚本框架设计,建立全局认知。 -
基础脚本实例:批量停止/启动所有容器
包含docker ps -a与条件过滤的完整代码及运行截图(示意图)。 -
进阶场景:按名称、标签、状态精准过滤
利用docker inspect、jq解析元数据,实现精准控制。 -
安全防护:命令执行前二次确认机制
防止误操作导致生产环境瘫痪——read交互 + 模拟运行模式。 -
定时任务与异常处理
结合crontab实现夜间自动启停,并捕获失败日志。 -
容器编排与脚本的取舍
Docker Compose vs 原生脚本:何时选择脚本,何时需要编排工具。 -
常见问题(FAQ)
- Q:脚本执行到一半报错怎么办?
- Q:如何只重启状态异常的容器?
- Q:Windows环境下能否运行这些脚本?
为什么需要批量管理容器?
在微服务架构或CI/CD流水线中,一个项目可能同时运行20~50个容器,如果每个都要手动执行docker start或docker stop,不仅效率低下,而且极易遗漏或误操作。
- 夜间资源回收:开发环境在非工作时间关闭以节省服务器费用。
- 版本升级:需要同时重启所有关联容器以加载新配置。
- 故障快照:批量暂停所有容器后导出日志或镜像。
脚本化管理的三个优势:
- 可重复:同一脚本在任意环境执行相同逻辑。
- 可审计:输出日志记录每一步操作。
- 可扩展:轻松集成到监控或自动化平台。
核心思路解析
批量管理容器脚本的核心逻辑可归纳为三步:
获取容器列表 → 过滤目标容器 → 执行操作(start/stop/restart)
关键设计点:
- 状态识别:检查容器是
running、exited、paused等状态。 - 操作幂等性:对已停止的容器执行
stop不应报错,对已运行的容器执行start应跳过。 - 错误隔离:单个容器失败不影响其他容器操作。
常见的过滤条件包括:容器名称前缀、标签(如env=dev)、镜像名称、运行时长等。
基础脚本实例:批量停止/启动所有容器
1 批量停止所有运行中的容器
#!/bin/bash
# stop_all_containers.sh
echo ">> 正在获取所有运行中的容器..."
RUNNING_CONTAINERS=$(docker ps -q)
if [ -z "$RUNNING_CONTAINERS" ]; then
echo ">> 没有正在运行的容器。"
else
echo ">> 即将停止以下容器:"
docker ps --format "table {{.ID}}\t{{.Names}}" | tail -n +2
echo ">> 开始停止..."
docker stop $RUNNING_CONTAINERS
echo ">> 所有运行中的容器已停止。"
fi
2 批量启动所有已停止的容器
#!/bin/bash
# start_all_stopped.sh
echo ">> 正在获取所有已停止的容器..."
STOPPED_CONTAINERS=$(docker ps -a -f "status=exited" -q)
if [ -z "$STOPPED_CONTAINERS" ]; then
echo ">> 没有已停止的容器。"
else
echo ">> 即将启动以下容器:"
docker ps -a -f "status=exited" --format "table {{.ID}}\t{{.Names}}" | tail -n +2
echo ">> 开始启动..."
docker start $STOPPED_CONTAINERS
echo ">> 所有已停止的容器已启动。"
fi
执行效果:
stop_all_containers.sh先列出所有运行中的容器ID和名称,然后逐一停止。- 即使部分容器已停止,
docker stop也不会报错,实现幂等操作。
进阶场景:按名称、标签、状态精准过滤
当容器数量庞大(例如200+),且只有部分需要重启时,精准过滤至关重要。
1 按名称前缀重启
#!/bin/bash
# restart_by_prefix.sh
PREFIX="myapp-"
echo ">> 查找名称以 '$PREFIX' 开头的容器..."
CONTAINERS=$(docker ps -a --filter "name=^/${PREFIX}" -q)
if [ -z "$CONTAINERS" ]; then
echo ">> 未找到匹配容器。"
exit 0
fi
echo ">> 匹配到以下容器:"
docker ps -a --filter "name=^/${PREFIX}" --format "table {{.Names}}\t{{.Status}}"
echo ">> 重启中..."
docker restart $CONTAINERS
echo ">> 完成。"
2 按标签(Label)过滤后批量管理
#!/bin/bash
# manage_by_label.sh
LABEL="env=staging"
ACTION=${1:-stop} # 默认操作为stop,可传参 start/stop/restart
echo ">> 查找标签为 '$LABEL' 的容器..."
CONTAINERS=$(docker ps -a --filter "label=$LABEL" -q)
if [ -z "$CONTAINERS" ]; then
echo ">> 未找到匹配容器。"
exit 0
fi
echo ">> 执行操作: $ACTION"
for CID in $CONTAINERS; do
docker $ACTION $CID
done
使用方式:
./manage_by_label.sh start 或 ./manage_by_label.sh stop
3 按状态过滤:只重启异常容器
#!/bin/bash
# restart_restarting.sh
echo ">> 查找状态为 restarting 的容器..."
RESTARTING=$(docker ps --filter "status=restarting" -q)
if [ -n "$RESTARTING" ]; then
echo ">> 发现以下容器处于重启循环中:"
docker ps --filter "status=restarting" --format "table {{.ID}}\t{{.Names}}"
echo ">> 执行重启..."
docker restart $RESTARTING
else
echo ">> 无异常容器。"
fi
安全防护:命令执行前二次确认机制
误操作是运维大忌,以下脚本在执行前打印即将操作的容器列表,并要求用户输入yes确认。
#!/bin/bash
# batch_stop_with_confirm.sh
echo ">> 以下容器将被停止:"
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}" | tail -n +2
read -p ">> 确认停止以上所有容器?(输入yes确认): " CONFIRM
if [ "$CONFIRM" != "yes" ]; then
echo ">> 已取消操作。"
exit 0
fi
echo ">> 停止中..."
docker stop $(docker ps -q)
echo ">> 操作完成。"
增强安全措施:
- 模拟运行模式:加入
--dry-run参数,只打印命令而不实际执行。 - 日志备份:操作前将容器状态导出到文件。
if [ "$1" == "--dry-run" ]; then
echo ">> 模拟运行模式:"
echo " docker stop $(docker ps -q)"
exit 0
fi
定时任务与异常处理
1 结合crontab实现夜间自动回收
假设你希望每天晚上23:00停止所有开发环境的容器,白天8:00启动:
# 编辑crontab:crontab -e 0 23 * * * /home/ops/stop_dev_env.sh >> /var/log/container_stop.log 2>&1 0 8 * * * /home/ops/start_dev_env.sh >> /var/log/container_start.log 2>&1
2 异常处理:捕获失败并发送告警
#!/bin/bash
# batch_stop_with_trap.sh
FAILED_CONTAINERS=()
STOP_LIST=$(docker ps -q)
for CID in $STOP_LIST; do
docker stop $CID || FAILED_CONTAINERS+=("$CID")
done
if [ ${#FAILED_CONTAINERS[@]} -gt 0 ]; then
echo ">> 以下容器停止失败:" >&2
for CID in "${FAILED_CONTAINERS[@]}"; do
docker ps -a --filter "id=$CID" --format "table {{.Names}}" | tail -n +2
done
# 可在此调用邮件或Slack接口告警
exit 1
else
echo ">> 所有容器停止成功。"
fi
容器编排与脚本的取舍
何时使用脚本?
- 临时管理:一次性操作或不定期维护。
- 非标准场景:如需要基于容器状态动态决策(例如先停止依赖链下游的容器)。
- 环境兼容:裸机或混合环境,未使用编排工具。
何时使用Docker Compose或Kubernetes?
- 长期运行的多服务应用:Compose的
up/down天然支持批量启停。 - 需要滚动更新、健康检查:Kubernetes的Deployment更可靠。
- 声明式管理:配置即代码,避免脚本逻辑分散。
最佳实践:
脚本适合作为“胶水代码”连接现有工具,
- 在CI/CD流程中调用脚本更新特定标签的容器。
- 在监控报警触发时自动重启异常容器。
常见问题(FAQ)
Q1:脚本执行到一半报错,部分容器已操作成功,如何回滚?
A:建议在操作前先保存当前容器状态快照:
docker ps --format "{{.ID}}:{{.Names}}" > /tmp/container_snapshot_$(date +%Y%m%d%H%M).txt
若出错,可手动恢复:对已停止的容器执行start,对已启动的容器执行stop,更稳健的方案是在脚本内添加“操作记录表”,每成功操作一个容器就记录,失败时反向恢复已操作部分。
Q2:如何只重启状态异常的容器(如不停重启的容器)?
A:使用过滤条件 --filter "status=restarting" 或 --filter "status=exited",然后执行docker restart,示例参见4.3节。
Q3:Windows环境下(如Docker Desktop on Windows)能否运行这些脚本?
A:可以,Windows支持WSL2(Windows Subsystem for Linux),可在WSL2中直接运行bash脚本,或者使用PowerShell版本:
# Windows PowerShell 示例
$containers = docker ps -q
if ($containers) {
docker stop $containers
}
推荐使用WSL2,因其与Linux环境完全兼容。
Q4:脚本如何避免操作到生产环境容器?
A:
- 环境变量隔离:在脚本中检查环境变量
ENV,只有dev或staging时才允许执行。 - 标签硬限制:仅操作包含特定标签(如
env=experimental)的容器。 - 白名单机制:脚本内定义允许操作的容器名称列表。
示例:
ALLOWED_PREFIX="dev-"
CONTAINERS=$(docker ps -a --filter "name=^/${ALLOWED_PREFIX}" -q)
if [ -z "$CONTAINERS" ]; then echo "无匹配容器,退出。"; exit 0; fi
通过本文,你已掌握从基础到进阶的容器批量管理脚本编写方法,关键点在于:清晰过滤、幂等操作、安全确认、日志记录,无论你管理的是10个还是1000个容器,合理的脚本都能让启停操作变得可靠且可控。
本文所有示例脚本均经过基础测试,建议在生产环境部署前在测试环境验证。