如何在Docker Swarm的/bin/sh中正确使用exec "$@"启动容器进程?
问题分析与解决
你的问题核心是ENTRYPOINT和CMD的配置逻辑错误,导致entrypoint.sh里的exec "$@"没有接收到任何可执行的命令参数,容器自然会因无进程运行而退出。
错误原因
当前Dockerfile的配置是:
ENTRYPOINT ["/bin/sh"] CMD ["entrypoint.sh"]
这会让容器启动时执行/bin/sh entrypoint.sh——此时entrypoint.sh作为sh的参数被调用,但你没有给entrypoint.sh传递任何后续参数,所以脚本里的$@是空值,exec "$@"相当于执行空命令,容器直接退出。
正确配置方案
方案一:直接将entrypoint.sh设为ENTRYPOINT(推荐)
修改Dockerfile的ENTRYPOINT和CMD,让entrypoint脚本作为入口,CMD提供默认的启动命令(即openresty的nginx启动命令):
FROM openresty/openresty:alpine-fat WORKDIR / COPY entrypoint.sh entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"]
这样容器启动时,会执行/entrypoint.sh nginx -g 'daemon off;',脚本里的exec "$@"会替换当前进程为nginx -g 'daemon off;',既实现了你想要的exec传递信号的效果,也能正常启动openresty进程。
方案二:保留/bin/sh作为ENTRYPOINT(不推荐)
如果一定要通过sh调用脚本,需要用-c参数传递完整命令链,让$@能拿到后续参数:
FROM openresty/openresty:alpine-fat WORKDIR / COPY entrypoint.sh entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/bin/sh", "-c"] CMD ["/entrypoint.sh nginx -g 'daemon off;'"]
这种方式绕了一层shell,不如方案一直接,且可能影响信号传递的可靠性。
额外说明
exec "$@"的核心作用是让实际运行的进程替换entrypoint脚本的进程,这样容器的主进程就是业务进程(比如nginx),外部发送的停止信号(如SIGTERM)能直接传递给它,避免僵尸进程问题。
内容的提问来源于stack exchange,提问作者SapphireBlazer01
相关产品推荐
相关产品推荐

