【问题标题】:How to Keep a Service Running in a Detached Container? [closed]如何让服务在分离的容器中运行? [关闭]
【发布时间】:2021-11-18 10:35:16
【问题描述】:

使用 docker 部署一个 uvicorn 服务器来服务一些 tensorflow 模型。 dockerfile 的结尾是这样的。

# Start ASGI server
CMD ['./runserver.sh']

runserver.sh 看起来像这样

#!/usr/bin/env bash
# encoding:utf-8
# This is a blocking call
uvicorn gateway:app --host=0.0.0.0 --workers 20 # Default port 8000

这是我用来启动容器的命令

docker run --detach --publish 8000:8000 tensor_image

我的期望和目标: 容器将保持活动状态,直到被 docker stop 命令杀死,并且客户端可以向 uvicorn 服务器发送请求。

发生了什么: docker run 命令只是在终端上回显容器的长 id,然后容器就死掉了。

如何保持运行?另外,如果我让 uvicorn 将其内容记录到容器内的本地文件中,如何查看服务器日志本身?

如果这很重要,请使用 Linux mint ulyana 作为我的操作系统。一些额外的澄清

【问题讨论】:

  • 您的 Dockerfile 不完整。请参阅minimal reproducible example
  • 如果您删除 --detach 选项,它会说明什么?如果您的 CMD 正是您所显示的,我怀疑事情出了问题,因为您没有正确的 JSON 数组语法;改成双引号CMD ["./runserver.sh"] 能解决吗?

标签: docker containers devops uvicorn


【解决方案1】:

您的问题与 docker 运行容器的方式有关。

您的容器将运行的主要进程取决于两个 Dockerfile 指令的组合,ENTRYPOINTCMD

简而言之 - 请考虑查看例如 this related SO question 以获得更深入的了解 - ENTRYPOINT 定义了将在您的容器启动时运行的命令。默认的ENTRYPOINT 命令是/bin/sh -c,它不能被docker 命令行覆盖。

另一方面,CMD 可以被视为补充参数,将附加到提供的ENTRYPOINT。如果您在运行容器时提供一些参数,它将被覆盖。

在此背景下,我认为您可以通过多种方式运行您的应用程序。

例如,通过使您的 Dockerfile ENTRYPOINT 成为您要运行的实际 shell 脚本:

ENTRYPOINT ["./runserver.sh"]

其他,通过使用CMD,但修改您的runserver.sh 脚本并使用exec 运行uvicorn

#!/usr/bin/env bash
# encoding:utf-8
# To run in production with multiple slaves
exec uvicorn gateway:app --host=0.0.0.0 --workers 20 # Default port 8000

exec 触发运行脚本的进程被给定的命令替换,而不是将其作为新进程启动,这是运行 shell 命令时的默认行为。

您可以使用CMD 并直接提供uvicorn 命令 - 它应该对您的PATH 变量可见:

CMD ["uvicorn", "gateway:app", "--host", "0.0.0.0", "--workers", "20"]

执行任何这些更改将确保容器不会提前终止。

【讨论】:

  • 感谢您的回答,我会试试这个。我承认我在容器生命周期方面的概念差距,特别是为什么当runserver.sh 是一个阻塞脚本时容器会停止(因为它的最后一个也是唯一的命令)。另外,容器的主进程是什么意思?是pid=0的进程,即systemd吗?
  • 抱歉@Della 回复晚了。不客气。你能尝试吗?不,请不要与 pids、systemd 等混淆。如果我没有很好地解释自己,我很抱歉。我更新了答案,试图解释我的意思并尝试提供另一种选择。拜托,你能回顾一下吗?我希望它有所帮助。
  • 谢谢。实际上,使它成为 exec 并没有帮助,问题是单引号作为对原始问题的另一条评论所说。在 python 中,我几乎没有注意到字符串文字是单引号还是双引号,所以我也将这个坏习惯带到了其他语言。一定要小心。
  • 非常感谢@Della 的反馈。我很高兴看到问题得到解决。抱歉,我看到了评论,但我认为这与您编写问题的方式有关,而不是实际代码。不管怎样,希望这个答案能给你一些关于docker使用的有用建议。
【解决方案2】:

为了分离容器,您必须在阻塞模式下运行 CMD 语句。

在你的情况下,我无法重现,你应该运行 uvicorn 不是作为一个守护进程,而是作为一个阻塞应用程序。

【讨论】:

  • Uvicorn 是一个阻塞应用程序,即当我使用我共享的命令从终端运行它时,它会启动工作人员,开始监听端口 8000 并阻塞终端等待请求。为什么它不会阻塞在容器内以保持容器存活?
猜你喜欢
  • 2013-04-21
  • 2014-03-03
  • 1970-01-01
  • 2019-10-03
  • 1970-01-01
  • 2015-07-13
  • 2013-07-29
  • 1970-01-01
  • 2017-07-24
相关资源
最近更新 更多