在Docker容器启动后运行自定义脚本

4
我有以下的Node.js dockerfile:
# pull image
FROM node:13.12.0-alpine

# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# install app dependencies
COPY package.json ./
COPY package-lock.json ./
RUN npm install

# add app
COPY . ./

# start app
CMD node server dev

我需要在容器启动后动态运行自定义JS脚本。我该如何实现?
更新: 我尝试在CMD之后添加以下入口点,但是既没有执行CMD也没有执行ENTRYPOINT:
ENTRYPOINT node customScript.js

添加了一个包装的shell脚本(startup.sh),以包含这两个命令:

#!/bin/sh

nohup node server dev > startup.log && node data/scripts/custom.js > custom.log

已将CMD替换为:

CMD ["./startup.sh"]

这只执行了 shell 中的第一个命令,而不是第二个。我也没有看到容器中创建输出重定向日志文件。


你能举个例子吗?例如,在应用程序的主函数中编写任何代码都可以;那是做所需设置的好地方吗?或者你可以启动一个单独的容器,或从主机进行HTTP管理调用,或使用入口点包装脚本?有很多选择。 - David Maze
只需在脚本末尾添加入口点和脚本名称,例如ENTRYPOINT[“sh”, Abc.sh]。 - Sahil Kandroo
@DavidMaze,请看我的更新。我无法在单独的容器中运行脚本,因为它需要很多来自节点容器的代码。 - sotn
所有的代码都应该在镜像中,不是吗?如果你没有使用 ENTRYPOINT 的话,你应该能够 docker run the-same-image some other command - David Maze
1
@sotn 看起来你只是想让Docker启动两个无限进程而不是一个。是这样吗?如果是的话,请参考这个链接:https://docs.docker.com/config/containers/multi-service_container/ - anemyte
显示剩余4条评论
4个回答

3

理想情况下,您应该将nohup进程在后台运行。

CMDENTRYPOINT没有任何问题。

#!/bin/sh

nohup node server dev > startup.log && node data/scripts/custom.js > custom.log

在使用nohup命令启动进程时,可以在命令后加上&符号,将进程置于后台运行。

nohup ./yourscript &

或者

nohup command &

在此之后,你可以运行node命令。

sh示例。

nohup nice "$0" "calling_myself" "$@" > $nohup_out &
node index.js
sleep 1
tail -f $nohup_out

2
您应该使用一个进程监管程序来在单个容器中运行多个进程。它们还可能会自动重新启动已经停止的进程。如果没有进程监管程序,您的进程可能会出现问题。
例如,在我的项目alpine-s6-nginx-php中,我使用s6来在单个容器中运行进程。该项目具有类似面向对象的继承模型,从以下内容开始:
  • 基础镜像alpine-s6-base
  • alpine-s6-nginx
  • 最后到alpine-s6-nginx-php
基础镜像准备了s6设置,nginx镜像添加了nginx进程,最终的alpine-s6-nginx-php镜像添加了php-fpm7进程。您可以查看这些代码库和s6进程监管程序。不需要为每个进程分离层,所有进程都可以在单个Dockerfile中添加。您也可以使用s6替代方案,如systems或etc。
简而言之,您可以使用s6-overlay轻松构建受s6监管的容器镜像。

1

您可以在脚本末尾添加入口点关键字和脚本名称,例如ENTRYPOINT ["sh", "Abc.sh"]。


请查看我对原帖的更新。 - sotn

1
如果您需要在Docker启动时运行两个命令,则其中一个应该是非阻塞的,另一个可以是阻塞调用。
如果两个调用都是阻塞的,则需要在单独的线程/进程中启动一个命令,然后运行另一个命令。
这可以通过一个父脚本(sh)来实现,该脚本可以为一个命令启动一个进程,并在当前进程中调用最后一个命令。

https://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/internal.html https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_01_04.html


1
这个似乎不是仅有链接的内容,也没有其他需要删除的地方。这是一个纯文本的解决方案描述,非常合法。而且它是自足的,所以我会把它恢复。您可能需要澄清您的回答,以避免将来发生这种错误。 - Zoe stands with Ukraine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接