Docker中的Cron容器 - 它们实际上是如何工作的?

10

我已经使用Docker几个月了,并且正在将各种不同的服务器映像Docker化。一个一致性的问题是许多服务器需要运行cron作业。关于这个问题有很多在线讨论(包括在Stackoverflow上),但我并不完全理解其机制。

目前,我正在使用主机的cron,并且通过docker exec进入每个容器来运行脚本。我为脚本的名称和位置创建了一个约定;所有我的容器都有相同的脚本。这避免了主机的cron依赖于容器。

基本上,每分钟一次,主机的cron会执行以下操作:

for each container
   docker exec -it <containername> /cronscript/minute-script

这样做可以实现,但会使容器依赖主机。

我想要做的是创建一个cron容器,在其他容器中启动脚本 - 但我不知道有没有类似于“docker exec”的东西可以从一个容器到另一个容器中运行。

我目前遇到的具体情况是在MySQL容器中运行备份,并在每分钟运行Moodle所需的定时任务。最终,我还需要通过cron完成其他事情。Moodle使用命令行PHP脚本。

从一个容器中启动另一个容器中的脚本的正确docker化方法是什么?

更新: 可能我的具体用例会有所帮助,尽管随着时间的推移,可能还会有更多。

目前,cron需要执行以下操作:

  • 从MySQL执行数据库转储。我可以通过mysqldump TCP链接从cron容器中进行操作;这里的缺点是我无法将备份用户限制为127.0.0.1主机。我也许还可以通过卷来将MySQL套接字弄进cron容器。
  • 对Moodle安装执行常规维护。Moodle包括一个php命令行脚本,可运行所有维护任务。对我来说,这是最重要的。我可能可以通过卷运行此脚本,但Moodle并不是为这种情况而设计的,我不能排除竞态条件。此外,我不希望将我的moodle安装在卷中,因为这会使更新容器变得更加困难(请记住,在Docker中,当您使用新镜像更新容器时,卷不会重新初始化)。
  • 未来:对我其他几台服务器执行日常维护,例如清理电子邮件队列等。

你读过 https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86#.uwmlzjix5 吗? - user2915097
有趣的想法,我没有考虑过这样做。不过它似乎也存在同样的问题;或者有一种方法让一个容器向另一个容器发送信号吗? - Kevin Keane
请参考以下网址了解如何通过主机名在Docker容器之间进行通信:https://dev59.com/eV0a5IYBdhLWcg3wPWpN 和 http://blog.sequenceiq.com/blog/2014/08/12/docker-networking/ - user2915097
1
请查看 https://docs.docker.com/engine/reference/commandline/run/ 中的 docker run 的文档 --link=[] 将另一个容器链接到当前容器 - user2915097
如果您需要操作的数据在一个卷中,您可以使用命名卷或 volumes_from。这使您可以在不同的容器中运行计划任务(与链接相同的想法,但不同的机制)。卷的名称(或容器,如果您正在使用 volumes_from)可以作为 crontab 条目的一部分包含在其中。 - dnephin
显示剩余2条评论
1个回答

12

我的解决方案是:

  • 在容器中安装 crond
  • 安装您的软件
  • 将 cron 作为守护进程运行
  • 运行您的软件

我的 Dockerfile 的一部分

FROM debian:jessie

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY .crontab /usr/src/app

# Set timezone
RUN echo "Europe/Warsaw" > /etc/timezone \
    && dpkg-reconfigure --frontend noninteractive tzdata

# Cron, mail
RUN set -x \
    && apt-get update \
    && apt-get install -y cron rsyslog mailutils --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

CMD rsyslogd && env > /tmp/crontab && cat .crontab >> /tmp/crontab && crontab /tmp/crontab && cron -f

描述

  1. 设置时区,因为cron需要此项来正确运行任务
  2. 安装cron软件包 - 包含cron守护程序的软件包
  3. 安装rsyslog软件包以记录cron任务输出
  4. 如果您想要从cron任务发送电子邮件,则安装mailutils软件包
  5. 运行rsyslogd
  6. 将环境变量复制到临时文件中,因为cron使用最小化的环境运行任务,您的任务可能需要访问容器的环境变量
  7. 将您的.crontab文件(包含您的任务)追加到tmp文件中
  8. 从tmp文件中设置根cron表
  9. 运行cron守护程序

我在我的容器中使用这个方法,非常有效。

一个容器一个进程

如果您喜欢这种范式,请为每个cron任务创建一个Dockerfile。例如:

  • Dockerfile - 主程序
  • Dockerfile_cron_task_1 - cron任务1
  • Dockerfile_cron_task_2 - cron任务2

并构建所有容器:

docker build -f Dockerfile_cron_task_1 ...

谢谢!我能看出这个解决方案的工作原理,但它打破了每个容器一个进程的范式。虽然如此,我喜欢它将所有内容都包含在同一个容器中,而且我可能会真的采用这个解决方案;似乎对于这个问题并没有真正好的解决方案。 - Kevin Keane
我注意到你对答案的补充(关于每个容器一个进程),它确实解决了关注点分离的问题,但最终仍然存在同样的问题,即从cron容器到主容器的通信只能通过共享卷或链接来实现。你的架构允许cron对主容器有更多的了解,因此它可能至少能够满足80%的真实应用场景。 - Kevin Keane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接