我尝试在容器启动并运行后运行以下命令。
php artisan queue:work -n -q &
“&”之所以存在,是因为守护进程选项已被弃用,后来从 Laravel 中删除。
但是,这完全破坏了我的容器启动。
CMD ["php", "artisan", "queue:work", "-n", "-q", "&"]
我应该如何以 Docker 方式做到这一点?
编辑:
使用 docker-compose 我将此行添加到我的 docker-compose.yml 文件中
command: bash -c 'php artisan queue:work -n -q;'
容器已启动,但未处理任何请求:S
使用这个:
command: bash -c 'php artisan queue:work -n -q &; echo "runs"; tail -f /dev/null'
容器启动后停止
最终解决方案
所以最后我想也许负责交付应用程序的服务器不应该是运行队列的服务器。
因此,我启动了同一 docker 映像的另一个实例,其唯一目的是运行 artisanqueue:work。
queue:work 命令在前台运行,因此您应该以这种方式运行它,这样容器就不会立即退出。
由于 Laravel 中的应用程序代码与将容器作为 Web 应用程序、队列或调度程序运行相同,因此我构建了一个可以在这些上下文中使用的映像。我使用带有环境变量的 bash 启动脚本来定义容器角色,这就是我为队列工作容器运行的脚本:
#!/bin/bash
# Defaults to an app server
role=${CONTAINER_ROLE:-app}
if [ "$role" = "queue" ]; then
# Run queue
php artisan queue:work --verbose --tries=3 --timeout=90
elif [ "$role" = "app" ]; then
# Run the web application
/usr/bin/caddy --agree=true --conf=/etc/Caddyfile
elif [ "$role" = "scheduler" ]; then
while [ true ]
do
php artisan schedule:run --verbose --no-interaction &
sleep 60
done
else
echo "Could not match the container role...."
exit 1
fi
还要注意无限 while 循环和 sleep 组合,以保持调度程序角色运行并在后台运行 Schedule:run 命令,以防调度程序运行重叠(因为它们需要每分钟运行一次,无论最后一个是否完成)。
您不能在后台运行队列,否则容器将停止,因为命令已有效完成。移除
&
,它会保持活力。
但是,如果您想在后台运行队列并且仍然能够附加到容器并访问 shell,则可以执行类似
tail -f /dev/null
的操作作为保持容器运行的最终命令。
如果需要队列正常关闭,可以按照此操作。
这取自 @Paul Redmond 在 Laravel News 的文章,并扩展了他的 docker-entrypoint 文件以满足我的需要。经过大量的优雅关闭测试后,我终于能够做到了。
docker-compose.yml 文件中的第一件事是为队列服务设置
stop_signal: SIGTERM
。
queue:
image: laravel-www
container_name: laravel-queue
stop_signal: SIGTERM
depends_on:
- app
volumes:
- .:/var/www/html
...
接下来在entrypoint.sh文件中,主要是使用
exec
命令运行queue:work。
#!/usr/bin/env bash
set -e
# Run our defined exec if args empty
if [ -z "$1" ]; then
role=${CONTAINER_ROLE:-app}
env=${APP_ENV:-production}
if [ "$env" != "local" ]; then
echo "Caching configuration..."
(cd /var/www/html && php artisan cache:clear && php artisan config:clear && php artisan route:clear && php artisan view:clear)
(cd /var/www/html && php artisan config:cache && php artisan event:cache && php artisan route:cache && php artisan view:cache)
fi
if [ "$role" = "app" ]; then
echo "Running PHP-FPM..."
exec php-fpm
elif [ "$role" = "queue" ]; then
echo "Running the queue..."
exec php /var/www/html/artisan queue:work -vv --no-interaction --tries=3 --sleep=5 --timeout=300 --delay=10
elif [ "$role" = "cron" ]; then
echo "Running the cron..."
while [ true ]
do
exec php /var/www/html/artisan schedule:run -vv --no-interaction
sleep 60
done
else
echo "Could not match the container role \"$role\""
exit 1
fi
else
exec "$@"
fi
你的工作完成了。下次您停止队列服务时,它会优雅地停止,不会等待 10 秒
SIGKILL
。我认为这与PID 1
的事情有关。
使用主管
Dockerfile:
FROM php:8.1-fpm
# Supervisor
RUN apt-get update && apt-get install -y supervisor
# config
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# dependencies
COPY . /var/www/html
RUN ... # Laravel dependencies
# run Supervisor
CMD ["/usr/bin/supervisord", "-n"]
supervisord.conf
[supervisord]
nodaemon=true
[program:laravel-queue]
command=php /var/www/html/artisan queue:work
autostart=true
autorestart=true
使用主管
apt-get 安装主管
cd /etc/supervisor/conf.d && sudo nano laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=docker exec php php /path/to/artisan queue:work redis --sleep=3 --tries=5
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/var/logs/worker.log