【问题标题】:Docker restart entrypointDocker 重启入口点
【发布时间】:2016-08-05 10:48:47
【问题描述】:

我在大约一个月前开始使用 docker,但无法找到令人满意的解决方案来解决以下情况。

我想部署一个 NodeJS 应用程序,因为使用 ENTRYPOINT 是最佳实践,我更喜欢使用这个命令: ENTRYPOINT ["node", "src/start.js"].

但是我还没有找到在容器中重新启动入口点进程的方法,这意味着每次我在 nodejs 应用程序中更改某些内容时,我都必须重新启动整个容器,这在具有共享卷的开发环境中有点烦人。

我想到的一个解决方案是为此使用进程管理器,并执行ENTRYPOINT ["pm2", "src/start.js"] 之类的操作,但对单个进程使用进程管理器对我来说似乎是错误的。

我想寻求一种方法,让我尽可能接近热插拔,而无需在“开发 Docker”和“生产 Docker”之间更改 Dockerfile。

TL;DR:应该可以在我的开发机器上不安装 NodeJS 或应用程序所需的任何东西,但可以在 docker 容器中运行所有内容,同时能够重新启动所述节点进程容器,而无需重新启动容器本身。更改 Dockerfile 不是我的选择,我想使用 ENTRYPOINT

编辑
Dockerfile

FROM mhart/alpine-node:4.4.7

# add curl and bash
RUN apk add --update curl bash

#Add user
RUN addgroup websites && adduser -s /bin/bash -D -G websites user-api

#Copy app
WORKDIR /srv/app
ADD src ./src/
ADD node_modules ./node_modules

#Expose port
EXPOSE 3000

ENTRYPOINT ["node", "src/start.js"]

使用

构建图像
docker build -t app .

使用

在我的工作站上运行容器
docker run -dit -p 53017:3000 --name app -v c:/Users/hesxenon/Projects/app:/srv/app app:latest

【问题讨论】:

  • 重启容器有什么问题?这只是一个附加了一些 cgroup 和命名空间的进程。 “容器”的重量相对较轻,不会导致 nodejs 加载应用程序的速度过慢。您是否更关心在更改之间重建容器映像?
  • 重启容器本身并没有什么问题,我只是一个非常不耐烦的人:) 我不喜欢等待 30 秒,因为我可以在 2 秒内获得相同的效果。虽然容器相对轻量级,但我认为为单个进程重新启动整个底层“系统”没有多大意义。
  • 你能用你用来“重启”你的应用程序的步骤来更新这个问题吗? docker run <myimage> node src/start.js 应该比 node src/start.js 慢得多,所以也许您在每次容器重新启动时重建映像?还是使用 docker-compose 并重新启动构成“系统”的多个容器?我相信您要问的问题是“我怎样才能加快我的 Node.js+Docker 开发和构建过程而不偏离生产构建太远”,我们只是在术语上有一些差异。
  • 因此您不会在每次重新启动时重建映像,因为您已安装本地应用程序目录。是docker stop 需要很长时间吗?
  • 既然你提到了,是的,docker stop 需要很长时间。

标签: node.js docker process-management


【解决方案1】:

pm2 有一个很棒的 npm 模块。将它作为一个全局包安装在你的 nodejs 基础镜像中。

使用ENTRYPOINT ["pm2-docker", "src/start.js"] 启动您的应用

然后您可以使用docker exec -ti <containerid> <shell> 输入 docker 映像 并使用pm2 stop 0 停止应用程序,然后重新配置,并使用pm2 start 0 再次启动它。 Whitout 杀死容器从而导致 pid1 死亡。

【讨论】:

【解决方案2】:

尝试在 Node.js 中处理 SIGTERMSIGINT 信号。

docker stopdocker restart 向您的进程发送 SIGTERM。如果没有 SIGTERM 处理程序,docker 将等待默认的 10 秒超时,直到它发送 SIGKILL 并且您的进程重新启动。这可能是您重启延迟的主要原因。

当您处理信号时,ctrl-c 发送一个SIGINT,所以也要处理它。

process.on('SIGTERM', function () {
  console.log('SIGTERM');
  process.exit(0);
}
process.on('SIGINT', function () {
  console.log('SIGINT');
  process.exit(0);
}

关于 Docker 开销

这是您正在启动的进程顶部的some info on the overhead a container requires。它非常小,所以快速测试一下:

docker@default-docker:~$ time true
real    0m 0.00s
user    0m 0.00s
sys     0m 0.00s

docker@default-docker:~$ time docker run busybox true
real    0m 0.64s
user    0m 0.01s
sys     0m 0.00s

因此,与普通进程相比,我笔记本电脑上的虚拟机在容器中启动进程所需的时间大约要长 0.64 秒。

【讨论】:

    【解决方案3】:

    我认为最好的选择是使用 nodemon:https://www.npmjs.com/package/nodemon

    它会监控您指定的源目录并在有任何变化时重新启动。

    另外作为增加容器启动时间的额外奖励,如果你复制 package.json 然后在容器上运行 npm install 它将使用缓存的包 json,可能会将其减少到一两秒因为 node_modules 将是您要复制的最大文件夹:How to cache the RUN npm install instruction when docker build a Dockerfile

    COPY package.json .
    RUN npm install
    COPY src ./src/
    

    【讨论】:

      【解决方案4】:

      docker stop takes 10 seconds by default - 您可以使用 -t 参数进行调整,但 docker restart 应该几乎是即时的,并且应该与重新启动节点相同。

      我不太清楚你所说的底层“系统”是什么意思,它不是虚拟机,只要你不重新启动 Docker 主机,重新启动容器(如果它已设置正确)不应该比重新启动进程本身花费更长的时间。

      【讨论】:

      • 这就是为什么我把系统放在双引号中,我知道它不是虚拟机,但容器仍然需要在启动时从主机加载一些二进制文件,不是吗?
      • @HES_Xenon docker 在您的容器进程运行之前确实做了 一些 工作并加载了docker-containerd-shim,但这一切都非常快。我在回答中添加了一些细节。
      猜你喜欢
      • 1970-01-01
      • 2021-12-01
      • 2017-09-14
      • 1970-01-01
      • 2023-01-12
      • 2016-10-04
      • 2013-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多