Вы путаете время сборки (в основном RUN
инструкции) со временем выполнения (ENTRYPOINT
или CMD) и после этого нарушаете правило: один контейнер, один процесс, даже если это не священный.
Я предлагаю использовать Supervisord с этой конфигурацией
[unix_http_server]
file=/tmp/supervisor.sock ; path to your socket file
[supervisord]
logfile=/var/log/supervisord/supervisord.log ; supervisord log file
loglevel=error ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
nodaemon=false ; run supervisord as a daemon
minfds=1024 ; number of startup file descriptors
minprocs=200 ; number of process descriptors
user=root ; default user
childlogdir=/var/log/supervisord/ ; where child log files will live
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
[program:npm]
command=npm run --prefix /path/to/app start
stderr_logfile = /dev/stdout
stdout_logfile = /dev/stderr
[program:nginx]
command=nginx -g "daemon off;"
stderr_logfile = /dev/stdout
stdout_logfile = /dev/stderr
В этой конфигурации вы будете перенаправлять журналы на стандартный вывод, и это хорошая практика, а не файлы внутри контейнера, которые могут бытьэфемерно, также у вас будет PID, отвечающий за обработку дочерних процессов и перезапуск их с определенными правилами.
Вы можете попытаться добиться этого также с помощью скрипта bash, но это может быть сложно.
Еще один лучшийрешение должно заключаться в использовании отдельного контейнера с сетевым пространством имен для пересылки запросов NGINX восходящему потоку NPM ... но без Kubernetes его вряд ли можно поддерживать, даже если это не просто с помощью Docker:)