在 Docker 使用中,如何有效停止容器是运维的重要环节。今天聚焦 docker stop 命令。它融合了'先礼后兵'的完整机制。
一、为什么不是所有的'停止'都叫 Stop?
很多新手会混淆 docker stop 和 docker kill,甚至觉得它们没什么区别,不都是让容器停止运行吗?如果你也这么想,那就大错特错了。它们的区别,就像是'礼貌地请客人离开'和'直接把客人轰出门外'的本质区别。
docker stop:优雅的绅士 它的工作流程是'先礼后兵'。当你执行docker stop时,Docker daemon 会先向容器内的主进程(PID 1)发送一个 SIGTERM 信号。这个信号的意思是:'您好,麻烦您处理一下手头的工作,我们准备要关闭了。'进程收到这个信号后,可以执行一些预定义的清理操作,比如关闭数据库连接、将内存数据持久化到磁盘、完成正在处理的网络请求等。这给了容器一个'体面退出'的机会。
只有在等待一段时间(默认 10 秒)后,如果容器依然没有自行停止,Docker 才会失去耐心,发出终极杀手锏——SIGKILL 信号。这个信号是强制性的,操作系统会立即终止该进程,并且进程无法捕获或忽略它。这是一种强制手段。
docker kill:粗暴的霸王 相比之下,docker kill就直接多了。它默认发送的就是 SIGKILL 信号(也可通过-s参数指定其他信号),相当于不由分说,直接拔电源。容器进程没有机会做任何清理工作,可能会导致数据丢失或状态不一致。
所以,首选永远是 docker stop!除非容器已经完全无响应,你确认它无法处理 SIGTERM 信号,这时才考虑使用 docker kill 作为最后的补救措施。
二、实战示例:从入门到精通
光说不练假把式,下面我们通过一系列示例来真切感受 docker stop 的魅力。
示例 1:基础操作——停止一个容器
启动一个测试容器:我们用一个最简单的 Nginx 容器来演示。它会以后台模式运行。
docker run -d --name my-nginx nginx:alpine
使用 docker ps 查看,确认容器正在运行(STATUS 为 Up)。
优雅地停止它:
docker stop my-nginx
再次运行 docker ps,你会发现容器不见了。运行 docker ps -a 可以看到容器状态变为 Exited (0),其中的 0 表示正常退出码。
示例 2:处理'顽固'容器——修改超时时间
假设我们有一个自定义的容器,它收到 SIGTERM 后需要花费 25 秒进行复杂的数据清理工作。默认的 10 秒显然不够。
启动一个模拟'慢'容器:我们可以写一个简单的脚本模拟此行为。
# 创建一个名为 slow-stop.sh 的脚本
cat > slow-stop.sh << 'EOF'
#!/bin/sh
# 模拟收到 SIGTERM 后的清理工作
trap "echo 'Received SIGTERM, cleaning up...'; sleep 25; echo 'Cleanup done!'; exit 0" SIGTERM
echo "Container is running..."
# 保持脚本运行
;
1
EOF
> Dockerfile <<
FROM alpine:latest
COPY slow-stop.sh /
RUN +x /slow-stop.sh
CMD []
EOF
docker build -t my-slow-app .
docker run -d --name slow-container my-slow-app


