上篇博客中主要介绍了容器如何优雅的关闭, 这篇文章将会介绍某些容器非正常关闭, 但是无法重启时的一些问题, 可以一种比较巧妙的方式对其进行调试.

问题产生

不知道大家有没有遇到这样一种问题, 本来正常运行的容器由于某些原因退出了, 再次start却无法启动. 由于docker exec只能进入正在运行的容器, 已经退出的容器就无法调试了.

以下面的现象为例

1
2
3
4
5
6
7
'use strict';
var http = require('http');
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(3000, '0.0.0.0');
console.log('server started');
1
2
3
FROM node:10.17.0-alpine
COPY main.js main.js
ENTRYPOINT ["node", "main.js"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
docker build -t test .
docker run --name force-exec -ti -d test
docker exec -ti force-exec /bin/sh

/ $ vi main.js
/ $ cat main.js
# 我将`var http = require('http');`删掉了
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(3000, '0.0.0.0');

# 强制stop操作
docker stop force-exec

# 重新start, 发现容器根本不会启动
docker start force-exec

解决方案

这里我提供一种解决思路, 是将已经停掉的容器进行转存, 将其制作为镜像. 这样, 我们可以重新启动一个镜像, 并将CMD命令替换为/bin/bash来获得一个新的容器.

容器转存

1
2
3
4
5
6
7
8
9
10
# 查看这个无法启动的容器
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64a9b5143f77 test "node main.js" 6 minutes ago Exited (1) 3 minutes ago force-exec

# 使用 commit命令, 将该容器转存为镜像
$ docker commit force-exec force-exec:debug

# 再次启动容器, 将entrypoint改掉即可进去调试
$ docker run -ti --entrypoint=/bin/sh force-exec:debug

具体请查看docker官方文档中的commit命令使用.

总结

通过这篇博客, 希望大家能够了解到一个无法启动的镜像, 我们仍然有办法对其进行调试, Docker本身在容器的运行以及调试方面, 已经提供了强大的功能, 希望大家能够认真的阅读相关文档, 找到合适的命令.