Running cron python jobs within docker

2019-01-13 01:19发布

I would like to run a python cron job inside of a docker container in detached mode. My set-up is below:

My python script is test.py

  #!/usr/bin/env python
  import datetime
  print "Cron job has run at %s" %datetime.datetime.now()

My cron file is my-crontab

* * * * * /test.py > /dev/console

and my Dockerfile is

FROM ubuntu:latest
RUN apt-get update && apt-get install -y software-properties-common python-software-properties && apt-get update

RUN apt-get install -y python cron
ADD my-crontab /
ADD test.py /
RUN chmod a+x test.py

RUN crontab /my-crontab
ENTRYPOINT cron -f

What are the potential problems with this approach? Are there other approaches and what are their pros and cons?

8条回答
走好不送
2楼-- · 2019-01-13 01:57

Single Container Method

You may run crond within the same container that is doing something closely related using a base image that handles PID 0 well, like phusion/baseimage.

Specialized Container Method

May be cleaner would be to have another Container linked to it that just runs crond. For example:

Dockerfile

 FROM busybox
 ADD crontab /var/spool/cron/crontabs/www-data
 CMD crond -f

crontab

 * * * * * echo $USER

Then run:

 $ docker build -t cron .
 $ docker run --rm --link something cron

Note: In this case it'll run the job as www-data. Cannot just mount the crontab file as volume because it needs to be owned by root with only write access for root, else crond will run nothing. Also you'll have to run crond as root.

查看更多
神经病院院长
3楼-- · 2019-01-13 01:59

Don't mix crond and your base image. Prefer to use a native solution for your language (schedule or crython as said by Anton), or decouple it. By decoupling it I mean, keep things separated, so you don't have to maintain an image just to be the fusion between python and crond.

You can use Tasker, a task runner that has cron (a scheduler) support, to solve it, if you want keep things decoupled.

Here an docker-compose.yml file, that will run some tasks for you

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: helloFromPython
                tasks:
                    docker:
                        - name: helloFromPython
                          image: python:3-slim
                          script:
                              - python -c 'print("Hello world from python")'

Just run docker-compose up, and see it working. Here is the Tasker repo with the full documentation:

http://github.com/opsxcq/tasker

查看更多
放荡不羁爱自由
4楼-- · 2019-01-13 02:00

Another possibility is to use Crython. Crython allows you to regularly schedule a python function from within a single python script / process. It even understands cron syntax:

@crython.job(expr='0 0 0 * * 0 *')
def job():
    print "Hello world"

Using crython avoids the various headaches of running crond inside a docker container - your job is now a single process that wakes up when it needs to, which fits better into the docker execution model. But it has the downside of putting the scheduling inside your program, which isn't always desirable. Still, it might be handy in some use cases.

查看更多
淡お忘
5楼-- · 2019-01-13 02:08

We are using below solution. It supports both docker logs functionality and ability to hang the cron process in the container on PID 1 (if you use tail -f workarounds provided above - if cron crashes, docker will not follow restart policy):

cron.sh:

#!/usr/bin/env bash

printenv | cat - /etc/cron.d/cron-jobs > ~/crontab.tmp \
    && mv ~/crontab.tmp /etc/cron.d/cron-jobs

chmod 644 /etc/cron.d/cron-jobs

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

cron -f

Dockerfile:

RUN apt-get install --no-install-recommends -y -q cron 

ADD cron.sh /usr/bin/cron.sh
RUN chmod +x /usr/bin/cron.sh

ADD ./crontab /etc/cron.d/cron-jobs
RUN chmod 0644 /etc/cron.d/cron-jobs

RUN touch /var/log/cron.log

ENTRYPOINT ["/bin/sh", "/usr/bin/cron.sh"]

crontab:

* * * * * root <cmd> >> /var/log/cron.log 2>&1

And please don't forget to add the creepy new line in your crontab

查看更多
地球回转人心会变
6楼-- · 2019-01-13 02:13

Here is a complement on rosksw answer.

There is no need to do some string replacement in the crontab file in order to pass environment variables to the cron jobs.

It is simpler to store the environment variables in a file when running the contrainer, then load them from this file at each cron execution. I found the tip here.

In the dockerfile:

CMD mkdir -p /data/log && env > /root/env.txt && crond -n

In the crontab file:

* * * * * root env - `cat /root/env.txt` my-script.sh
查看更多
唯我独甜
7楼-- · 2019-01-13 02:17

Here's an alternative solution.

in Dockerfile

ADD docker/cron/my-cron /etc/cron.d/my-cron
RUN chmod 0644 /etc/cron.d/my-cron

ADD docker/cron/entrypoint.sh /etc/entrypoint.sh

ENTRYPOINT ["/bin/sh", "/etc/entrypoint.sh"]

in entrypoint.sh

 #!/usr/bin/env bash
  printenv | cat - /etc/cron.d/my-cron > ~/my-cron.tmp \
    && mv ~/my-cron.tmp /etc/cron.d/my-cron

cron -f
查看更多
登录 后发表回答