【问题标题】:How to run a cron job inside a docker container?如何在 docker 容器中运行 cron 作业?
【发布时间】:2016-09-24 07:21:12
【问题描述】:

我正在尝试在调用 shell 脚本的 docker 容器中运行 cronjob。

昨天我一直在网上搜索和堆栈溢出,但我真的找不到有效的解决方案。
我该怎么做?

编辑:

我创建了一个(commented) github repository,其中包含一个工作的 docker cron 容器,它以给定的时间间隔调用一个 shell 脚本。

【问题讨论】:

    标签: docker cron containers sh


    【解决方案1】:

    Cron 作业存储在 /var/spool/cron/crontabs(我知道的所有发行版中的常见位置)。顺便说一句,您可以使用类似的方法在 bash 中创建一个 cron 选项卡:

    crontab -l > cronexample
    echo "00 09 * * 1-5 echo hello" >> cronexample
    crontab cronexample
    rm cronexample
    

    这将使用 cron 任务创建一个临时文件,然后使用 crontab 对其进行编程。最后一行删除临时文件。

    【讨论】:

    • cron 守护进程通常不在容器中运行。
    • @BhargavNanekalva 它需要专门设置在这个答案没有解决的容器中。
    • @Matt,您能否指出它应该如何在容器中具体指定? .我做了 crontab -l 并显示了命令 - kagda.ru/i/6d014816d43_29-06-2017-11:38:59_6d01.png 但仍然没有运行
    • @Копать_Шо_я_нашел 除了在容器中运行的服务之外,您还必须运行 crond,通常使用像 s6 这样的服务管理器。可能会问这个问题以获得正确的答案
    【解决方案2】:

    您可以将您的 crontab 复制到一个映像中,以便从该映像启动的容器运行该作业。

    在他的Ekito/docker-cron 中看到来自Julien Boulay 的“Run a cron job with Docker”:

    让我们创建一个名为“hello-cron”的新文件来描述我们的工作。

    * * * * * echo "Hello world" >> /var/log/cron.log 2>&1
    # An empty line is required at the end of this file for a valid cron file.
    

    如果你想知道什么是 2>&1,Ayman Houriehexplains

    以下 Dockerfile 描述了构建映像的所有步骤

    FROM ubuntu:latest
    MAINTAINER docker@ekito.fr
    
    RUN apt-get update && apt-get -y install cron
    
    # Copy hello-cron file to the cron.d directory
    COPY hello-cron /etc/cron.d/hello-cron
     
    # Give execution rights on the cron job
    RUN chmod 0644 /etc/cron.d/hello-cron
    
    # Apply cron job
    RUN crontab /etc/cron.d/hello-cron
     
    # Create the log file to be able to run tail
    RUN touch /var/log/cron.log
     
    # Run the command on container startup
    CMD cron && tail -f /var/log/cron.log
    

    (见GaafarcommentHow do I make apt-get install less noisy?
    apt-get -y install -qq --force-yes cron也可以工作)

    正如Nathan Lloydthe comments 中所指出的:

    关于一个陷阱的快速说明:
    如果您要添加脚本文件并告诉 cron 运行它,请记住
    RUN chmod 0744 /the_script
    如果您忘记了,Cron 会静默失败


    或者,确保您的作业本身直接重定向到 stdout/stderr 而不是日志文件,如hugoShakaanswer 中所述:

     * * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
    

    将 Dockerfile 的最后一行替换为

    CMD ["cron", "-f"]
    

    另见(关于cron -f,也就是说cron“前台”)“docker ubuntu cron -f is not working


    构建并运行它:

    sudo docker build --rm -t ekito/cron-example .
    sudo docker run -t -i ekito/cron-example
    

    请耐心等待 2 分钟,您的命令行应该会显示:

    Hello world
    Hello world
    

    Eric 添加in the comments

    请注意,如果tail 在映像构建期间创建,它可能无法显示正确的文件。
    如果是这种情况,您需要在容器运行时创建或触摸文件,以便 tail 拾取正确的文件。

    见“Output of tail -f at the end of a docker CMD is not showing”。


    Jason Kulatunga 的“Running Cron in Docker”(2021 年 4 月)中查看更多信息,就像他在 commented below 一样

    查看 Jason 的图片AnalogJ/docker-cron,基于​​:

    • Dockerfile 安装 cronie/crond,取决于发行版。

    • 初始化/etc/environment然后调用的入口点

      cron -f -l 2
      

    【讨论】:

    • 您可能应该在安装 cron 时添加 -y 以避免 docker build 退出
    • 这个解决方案还能用吗?当我遵循给定的指导方针时,当我以 root 身份登录容器并输入 crontab -l 时,我得到 No crontab installed for root,而且我的屏幕仍然是空白的。但是,当我检查“/etc/cron.d/”时,我看到 crontab 字段在那里(更令人惊讶的是),当我检查 /var/log/cron.log 时,我看到脚本正在运行(正在附加文件内容与Hello World)。我在我的 Dockerfile 中提取这个图像:FROM phusion/baseimage:0.10.0。关于行为差异的任何想法?
    • 自 2018 年起,这种方法不再有效;有没有人能够让他们的 cronjob 使用 Ubuntu 作为基础映像?我对开箱即用的 cron 附带的 Alpine 映像不感兴趣
    • 关于一个陷阱的快速说明:如果您要添加一个脚本文件并告诉 cron 运行它,请记住RUN chmod 0744 /the_script。如果你忘记了,Cron 会默默地失败。
    • 我写了一篇博文,将这个建议(以及我在 docker 中运行 cron 时发现的其他问题)实现到多个发行版(ubuntu、alpine、centos)的工作 docker 镜像中:blog.thesparktree.com/cron-in-docker
    【解决方案3】:

    我根据其他答案创建了一个 Docker 镜像,可以像这样使用

    docker run -v "/path/to/cron:/etc/cron.d/crontab" gaafar/cron

    其中/path/to/cron:crontab 文件的绝对路径,或者您可以将其用作 Dockerfile 中的基础:

    FROM gaafar/cron
    
    # COPY crontab file in the cron directory
    COPY crontab /etc/cron.d/crontab
    
    # Add your commands here
    

    供参考,图片is here

    【讨论】:

      【解决方案4】:

      当您在另一台主机上部署容器时,请注意它不会自动启动任何进程。您需要确保“cron”服务在您的容器内运行。 在我们的例子中,我使用 Supervisord 和其他服务来启动 cron 服务。

      [program:misc]
      command=/etc/init.d/cron restart
      user=root
      autostart=true
      autorestart=true
      stderr_logfile=/var/log/misc-cron.err.log
      stdout_logfile=/var/log/misc-cron.out.log
      priority=998
      

      【讨论】:

      • 我在 supervisor.log 中收到一个错误,表明 cron 服务多次停止并进入了 FATAL 状态。但是 cron 似乎在顶部运行并正常执行 cronjobs。谢谢!
      • 是的,我也发生了同样的事情,但它可以正常工作,所以不需要打扰。
      【解决方案5】:

      虽然这旨在通过 Docker 的 exec 接口在容器中正在运行的进程旁边运行作业,但您可能对此感兴趣。

      我编写了一个守护程序,它可以观察容器并在它们的元数据中定义作业并安排作业。示例:

      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
      

      'Classic',类似 cron 的配置也是可能的。

      这里是docs,这里是image repository

      【讨论】:

      • 谢谢。这个答案最适合 Docker 容器环境。 Docker 镜像没有任何变化,只添加了执行任务的特殊容器,它的工作方式类似于命令 docker exec <container_name> <some_command> 按计划。
      【解决方案6】:

      VonC's 的回答非常彻底。此外,我想补充一件对我有帮助的事情。如果您只想运行 cron 作业而不拖尾文件,您可能会很想从 cron 命令中删除 && tail -f /var/log/cron.log

      但是这会导致 Docker 容器在运行后不久退出,因为当 cron 命令完成时,Docker 认为最后一个命令已经退出并因此终止容器。这可以通过cron -f 在前台运行 cron 来避免。

      【讨论】:

        【解决方案7】:

        @VonC 的建议很好,但我更喜欢在一行中完成所有 cron 作业配置。这样可以避免 cronjob 位置等跨平台问题,并且您不需要单独的 cron 文件。

        FROM ubuntu:latest
        
        # Install cron
        RUN apt-get -y install cron
        
        # Create the log file to be able to run tail
        RUN touch /var/log/cron.log
        
        # Setup cron job
        RUN (crontab -l ; echo "* * * * * echo "Hello world" >> /var/log/cron.log") | crontab
        
        # Run the command on container startup
        CMD cron && tail -f /var/log/cron.log
        

        运行 docker 容器后,您可以通过以下方式确定 cron 服务是否正常工作:

        # To check if the job is scheduled
        docker exec -ti <your-container-id> bash -c "crontab -l"
        # To check if the cron service is running
        docker exec -ti <your-container-id> bash -c "pgrep cron"
        

        如果您更喜欢使用 ENTRYPOINT 而不是 CMD,那么您可以将上面的 CMD 替换为

        ENTRYPOINT cron start && tail -f /var/log/cron.log
        

        【讨论】:

        • RUN apt-get update &amp;&amp; apt-get -y install cron 否则找不到包cron
        • 谢谢 Youness,你给了我执行以下操作的想法,这在我的情况下有效,每个 cron 在不同的文件中指定:RUN cat $APP_HOME/crons/* | crontab 就像一个魅力:)
        • cron 添加到入口点脚本似乎是最好的选择:ENTRYPOINT ["entrypoint.sh"]
        • ENTRYPOINT 中使用 2 个命令是危险的。我相信第一个(cron)分叉到后台,而第二个(tail)在前台运行。如果cron 停止,您将永远不会知道。如果tail 停止,docker 会注意到。
        • 这在某种程度上是有道理的,尽管您可以围绕它添加一些监控/日志记录(使用另一个入口点或其他一些监控机制)来检查 cron 服务的健康状态
        【解决方案8】:

        接受的答案在生产环境中可能很危险

        在 docker 中,每个容器只应执行一个进程,因为如果不这样做,分叉并进入后台的进程不会受到监控,并且可能会在您不知情的情况下停止。

        当你使用CMD cron &amp;&amp; tail -f /var/log/cron.log时,cron进程基本上fork以便在后台执行cron,主进程退出并让你在前台执行tailf。后台 cron 进程可能会停止或失败,您不会注意到,您的容器仍会静默运行,并且您的编排工具不会重新启动它。

        您可以通过将 cron 的命令输出直接重定向到分别位于 /proc/1/fd/1/proc/1/fd/2 的 docker stdoutstderr 来避免这种情况。

        使用基本的 shell 重定向,您可能想做这样的事情:

        * * * * * root echo hello > /proc/1/fd/1 2>/proc/1/fd/2
        

        您的 CMD 将是:CMD ["cron", "-f"]

        【讨论】:

        • 不错:cron -f 用于“cron 前台”。我已将您的答案包含在我的上面,以获得更多可见性。 +1
        • 假设我的程序没有输出任何东西。我还能使用这种方法并确保我的进程不会在后台停止吗?
        • @Arcsector 此方法避免将进程置于后台,这就是它不会静默失败的原因。在 docker 容器中拥有后台进程并不简单。如果您希望有一个正在运行的后台进程,您可能希望使用一个 init 进程来监控您在容器中运行的多个进程。另一种方法是在名为“sidecar”的主容器旁边的另一个容器中启动该过程。最好的方法通常是避免容器中的多个进程。
        • 漂亮干净!喜欢它:)
        • 这是一个很好的解决方案,除了一个问题外,对我们也很有效。当容器收到 SIGTERM 信号时,它似乎并没有等待计划进程完成并正常关闭,而是杀死可能导致问题的进程。
        【解决方案9】:

        还有另一种方法,就是使用Tasker,这是一个支持 cron(调度程序)的任务运行程序。

        为什么?有时要运行 cron 作业,您必须将基础映像(python、java、nodejs、ruby)与 crond 混合。这意味着要维护另一个图像。 Tasker 通过分离 crond 和你的容器来避免这种情况。您可以只关注您想要执行命令的图像,并配置 Tasker 以使用它。

        这是一个docker-compose.yml 文件,它将为您运行一些任务

        version: "2"
        
        services:
            tasker:
                image: strm/tasker
                volumes:
                    - "/var/run/docker.sock:/var/run/docker.sock"
                environment:
                    configuration: |
                        logging:
                            level:
                                ROOT: WARN
                                org.springframework.web: WARN
                                sh.strm: DEBUG
                        schedule:
                            - every: minute
                              task: hello
                            - every: minute
                              task: helloFromPython
                            - every: minute
                              task: helloFromNode
                        tasks:
                            docker:
                                - name: hello
                                  image: debian:jessie
                                  script:
                                      - echo Hello world from Tasker
                                - name: helloFromPython
                                  image: python:3-slim
                                  script:
                                      - python -c 'print("Hello world from python")'
                                - name: helloFromNode
                                  image: node:8
                                  script:
                                      - node -e 'console.log("Hello from node")'
        

        那里有 3 个任务,每分钟都会运行一次 (every: minute),每个任务都会执行 script 代码,在 image 部分定义的图像内。

        只需运行docker-compose up,就可以看到它工作了。以下是包含完整文档的 Tasker 存储库:

        http://github.com/opsxcq/tasker

        【讨论】:

        • Dockerception(从另一个容器运行 docker 容器)是一种不好的做法,应该仅限于持续集成。一种解决方法是在指定容器上使用docker exec
        • Tasker 在 docker (Dind/Dockerception) 中不使用 docker,请注意作为映射传递给 docker 套接字,所有生成的容器都在 tasker 运行的守护进程中生成。如果您不想在 docker 中运行 tasker,您可以将其部署为任何其他应用程序。
        • 我没有得到使用 tasker 的好处。对我来说,使用 java 和 sh*** 来运行 cron 作业似乎真的有点过头了。
        • 混合 cron 和你需要的基础镜像(例如 python/node)创建一个需要维护和部署的额外依赖,在这种情况下所有作业共享同一个容器,这意味着你必须担心在每个作业运行后清理所有内容。在 tasker 上运行的作业是幂等的,因此您不必担心。
        【解决方案10】:

        在一些限制root访问的精简图像上运行时,我必须将我的用户添加到sudoers并以sudo cron运行

        FROM node:8.6.0
        RUN apt-get update && apt-get install -y cron sudo
        
        COPY crontab /etc/cron.d/my-cron
        RUN chmod 0644 /etc/cron.d/my-cron
        RUN touch /var/log/cron.log
        
        # Allow node user to start cron daemon with sudo
        RUN echo 'node ALL=NOPASSWD: /usr/sbin/cron' >>/etc/sudoers
        
        ENTRYPOINT sudo cron && tail -f /var/log/cron.log
        

        也许对某人有帮助

        【讨论】:

        • 我相信节点镜像使用节点用户;所以也许你需要为那个用户添加权限
        【解决方案11】:

        对于那些想要使用简单轻量图像的人:

        FROM alpine:3.6
        
        # copy crontabs for root user
        COPY config/cronjobs /etc/crontabs/root
        
        # start crond with log level 8 in foreground, output to stderr
        CMD ["crond", "-f", "-d", "8"]
        

        cronjobs 是包含您的 cronjobs 的文件,格式如下:

        * * * * * echo "hello stackoverflow" >> /test_file 2>&1
        # remember to end this file with an empty new line
        

        【讨论】:

        • 基于简单、轻便和标准的图像。这应该是公认的答案。还可以使用 &gt; /proc/1/fd/1 2&gt; /proc/1/fd/2 重定向直接从 docker 日志访问 cronjobs 输出。
        • 对于不使用 alpine 的人:支持 -d 8 参数的 crond 不是标准的 cron,它是来自 busybox 的 crond 命令。例如,在 ubuntu 中,您可以将其作为 busybox crond -f -d 8 运行。对于旧版本,您必须使用-L /dev/stdout/
        • 如果可以的话,我会给这个+100。这是迄今为止在 Docker 环境中运行 cron 作业的最佳方式。
        • 这可以完全由带有image:alpine的docker-compose.yml完成吗?
        • CMD ["crond"CMD ["cron"?
        【解决方案12】:

        在专用容器中定义 cronjob,该容器通过 docker exec 向您的服务运行命令。

        这是更高的内聚性,运行脚本将可以访问您为服务定义的环境变量。

        #docker-compose.yml
        version: "3.3"
        services:
            myservice:
              environment:
                MSG: i'm being cronjobbed, every minute!
              image: alpine
              container_name: myservice
              command: tail -f /dev/null
        
            cronjobber:
             image: docker:edge
             volumes:
              - /var/run/docker.sock:/var/run/docker.sock
             container_name: cronjobber
             command: >
                  sh -c "
                  echo '* * * * * docker exec myservice printenv | grep MSG' > /etc/crontabs/root
                  && crond -f"
        

        【讨论】:

        • 我无法使用 docker swarm 让它工作。收到myservice unknown 错误。
        • 应该有关于安装 docker 套接字的高安全性影响的警告:lvh.io/posts/…
        【解决方案13】:

        尝试使用 Clockwork gem 来安排任务。请按照此链接中提供的步骤操作。

        http://fuzzyblog.io/blog/rails/2017/05/11/adding-cron-to-a-dockerized-rails-application-using-clockwork.html

        您可以在 lib/clock.rb 文件中调用 rake 任务,如下所示。

        every(1.day, 'Import large data from csv files', :at => '5:00') do |job|
          `rake 'portal:import_data_from_csv'`
        end
        

        在 docker-compose 文件中创建一个单独的容器并在容器内运行以下命令。

        command: bundle exec clockwork lib/clock.rb
        

        【讨论】:

        • 使用其他工具进行日程安排的好主意。但是,这个问题是专门针对 cron 提出的,所以在我看来,您的建议最好作为对该问题的评论。
        【解决方案14】:

        所以,我的问题是一样的。解决方法是更改​​docker-compose.yml 中的命令部分。

        来自

        命令:crontab /etc/crontab && tail -f /etc/crontab

        收件人

        命令:crontab /etc/crontab

        命令:tail -f /etc/crontab

        问题是命令之间的“&&”。删除后就没事了。

        【讨论】:

          【解决方案15】:

          如果您使用 docker for windows,请记住,如果您打算将 crontab 文件从 windows 导入到 ubuntu 容器,则必须将行尾格式从 CRLF 更改为 LF(即从 dos 到 unix)。如果没有,您的 cron-job 将无法工作。这是一个工作示例:

          FROM ubuntu:latest
          
          RUN apt-get update && apt-get -y install cron
          RUN apt-get update && apt-get install -y dos2unix
          
          # Add crontab file (from your windows host) to the cron directory
          ADD cron/hello-cron /etc/cron.d/hello-cron
          
          # Change line ending format to LF
          RUN dos2unix /etc/cron.d/hello-cron
          
          # Give execution rights on the cron job
          RUN chmod 0644 /etc/cron.d/hello-cron
          
          # Apply cron job
          RUN crontab /etc/cron.d/hello-cron
          
          # Create the log file to be able to run tail
          RUN touch /var/log/hello-cron.log
          
          # Run the command on container startup
          CMD cron && tail -f /var/log/hello-cron.log
          

          这实际上花了我几个小时才弄清楚,因为在 docker 容器中调试 cron 作业是一项乏味的任务。希望它可以帮助其他无法让他们的代码工作的人!

          【讨论】:

          • 这有助于解决我在尝试使输出重定向工作时遇到的问题。像 cat /proc/1/status &gt; /proc/1/fd/1 这样的命令会从 crond 返回一个错误,声明 crond: USER root pid 6 cmd root cat /proc/1/status &gt; /proc/1/fd/1: nonexistent directory/proc/1/fd/1。将行尾更改为 Unix 使我能够成功运行命令。谢谢,这花了我几个小时才弄清楚!
          【解决方案16】:

          从上面的例子中我创建了这个组合:

          在 Nano 中使用 Crontab 进行高山图像和编辑(我讨厌 vi)

          FROM alpine
          
          RUN apk update
          RUN apk add curl nano
          
          ENV EDITOR=/usr/bin/nano 
          
          # start crond with log level 8 in foreground, output to stderr
          CMD ["crond", "-f", "-d", "8"]
          
          # Shell Access
          # docker exec -it <CONTAINERID> /bin/sh
          
          # Example Cron Entry
          # crontab -e
          # * * * * * echo hello > /proc/1/fd/1 2>/proc/1/fd/2
          # DATE/TIME WILL BE IN UTC
          

          【讨论】:

            【解决方案17】:

            设置一个与一次性作业并行的 cron

            创建一个脚本文件,比如 run.sh,其中包含应该定期运行的作业。

            #!/bin/bash
            timestamp=`date +%Y/%m/%d-%H:%M:%S`
            echo "System path is $PATH at $timestamp"
            

            保存并退出。

            使用入口点代替 CMD

            如果您在 docker 容器化期间有多个作业要启动,请使用入口点文件来运行它们。

            入口点文件是一个脚本文件,它在发出 docker run 命令时生效。所以,我们想要运行的所有步骤都可以放在这个脚本文件中。

            例如,我们有 2 个作业要运行:

            运行一次作业:回显“Docker 容器已启动”

            运行定期作业:run.sh

            创建 entrypoint.sh

            #!/bin/bash
            
            # Start the run once job.
            echo "Docker container has been started"
            
            # Setup a cron schedule
            echo "* * * * * /run.sh >> /var/log/cron.log 2>&1
            # This extra line makes it a valid cron" > scheduler.txt
            
            crontab scheduler.txt
            cron -f
            

            了解一下文件中已经设置好的crontab

            * * * * *: Cron 调度;作业必须每分钟运行一次。您可以根据自己的要求更新时间表。

            /run.sh: 周期性运行的脚本文件路径

            /var/log/cron.log:保存计划的 cron 作业输出的文件名。

            2&gt;&amp;1:错误日志(如果有)也将被重定向到上面使用的相同输出文件。

            注意:不要忘记添加一个额外的新行,因为它使它成为一个有效的 cron。 Scheduler.txt: 完整的 cron 设置将被重定向到一个文件。

            在 cron 中使用系统/用户特定的环境变量

            我实际的 cron 作业期望将大多数参数作为传递给 docker run 命令的环境变量。但是,使用 bash,我无法使用属于系统或 docker 容器的任何环境变量。

            然后,这是解决这个问题的方法:

            1. 在 entrypoint.sh 中添加以下行
            declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
            
            1. 更新 cron 设置并指定-
            SHELL=/bin/bash
            BASH_ENV=/container.env
            

            最后,你的entrypoint.sh 应该是这样的

            #!/bin/bash
            
            # Start the run once job.
            echo "Docker container has been started"
            
            declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env
            
            # Setup a cron schedule
            echo "SHELL=/bin/bash
            BASH_ENV=/container.env
            * * * * * /run.sh >> /var/log/cron.log 2>&1
            # This extra line makes it a valid cron" > scheduler.txt
            
            crontab scheduler.txt
            cron -f
            

            最后但并非最不重要的一点:创建一个 Dockerfile

            FROM ubuntu:16.04
            MAINTAINER Himanshu Gupta
            
            # Install cron
            RUN apt-get update && apt-get install -y cron
            
            # Add files
            ADD run.sh /run.sh
            ADD entrypoint.sh /entrypoint.sh
            
            RUN chmod +x /run.sh /entrypoint.sh
            
            ENTRYPOINT /entrypoint.sh
            

            就是这样。构建并运行 Docker 镜像!

            【讨论】:

            • @himanshuIIITian 我试过了,问题是“运行一次作业”的脚本永远不会返回,并且玉米 -f 也没有返回所以......这对我不起作用,有任何想法吗?谢谢
            • @DoronLevi - 你能分享一些日志来调查这个问题吗?或者您可以从这里检查整个代码 - github.com/nehabhardwaj01/docker-cron
            【解决方案18】:

            这是我基于docker-compose 的解决方案:

              cron:
                image: alpine:3.10
                command: crond -f -d 8
                depends_on:
                  - servicename
                volumes:
                  - './conf/cron:/etc/crontabs/root:z'
                restart: unless-stopped
            

            带有 cron 条目的行位于 ./conf/cron 文件中。

            注意:这不会运行不在alpine 图像上的命令。

            【讨论】:

              【解决方案19】:

              这条线帮助我运行了我预先安排的任务。

              ADD mycron/root /etc/cron.d/root
              
              RUN chmod 0644 /etc/cron.d/root
              
              RUN crontab /etc/cron.d/root
              
              RUN touch /var/log/cron.log
              
              CMD ( cron -f -l 8 & ) && apache2-foreground # <-- run cron
              

              --> 我的项目在里面运行:FROM php:7.2-apache

              【讨论】:

                【解决方案20】:

                您可以采取的另一条路线是Ofelia,这是一个高度可配置的任务运行器映像,允许 4 种执行模式。

                job-exec: this job is executed inside of a running container.
                job-run: runs a command inside of a new container, using a specific image.
                job-local: runs the command inside of the host running ofelia.
                job-service-run: runs the command inside a new "run-once" service, for running inside a swarm
                

                这里的优势是其他人已经为您完成了所有繁重的工作。超级方便,简单。

                它还有一个漂亮的官方吉祥物。

                【讨论】:

                  【解决方案21】:

                  不幸的是,上述答案都没有对我有用,尽管所有答案都会导致解决方案并最终导致我的解决方案,如果它对某人有帮助,这里是 sn-p。谢谢

                  这可以通过 bash 文件解决,由于 Docker 的分层架构,cron 服务不会通过 RUN/CMD/ENTRYPOINT 命令启动。

                  只需添加一个 bash 文件即可启动 cron 和其他服务(如果需要)

                  DockerFile

                  FROM gradle:6.5.1-jdk11 AS build
                  # apt
                  RUN apt-get update
                  RUN apt-get -y install cron
                  # Setup cron to run every minute to print (you can add/update your cron here)
                  RUN touch /var/log/cron-1.log
                  RUN (crontab -l ; echo "* * * * * echo testing cron.... >> /var/log/cron-1.log 2>&1") | crontab
                  # entrypoint.sh
                  RUN chmod +x entrypoint.sh
                  CMD ["bash","entrypoint.sh"]
                  

                  entrypoint.sh

                  #!/bin/sh
                  service cron start & tail -f /var/log/cron-2.log
                  

                  如果还需要任何其他服务与 cron 一起运行,则在同一命令中使用 &amp; 添加该服务,例如:/opt/wildfly/bin/standalone.sh &amp; service cron start &amp; tail -f /var/log/cron-2.log

                  一旦您进入 docker 容器,您可以看到 testing cron.... 将在文件中每分钟打印一次:/var/log/cron-1.log

                  【讨论】:

                  • 不应该使用tail -f /var/log/cron-1.log 而不是/var/log/cron-2.log,因为cron-1.log 是指向STDOUT/STDERR 的地方吗? (除非我遗漏了什么)
                  • 是的,正确,这是一个错字,/var/log/cron-1.log 应该在每个地方
                  【解决方案22】:

                  我决定使用busybox,因为它是最小的图像之一。

                  crond在前台执行(-f),日志发送到stderr(-d),我没有选择更改日志级别。 crontab 文件复制到默认路径:/var/spool/cron/crontabs

                  FROM busybox:1.33.1
                  
                  # Usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]
                  #
                  #   -f  Foreground
                  #   -b  Background (default)
                  #   -S  Log to syslog (default)
                  #   -l N    Set log level. Most verbose 0, default 8
                  #   -d N    Set log level, log to stderr
                  #   -L FILE Log to FILE
                  #   -c DIR  Cron dir. Default:/var/spool/cron/crontabs
                  
                  COPY crontab /var/spool/cron/crontabs/root
                  
                  CMD [ "crond", "-f", "-d" ]
                  

                  【讨论】:

                    【解决方案23】:

                    如果您想运行 crontab 以外的其他服务,您可能需要 除了你的之外,调用这个脚本来激活你的脚本 入口点:

                    addCronTabEntry.sh

                    (crontab -l 2>/dev/null; echo "*/1 * * * * <yourscript>") | crontab -
                    service cron start
                    

                    https://github.com/WolfgangFahl/pymediawikidocker

                    【讨论】:

                    • 在运行另一个主要服务时,我建议查看 dockerfile 中的 HEALTHCHECK 或 docker compose >= 2.1 以执行重复任务
                    【解决方案24】:

                    这个问题有很多答案,但有些很复杂,有些有一些缺点。我尝试解释问题并尝试提供解决方案。

                    cron-entrypoint.sh:

                    #!/bin/bash
                    
                    # copy machine environment variables to cron environment
                    printenv | cat - /etc/crontab > temp && mv temp /etc/crontab
                    
                    ## validate cron file
                    crontab /etc/crontab
                    
                    # cron service with SIGTERM support
                    service cron start
                    trap "service cron stop; exit" SIGINT SIGTERM
                    
                    # just dump your logs to std output
                    tail -f  \
                        /app/storage/logs/laravel.log \
                        /var/log/cron.log \
                        & wait $!
                    

                    问题解决

                    • 环境变量在 cron 环境中不可用(例如 env vars 或 kubernetes secrets)
                    • 当 crontab 文件无效时停止
                    • 当机器收到 SIGTERM 信号时优雅地停止 cron 作业

                    对于上下文,我在 Kubernetes 上使用以前的脚本和 Laravel 应用程序。

                    【讨论】:

                      猜你喜欢
                      • 2016-08-29
                      • 2018-12-27
                      相关资源
                      最近更新 更多