【问题标题】:How to restart Laravel queue workers inside a docker container?如何在 docker 容器中重新启动 Laravel 队列工作者?
【发布时间】:2021-06-15 13:57:46
【问题描述】:

我正在开发一个生产 docker compose 来运行我的 Laravel 应用程序。它有以下容器(其中包括):

  • php-fpm 用于应用程序
  • nginx
  • mysql
  • redis
  • 队列工作者(我的 php-fpm 的副本,加上 supervisord)。
  • 部署(我的 php-fpm 的另一个副本,其中安装了 Gitlab 运行器,以及 node+npm、composer 等)

当我推送到我的生产分支时,deployment 容器内的 gitlab 运行程序会执行我的部署脚本,该脚本会构建所有内容,运行 composer update 等

最后,我的部署脚本需要重新启动队列工作程序,它们位于 queue workers 容器内。当所有东西都安装在 VPS 上时,这很容易:php artisan queue:restart

但是如何让 deployment 容器在 queue workers 容器中运行该命令?

可能的解决方案

我的研究基本上表明容器不应该相互通信,但如果必须的话,我找到了四种可能的解决方案:

  1. 在两个容器中安装 SSH
  2. deployment容器共享docker.sock,以便它可以通过docker控制其他容器
  3. queue workers 容器监控文件系统中的目录;当它发生变化时,重新启动队列工作器
  4. 使用 queue workers 容器中的微型 http 服务器在容器之间进行通信

出于复杂性和安全性原因,我真的想避免使用 1 和 2。

我倾向于 3,但担心监控 fs 会浪费资源。有没有一种真正轻量级的方法来查看包含与 Laravel 安装一样多的文件的目录?

4 看起来有点疯狂,但肯定是可行的。是否有任何非常小的、简单的 http 服务器可以安装到 queue workers 容器中,当 deployment 容器到达端点时可以触发单个命令?

我希望有其他建议,或者如果确实没有比上述 3 或 4 更好的方法,请提供有关如何实施这些选项的任何建议。

【问题讨论】:

  • 为什么需要重启容器内的队列而不是docker restart <<container>>
  • 那是因为在我的设置中,我已经将 gitlab 运行器 inside 安装在一个容器中,因此它无法访问控制 docker。 runner 不会重建 docker 镜像,并且不涉及私有注册表;它只是克隆 git 并在容器内运行 composer install 等。

标签: laravel docker docker-compose devops


【解决方案1】:

删除现有容器并创建新容器。

容器基本上是单个进程的包装器,因此这类似于使用 Ctrl+Ckill( 1),然后再次启动它们。对于后台工作人员来说,这不应该打断他们当前的任务,而 Docker 让他们有机会在他们被杀死之前完成他们正在做的事情。

由于 Docker 镜像中的代码是固定的,因此当您的 CI 系统生成新镜像时,您无论如何都需要删除并重新创建容器才能使用新镜像运行它们。在您的设计中,“部署”容器需要访问主机的 Docker 套接字(选项 #2)才能执行与 Docker 相关的任何操作。我可能会在不同的系统上运行实际的构建序列并通过 Docker 注册表推送图像,但作为部署过程的一部分,基本上需要在目标系统上 sudo docker-compose ...

一个简单的基于 Compose 的解决方案是给每个图像一个唯一的标签,然后将其作为环境变量传递:

version: '3.8'
services:
  app:
    image: registry.example.com/php-app:${TAG:-latest}
    ...
  worker:
    image: registry.example.com/php-worker:${TAG:-latest}
    ...

那么你的部署只需要使用新标签重新运行docker-compose up

ssh root@production.example.com \
  env TAG=20210318 docker-compose up -d

Compose 将负责重新创建已更改的内容。

【讨论】:

  • 感谢您的精彩回复。对于处于这种困境中的其他任何人,我认为您的答案是最好的路径。
【解决方案2】:

我相信@David Maze 的回答是推荐的方式,但我决定发布我最终所做的事情,以防它对任何人有所帮助。

我采用了不同的方法,因为我在容器内部运行我的 CI 脚本,而不是使用 Docker 注册表并让 CI 脚本重建图像。

我仍然可以让部署容器访问docker.sock(选项#2),从而允许我的 CI 脚本控制 docker(例如重建容器等),但我并不热衷于这样做的安全隐患,所以我最终做了#3,用一个简单的inotifywait 观察我在 CI 脚本中修改的特殊“timestamp.txt”文件的变化。因为它只监视一个文件,所以它对 CPU 很轻并且运行良好。

# Start watching the special directory so we know when to restart the workers.
SITE_DIR=/var/www/projectname/public_html
WATCH_DIR=/var/www/projectname/updated_at

while true
do
    inotifywait -e create -e modify $WATCH_DIR

    if [ $? -eq 0 ]
    then
        echo "Detected Site Code Change. Executing artisan queue:restart."
        sudo -H -u www-data php $SITE_DIR/artisan queue:restart
    fi
done

所有部署脚本必须做的触发队列:重启是:

date > $WATCH_DIR/timestamp.txt

【讨论】:

    猜你喜欢
    • 2019-10-09
    • 2022-11-07
    • 2018-07-30
    • 1970-01-01
    • 2021-11-02
    • 2016-10-14
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多