Docker:为不同的容器运行 Cronjob

Docker:为不同的容器运行 Cronjob

我正在寻找有关为我的 php fpm 容器运行 cronjobs 的最佳实践。

現在正在運行:

  • NGINX 容器
  • PHP FPM 容器
  • MySQL 容器

我现在想运行另一个名为“Cronjob Container”的容器,它在我的 PHP FPM 容器中执行脚本(我需要一些 PHP 依赖项)。

因此有三种可能的解决方案:

1.) 运行自己的容器

我很乐意使用这个解决方案!

最好有一个运行 CRON 的容器,这样我就可以(以某种方式)在我的 php fpm 容器上调用 docker exec......或者有另一种方法。

2.) 在 PHP 容器内运行 CRON

这没问题,但不是最佳实践。我可以在运行 cron 的 php fpm 容器内启动第二个进程。这可行,但我不确定这是否是您应该与 docker 合作的对象。

3.)运行 Hosts Cron

这太残忍了。我需要找到给定路径的 processID 和 containerID,然后运行 ​​docker exec。但这或多或少是我最后的方法了……而且我讨厌在没有部署的情况下管理 cronjobs。

那么最好的方法是什么?

祝你今天过得愉快,

巴斯蒂安

答案1

我编写了一个守护进程,用于观察容器并在其元数据中定义作业。这最接近您的 1) 解决方案。示例:

version: '2'

services:
  wordpress:
    image: wordpress
  mysql:
    image: mariadb
    volumes:
      - ./database_dumps:/dumps
    labels:
      deck-chores.dump.command: sh -c "mysqldump --all-databases > /dumps/dump-$$(date -Idate)"
      deck-chores.dump.interval: daily

'经典'、类似 cron 的配置也是可能的。

这里有文档,这是图像存储库

答案2

Cron 本身可以安装并在前台运行(cron -f),因此很容易安装在容器中。要访问其他容器,您可能会在同一个容器中为客户端 CLI 安装 docker(而不是运行守护进程)。然后要访问主机 docker 环境,最常见的解决方案是绑定安装 docker 套接字(-v /var/run/docker.sock:/var/run/docker.sock)。唯一的问题是您需要在容器内设置 docker gid 以匹配主机 gid,然后将容器内的用户添加到 docker 组。

这意味着这些用户拥有与主机上任何 docker 用户相同的访问权限,例如 root 级别访问权限,因此您需要完全信任提交这些权限的用户,或者使用某种 sudo 等效权限限制他们可以运行的命令。另一个缺点是这种权限不太可移植,并且有安全意识的管理员不太可能批准在他们的系统上运行您的容器。

使用类似 Supervisord 的工具,可以非常轻松地恢复到选项 B。虽然它不是理想的“每个容器一个进程”,但它也不完全是一种反模式,因为它将整个容器和依赖项保持在一起,并消除了对主机的任何安全风险。

选择第一种还是第二种选择取决于您的环境、谁在提交作业、有多少容器需要针对自身提交作业等。如果是管理员针对大量容器提交作业,那么 cron 容器就很有意义。但如果您是应用程序开发人员,需要将计划作业作为软件包包含在您的应用程序中,请选择第二种选择。

答案3

在另一个容器中甚至在主机上运行 cron,但通过 php-fpm 运行脚本(例如,cron 将“curl”或某些 PHP 脚本)。

确保使用安全令牌、网络限制等保护此类设置。增强功能可以是拥有一个单独的 php-fpm 池,其中包含最多可以生成一个进程的动态进程。此池只能由 cron 访问。它还可以从自己的单独设置中受益,例如更长的执行时间、更多或更少的内存等。

PS:您可以使用类似直接在FPM容器中调用脚本,而不经过nginx。

原因:您可能想要访问相同的库、相同的配置等。在 Docker 中运行随机产生且不受信号管理器控制的进程是一个非常糟糕的主意。

答案4

我正在尝试实现类似的事情。

我最初的想法是从单独的容器启动 cron 作业cron,并在另一个容器内实际执行它们(php即,为容器内运行不同脚本的每个命令设置一条crontab记录docker run -i t $containerName $scriptName ...php

这种方法不太好,因为它有缺点@BMitch也提到了。另外我不太喜欢安装docker到容器中。

我想提供另一种适合您的解决方案#1类别:可以直接运行php-fpm。虽然它不是世界上最优雅的解决方案,但它具有以下优势:

  1. 安全性 - 无需特殊或特权访问,只需使用已在 docker 虚拟网络内php-host:9000开放的主机和端口(如)nginx
  2. cron管理与php容器分离——因此扩展不会受到影响
  3. 实际上cron用于 cronish 任务 - 只需植入crontab并完成,而不是通过各种其他库重新实现 cron
  4. 脚本执行不经过nginx,因此没有人可以直接通过网络服务器运行它们,您不需要实现任何身份验证或类似机制
  5. 权限问题更少。我之前的 cron dockerization 是cron在另一个php容器中安装的,并使用卷共享代码库。这很高效,但必须谨慎处理权限,因为缓存、DI、日志等必须由 Web 服务器和用户访问和写入cron。这种方法消除了这个问题

到目前为止我遇到的唯一缺点是第一行 w/hashbang ( #!/usr/local/bin/php) 被视为实际输出,并且发出有关已发送标头的 PHP 警告 ( Cannot modify header information - headers already sent by ...) - 删除 hashbang 可以解决这个问题。

具体该怎么做呢?

  1. 例如,准备一个干净的容器alpine:3.7
  2. 安装apk-cronfcgi包裹信息
  3. 运行如下命令:
SCRIPT_FILENAME=/docroot/scripts/cron/example-script.php \
REQUEST_METHOD=GET \
cgi-fcgi -bind -connect php-fpm:9000

从 crontab 内部。

有关该主题的更多信息:直接连接PHP-FPM

相关内容