【问题标题】:Python inside docker container, gracefully stopdocker容器内的Python,优雅地停止
【发布时间】:2018-12-19 13:51:34
【问题描述】:

我正在 Windows docker 容器 中运行一个非常基本的 Python 循环示例,我想优雅地停止

脚本在我的 dockerfile 中以这种方式启动:

CMD [ "python.exe" , "./test.py"]

在 docker 文档中,据说 SIGTERM 信号已发送到主命令,所以我试图以这种方式捕捉它:

import signal
import time
import logging, sys

class GracefulKiller:
  kill_now = False
  def __init__(self):
    signal.signal(signal.SIGINT, self.exit_gracefully)
    signal.signal(signal.SIGTERM, self.exit_gracefully)

  def exit_gracefully(self,signum, frame):
    self.kill_now = True

if __name__ == '__main__':
  logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
  killer = GracefulKiller()
  while True:
    time.sleep(1)
    logging.info("doing something in a loop ...")
    if killer.kill_now:
      break

  logging.info("End of the program. I was killed gracefully :)")

理论上,信号应该被处理程序捕获,布尔值应该切换,循环应该退出并显示我最后的日志行。它没有,它只是在信号发出的那一刻停止整个事情(或者更确切地说是 2-3 秒后)

C:\Users\Administrator\Documents\Projects\test>docker-compose up
Recreating test_1 ... done
Attaching to test_1
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
test_1  | INFO:root:doing something in a loop ...
Gracefully stopping... (press Ctrl+C again to force)
Stopping test_1   ... done

我的最后一行日志从未到达。 有谁知道发生了什么?它是特定于 python 的问题,特定于 docker 还是特定于 Windows?

我还尝试使用 docker 日志检查已停止的容器,最后一个日志也不在这里。尝试在其后添加睡眠,结果相同。

谢谢,

【问题讨论】:

  • 你有没有让这个与docker-compose一起工作?

标签: python windows docker


【解决方案1】:

当在当前版本中使用 docker-compose up 时,这似乎仍然普遍存在,我整个早上都在 Raspbian 上进行调查(并把我带到这里)。

但是,使用docker-compose 2.1.1 通过docker-compose up 使用以下配置运行您的示例表明实际调用了您的python 代码的最后一行,您只是看不到它:

docker-compose.yaml

services:
  grace_test:
    container_name: grace_test
    build: .

Dockerfile

FROM python:3.8-slim-buster

# setup WORKDIR
ADD . /grace_test
WORKDIR /grace_test
CMD ["python", "test.py"]

test.py

import signal
import time
import logging, sys

class GracefulKiller:
  kill_now = False
  def __init__(self):
    signal.signal(signal.SIGINT, self.exit_gracefully)
    signal.signal(signal.SIGTERM, self.exit_gracefully)

  def exit_gracefully(self,signum, frame):
    self.kill_now = True

if __name__ == '__main__':
  logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
  killer = GracefulKiller()
  while True:
    time.sleep(1)
    logging.info("doing something in a loop ...")
    if killer.kill_now:
      break

  logging.info("End of the program. I was killed gracefully :)")

验证

使用docker-compose logs检查Ctrl-C之后的日志:

$ docker-compose logs
grace_test  | INFO:root:doing something in a loop ...
grace_test  | INFO:root:doing something in a loop ...
grace_test  | INFO:root:doing something in a loop ...
grace_test  | INFO:root:doing something in a loop ...
grace_test  | INFO:root:End of the program. I was killed gracefully :)

【讨论】:

    【解决方案2】:

    只要抓住KeyboardInterrupt就可以了。

    if __name__ == '__main__':
      logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
      try:
        while True:
          time.sleep(1)
          logging.info("doing something in a loop ...")
      except KeyboardInterrupt as ex:
        print('goodbye!')
    

    【讨论】:

    • OP 询问如何使用操作系统信号。
    • @tgogos 在哪里?不是在标题中,也不是在文本中,我发现 OP 需要操作系统信号。从我看到的问题的标题和精神来看,无论如何他都需要停止容器的方法。
    • 我不需要信号,只是 docker 似乎正在使用它来优雅地停止容器:ctl.io/developers/blog/post/…
    • @Tigzy 当我使用docker run ... 时,您的代码似乎可以工作,但在我使用docker-compose up 时却失败了。 github 上有一些问题提到了这种不稳定的行为(#3347#3317)。
    猜你喜欢
    • 1970-01-01
    • 2016-05-10
    • 2018-09-08
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    • 2016-04-02
    相关资源
    最近更新 更多