我正在制作一个生产docker compose来运行我的Laravel应用程序。它有以下容器(以及其他容器(:
应用程序的- php fpm
- nginx
- mysql
- redis
- 队列工作者(我的php-fpm的副本,加上supervisord(
- 部署(我的php-fpm的另一个副本,其中安装了Gitlab运行程序,以及node+npm、composer等(
当我推送到我的生产分支时,部署容器内的gitlab运行程序执行我的部署脚本,该脚本构建所有内容,运行composer更新等
最后,我的部署脚本需要重新启动队列工作者容器中的队列工作者。当所有东西都一起安装在VPS上时,这很容易:php artisan queue:restart
。
但是我如何让部署容器在队列工作者集装箱内运行该命令
潜在解决方案
我的研究表明,容器基本上不应该相互交谈,但如果必须的话,我已经找到了四种可能的解决方案:
- 在两个容器中安装SSH
- 与部署容器共享
docker.sock
,以便它可以通过docker控制其他容器 - 让队列工作者容器监视文件系统中的一个目录;更改后,重新启动队列工作程序
- 容器与队列工作者容器中的小型http服务器之间进行通信
出于复杂性和安全性的原因,我确实希望分别避免1和2。
我倾向于3,但担心监控fs会浪费资源。有没有一种真正轻量级的方法可以监视一个目录,其中的文件数量与Laravel安装的文件数量一样多?
4看起来有点疯狂,但确实做得很好。是否有任何真正微小、简单的http服务器可以安装到队列工作者容器中,当部署集装箱到达端点时,这些服务器可以触发单个命令?
我希望能得到其他建议,或者如果真的没有比上面的3或4更好的方法,希望能得到关于如何实施这两个选项的任何建议
删除现有容器并创建新容器。
容器基本上是单个进程的包装器,因此这类似于使用Ctrl+C或kill(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将负责重新创造已经改变的事物。
我相信@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