美文网首页
Docker初学者问题 - 如何让容器启动后不会自动停止

Docker初学者问题 - 如何让容器启动后不会自动停止

作者: 啤酒沫 | 来源:发表于2019-02-04 12:35 被阅读0次

通常使用docker run --name XX image:tag这样的命令来启动容器后,会遇到两种情况。

  1. 容器启动后再标准输出打印了一些信息,然后就停在那里了。如果我们使用ctrl-cctrl-d退出后容器就结束了。
  2. 容器启动后很快就自己结束了,然后就没有然后了。

这两种都不熟我们期望的结果。我们希望容器在启动后持续运行,等待我们的再次临幸。对于这个问题网上有很多文章介绍,但能够将清楚的很少。我这里整理了一下希望能够让读者清晰的理解这种现象的原因以及应对方法。

没有耐心读长文的同学可以直接看最后的总结

CMD执行命令的三种差别

Docker Image在制作时通过DockerfileCMD命令指定了容器启动后执行的程序。这个指定程序决定了容器是否结束和如何结束。

我们来看看三种不同的情况:

1. CMD指定了一个持续运行的程序.

持续运行就是说程序不会主动退出。我们拿postgres的举栗子。

# 先来看一看postgres的CMD程序是哪个
$ docker pull postgres:11-alpine
...
...

$ docker inspect postgres:11-alpine
...

"Cmd": [
    "postgres"
],

...

我们看到容器在启动后会指定postgres程序,这个程序会持续运行。我们运行起来看看。

$ docker run --name pp postgres:11-alpine
...[一堆输出信息]...
2019-02-03 13:46:46.117 UTC [1] LOG:  database system is ready to accept connections
[停在这里不动了]
[我们该怎么办?]

ctrl-c
[然后就没有然后了]

容器成功启动了postgres程序,一旦按下ctrl-c程序终止了,容器也就退出了。

解决办法

运行时添加-d参数

$ docker run --name pp -d postgres:11-alpine
1c1e99ac3fd3f18c6558bfc8b0fd08e4bf7aaad80535dd6ea709892f20f06f27

可以看到添加-d参数后docker run命令输出了容器的ID而不是像之前那样输出postgres程序执行的内容。

$ docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS               NAMES
1c1e99ac3fd3        postgres:11-alpine   "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        5432/tcp            pp

通过docker ps命令看到容器确实启动起来,并持续运行。完美。

我们看看-d参数的解释

$ docker run --help
...
-d, --detach   Run container in background and print container ID
...

这个参数的含义就是对容器说:"我知道你在努力做事,但我也很忙,你自己到旁边干活去吧,有事儿我再找你"

2. CMD指定了一个shell

这次我们用node举栗子

$ docker pull node:10-alpine

$ docker inspect node:10-alpine
...
"Cmd": [
    "node"
],
...

node程序与postgres程序不太一样。node并不是我们上面谈的"持续运行"的概念。
它作为一种shell程序自身并不知道要做什么,而是需要与操作者交流从而执行操作者交付的任务。
shell与操作者之间交流的方式是通过tty进行的。如果tty没有了那么shell发现没有人理它了,它就会在孤独和寂寞中睡觉去了。
而当容器启动的时候并不会给程序分配一个tty,所以这就是我们看到启动shell程序的容器自动退出的原因。

解决办法

运行时添加-t参数

$ docker run --name nn -t node:10-alpine
> [这是shell提示符]

我们来看看-t参数的解释

$ docker run --help
...
 -t, --tty    Allocate a pseudo-TTY
...

这个参数的含义是:"瞧这个泰迪熊多可爱,你去和它聊天吧"

现在我们看到了shell 提示符,现在的状态与第一种情况类似了,下面我们只需要再加入-d参数就完美了

$ docker run --name nn -dt node:10-alpine  
bfeead85bf01dd182e4c631ee9077afbb5c989e9c75abdd4776086dd223b9cdc

我们期待的容器ID由出现了,完美。

3. CMD指定了一个普通程序

这种镜像不好找,我们用参数模拟一下。在启动容器是通过命令行参数指定容器启动的程序,这将替换CMD指定的程序。

$ docker run --name nn -dt node:10-alpine pwd
412baf5fc0428567bcce3a2cb00fc41a696c10ecda0447d23a9291c2a2b52f20

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
412baf5fc042        node:10-alpine      "pwd"               2 minutes ago       Exited (0) 2 minutes ago                       nn

虽然容器启动时返回了容器ID,但当我们查看容器状态时它已经Exited
起始这种容器设计之初就不是让它持续运行的,它只是为了完成一项专门的动作,然后去睡觉。

那么对于这样的容器我们改怎么办呢?
♪ Let it go, ♪ let it go
♫ Can't hold it back anymore
♪ Let it go, ♪ let it go
♬ Turn my back and slam the door

### 总结
根据CMD指定的程序不同,有三种情况需要考虑

  1. 对于自身持续运行的程序,指定-d参数。它就可以自己到角落里画圈圈去了。
  2. 对于一个shell程序,指定-dt参数。给它一只泰迪熊,它就去角落和和泰迪熊聊天去了。
  3. 对于一个执行完就结束的程序。我们只能Let it go

相关文章

网友评论

      本文标题:Docker初学者问题 - 如何让容器启动后不会自动停止

      本文链接:https://www.haomeiwen.com/subject/ouypsqtx.html