当前位置:嗨网首页>书籍在线阅读

05-技巧2 以守护进程方式运行容器

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

技巧2 以守护进程方式运行容器

在熟悉了Docker之后,(与我们一样)读者会开始思考Docker的其他使用场景,首先想到的使用场景之一是以后台服务的方式来运行Docker容器。

以服务方式运行Docker容器,通过软件隔离实现可预测行为,是Docker的主要使用场景之一。本技巧将让开发人员可以使用适合自己的操作的方式来管理服务。

问题

想要以服务方式在后台运行一个Docker容器。

解决方案

docker run 命令中使用 -d 标志,并使用相关的容器管理标志定义此服务特性。

Docker容器与多数进程一样,默认在前台运行。在后台运行Docker容器最常见的方式是使用标准的 & 控制操作。虽然这行得通,但如果用户注销终端会话就可能出现问题,用户被迫使用 nohup 标志,而这将在本地目录中创建一个不得不管理的输出文件……是的,使用Docker守护进程的功能完成这一点将简洁得多。

要做到这一点,可使用 -d 标志:

$ docker run -d -i -p 1234:1234 --name daemon ubuntu:14.04 nc -l 1234

docker run 一起使用的 -d 标志将以守护进程方式运行容器。 -i 标志则赋予容器与Telnet会话交互的能力。使用 -p 将容器的1234端口公布到宿主机上。通过 --name 标志赋予容器一个名称,以便后期用来对它进行引用。最后,使用netcat( nc )在1234端口上运行一个简单的监听应答(echo)服务器。

现在可以使用Telnet连接它并发送消息。使用 docker logs 命令可以看到容器已经接收该消息,如代码清单2-1所示。

代码清单2-1 使用Telnet连接容器netcat服务器

$ telnet localhost 1234  ⇽--- 使用telnet命令连接到容器的netcat服务器
 Trying ::1...
Connected to localhost.
Escape character is '^]'.
hello daemon  ⇽--- 输入发送给netcat服务器的一行文本
 ^]  ⇽--- 按组合键Ctrl+]然后按回车键退出Telnet会话
telnet> q  ⇽--- 输入q然后按回车键退出Telnet程序
 Connection closed.
$ docker logs daemon  ⇽--- 执行docker logs命令查看容器的输出
 hello daemon
$ docker rm daemon  ⇽--- 使用rm命令清除容器
 daemon
$

由此可见,以守护进程方式运行一个容器是相当简单的,但在实际操作中,还有一些问题有待解答。

  • 如果服务失败了会发生什么?
  • 在服务结束时会发生什么?
  • 如果服务不断失败会发生什么?

幸运的是,Docker为每个问题都提供了相应标志!

注意

尽管重启标志经常会与守护进程标志( -d )一起使用,但与 -d 一起运行这些标志并不是必需的。

docker run --restart 标志允许用户应用一组容器终止时需要遵循的规则(就是所谓的“重启策略”,见表2-1)。

表2-1 Docker重启标志选项

| 策  略 | 描  述 | | :----- | :----- | :----- | :----- | | no | 容器退出时不重启 | | always | 容器退出时总是自动重启 | | unless-stopped | 总是重启,不过显式停止除外 | | on-failure[:max-retry] | 只在失败时重启 |

no 策略很简单:当容器退出时,它不会被重启。这是默认值。

always 策略也很简单,不过还是值得简要讨论一下:

$ docker run -d --restart=always ubuntu echo done

这个命令以守护进程方式( -d )运行容器,并总是在容器终止时自动重启( --restart=always )。它发送了一个简单的快速完成的 echo 命令,然后退出容器。

如果执行了上述命令,然后执行 docker ps 命令,就会看到类似下面这样的输出:

$ docker ps
CONTAINER ID    IMAGE        COMMAND       CREATED
➥   STATUS             PORTS        NAMES
69828b118ec3    ubuntu:14.04    "echo done"     4 seconds ago
➥   Restarting (0) Less than a second ago       sick_brattain

dockerps 命令列出了所有运行中的容器及其信息,包括以下内容。

  • 容器什么时候被创建的( CREATED )。
  • 容器的当前状态——通常将是 Restarting ,因为它只运行了很短的时间( STATUS )。
  • 容器上一次运行的退出码(也在 STATUS 下面)。 0 代表运行成功。
  • 容器名称。默认情况下,Docker会通过连接两个随机单词为容器命名。有时这会造成一些奇怪的结果(这也是我们通常建议给容器起一个有意义的名称的原因)。

注意, STATUS 一栏还告诉我们,容器在不到一秒前退出并正在重启。这是因为 echo done 命令会立即退出,而Docker必须不断地重启这个容器。

需要特别说明的是,Docker复用了容器ID。这个ID在重启时不会改变,并且对于这个Docker调用来说, ps 表里永远只会有一条。

指定 unless-stoppedalways 几乎是一样的——二者都将在你执行 docker stop 时停止容器重启,不过 unless-stopped 将确保在守护进程重启时记住其停止状态(可能是你重启了计算机),而 always 则会再次启动容器。

最后, on-failure 策略只在容器从它的主进程返回一个非0退出码(一般表示失败)时重启:

$ docker run -d --restart=on-failure:10 ubuntu /bin/false

这条命令以守护进程( -d )形式运行容器,并设置了重启的尝试次数限制( --restart= on-failure:10 ),如果超出限制则退出。它执行了一个快速完成并肯定失败的简单的命令( /bin/false )。

如果执行上述命令并等待1分钟,然后执行 docker ps -a ,就会看到类似下面这样的输出:

$ docker ps -a
CONTAINER ID   IMAGE        COMMAND     CREATED
➥   STATUS            PORTS       NAMES
b0f40c410fe3   ubuntu:14.04     "/bin/false"   2 minutes ago
➥   Exited (1) 25 seconds ago            loving_rosalind

讨论

创建后台运行的服务经常碰到的困难在于确保后台服务在非常规环境中不会崩溃。因为这不是立马可见的,用户可能不会意识到有东西无法正常工作了。

本技巧让你无须再考虑由环境和处理重启引起的服务的偶然复杂度。你可以将思想集中在核心功能上。

举个具体的例子,你和团队可能会使用这个技巧在同一台机器上运行多个数据库而无须编写设置这些数据库的说明,也不用打开终端以保持其运行。