如何在 Docker 容器中使用 Cron

如何在 Docker 容器中使用 Cron

按计划运行后台任务是后端服务的标准要求。过去的设置很简单——您可以在服务器中定义您的任务crontab并收工。让我们看看在cron使用 Docker 进行部署时如何利用。

容器化您的服务可以提高开发人员的工作效率。同时,它会让您想知道传统的系统管理员关注点如何映射到 Docker 概念。cron与 Docker 容器一起使用时,您有多种选择,我们将在下面按适用性顺序探索它们。在继续之前,请确保您已安装 Docker并构建了应用程序的 Docker 映像。

使用主机的 Crontab

在最基本的情况下,您始终可以使用cron运行 Docker 引擎的主机的安装。确保cron已安装,然后crontab正常编辑系统。

您可以使用docker exec在现有容器中运行命令:

*/5 * * * * docker exec example_app_container /example-scheduled-task.sh

这只有在您可以提前确定容器的名称时才有效。通常最好创建一个仅用于运行任务的新容器:

*/5 * * * * docker run --rm example_app_image:latest /example-scheduled-task.sh

每五分钟,您的系统cron安装将使用您的应用程序映像创建一个新的 Docker 容器。Docker 将/example-scheduled-task.sh在容器内执行脚本。--rm一旦脚本退出,容器将被销毁 ( )。

在容器中使用 Cron

使用主机crontab会破坏 Docker 的容器化,因为计划任务需要在您的系统上手动设置。您需要确保cron在部署到的每台主机上都安装了它。虽然它在开发中很有用,但您应该尽可能将其集成cron到您的 Dockerised 服务中。

大多数流行的 Docker 基础镜像cron默认不包含守护进程。您可以将其安装在您Dockerfile的应用程序中,然后注册您的应用程序的crontab.

首先,crontab在您的代码库中创建一个新文件:

*/5 * * * * /usr/bin/sh /example-scheduled-task.sh

接下来,修改您Dockerfile以安装cron和注册您的crontab– 以下是使用基于 Debian 的映像执行此操作的方法:

运行 apt-get update && apt-get install -y cron
复制示例-crontab /etc/cron.d/example-crontab
运行 chmod 0644 /etc/cron.d/example-crontab &&\
    crontab /etc/cron.d/example-crontab

我们安装cron并将我们的代码库复制crontab/etc/cron.d目录中。接下来,我们需要修改我们的权限crontab以确保它可以被cron. 最后,使用该crontab命令使cron守护程序知道该文件。

要完成此设置,您需要修改映像的命令或入口点以cron在容器开始运行时启动守护程序。您无法通过RUN阶段来实现这一点,Dockerfile因为这些是暂时的步骤,不会在映像的构建阶段之后持续存在。该服务将在用于构建层的临时容器中启动,而不是在运行完整映像的最终容器中启动。

如果你的容器的唯一任务是运行cron——我们将在下面详细讨论——你可以添加ENTRYPOINT ["cron", "-f"]到你的Dockerfile作为前台进程启动它。如果您需要在前台保留另一个进程,例如 Web 服务器,您应该创建一个专用的入口点脚本(例如 ENTRYPOINT ["bash", "init.sh"])并service cron start作为命令添加到该文件中。

将 Cron 与应用程序的服务分开

实施上一节中描述的设置提供了比依赖主机的crontab. 将cron守护进程添加到为您的应用程序提供服务的容器可确保任何使用您的 Docker 映像的人都将自动设置计划任务。

尽管如此,这仍然会导致混合问题。您的容器最终有两个职责——首先,提供应用程序的功能,其次,保持cron活动并运行计划任务。理想情况下,每个容器都应该提供一个特定的功能单元。

在可能的情况下,您应该cron在与应用程序不同的容器中运行您的任务。如果您正在创建 Web 后端,这意味着一个容器提供您的 Web 服务器,另一个容器cron在前台运行。

如果没有这种分离,您将无法使用 Docker Swarm 或 Kubernetes 之类的编排器来运行应用程序的多个副本。每个容器都会运行自己的cron守护进程,从而导致计划任务多次运行。这可以通过使用绑定到共享 Docker 卷中的锁定文件来缓解。尽管如此,解决根本问题并为cron守护进程引入专用容器更易于维护。

通常,您希望两个容器都基于应用程序的 Docker 映像。它们都需要连接到您的服务的 Docker 卷和网络。这将确保cron容器具有与应用程序容器相同的环境,唯一的区别是前台进程。

这不是硬性规定——在某些项目中,您的计划任务可能是独立于代码库运行的琐碎脚本。在这种情况下,cron容器可能会使用最小的基础镜像并取消与不必要的外围资源的连接。

使用单独的cron容器进行设置的一种方法是使用docker-compose. 您可以将cron容器定义为一项额外服务。您可以使用应用程序的基本映像,覆盖 entrypoint 命令来启动cron守护程序。使用docker-compose还简化了将容器附加到它需要的任何共享卷和网络的过程。

版本:“3”
 
服务:
  应用程序:
    图像:演示图像:最新
    卷:
      - 数据:/应用程序数据
  定时任务:
    图像:演示图像:最新
    入口点:/bin/bash
    命令:[“cron”,“-f”]
    卷:
      - 数据:/应用程序数据
 
卷:
  数据:

使用上面的示例,一个容器使用图像中的默认入口点为我们的应用程序提供服务。确保这并不会启动cron守护!第二个容器覆盖映像的入口点以运行cron。只要映像仍然cron安装并crontab配置好,您就可以使用它docker-compose up来启动您的应用程序。

使用 Kubernetes Cron 作业

最后,让我们看一个在 Kubernetes 中运行计划任务的简单示例。Kubernetes 带有自己的CronJob资源,您可以在清单中使用它。

cron如果您使用 Kubernetes,则无需在您的映像中安装或设置专门的容器。请注意,这CronJob是一个测试版资源,可能会在未来的 Kubernetes 版本中发生变化。

api 版本:批处理/v1beta1
种类:CronJob
元数据:
  名称:my-cron
  命名空间:我的命名空间
规格:
  时间表:“*/5 * * * *”
  并发策略:禁止
  工作模板:
    规格:
      模板:
        规格:
          容器:
            - 名称:我的容器
              图像:我的图像:最新
              命令:["/bin/bash", "/my-cron-script.sh"]
          重启策略:失败

将上述清单应用到您的集群以创建一个新cron作业,该作业将/my-cron-script.sh每五分钟在您的容器中运行。频率作为对资源中的键的常规cron定义给出。schedulespec

您可以自定义ConcurrencyPolicy控制 Kubernetes 是否允许您的作业重叠。它默认为Allow但可以更改为Forbid(防止新作业在已经存在的情况下启动)或Replace(一旦新作业开始就终止现有作业)。

推荐使用 Kubernetes 的内置资源来管理集群内的计划任务。您可以轻松访问作业日志,而无需担心准备容器以用于cron. 您只需要生成一个 Docker 镜像,其中包含您的任务需要运行的所有内容。Kubernetes 将按照您指定的时间表处理创建和销毁容器实例。

正文完