Running cron python jobs within docker

后端 未结 9 1404
挽巷
挽巷 2020-12-04 08:59

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 pyt         


        
相关标签:
9条回答
  • 2020-12-04 09:58

    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.

    0 讨论(0)
  • 2020-12-04 09:59

    Several issues that I faced while trying to get a cron job running in a docker container were:

    1. time in the docker container is in UTC not local time;
    2. the docker environment is not passed to cron;
    3. as Thomas noted, cron logging leaves a lot to be desired and accessing it through docker requires a docker-based solution.

    There are cron-specific issues and are docker-specific issues in the list, but in any case they have to be addressed to get cron working.

    To that end, my current working solution to the problem posed in the question is as follows:

    Create a docker volume to which all scripts running under cron will write:

    # Dockerfile for test-logs
    
    # BUILD-USING:        docker build -t test-logs .
    # RUN-USING:          docker run  -d -v /t-logs --name t-logs test-logs
    # INSPECT-USING:      docker run -t -i  --volumes-from t-logs ubuntu:latest /bin/bash
    
    FROM stackbrew/busybox:latest
    
    # Create logs volume
    VOLUME /var/log
    
    CMD  ["true"]
    

    The script that will run under cron is test.py:

    #!/usr/bin/env python
    
    # python script which needs an environment variable and runs as a cron job
    import datetime
    import os
    
    test_environ = os.environ["TEST_ENV"]
    print "Cron job has run at %s with environment variable '%s'" %(datetime.datetime.now(), test_environ)
    

    In order to pass the environment variable to the script that I want to run under cron, follow Thomas' suggestion and put a crontab fragment for each script (or group of scripts) that has need of a docker environment variable in /etc/cron.d with a placeholder XXXXXXX which must be set.

    # placed in /etc/cron.d 
    # TEST_ENV is an docker environment variable that the script test.py need
    
    TEST_ENV=XXXXXXX
    #
    * * * * * root python /test.py >> /var/log/test.log
    

    Instead of calling cron directly, wrap cron in a python script that does does things: 1. reads the environment variable from the docker environment variable and sets the environment variable in a crontab fragment.

    #!/usr/bin/env python
    
    # run-cron.py
    # sets environment variable crontab fragments and runs cron
    
    import os
    from subprocess import call
    import fileinput
    
    # read docker environment variables and set them in the appropriate crontab fragment
    environment_variable = os.environ["TEST_ENV"]
    
    for line in fileinput.input("/etc/cron.d/cron-python",inplace=1):
        print line.replace("XXXXXXX", environment_variable)
    
    args = ["cron","-f", "-L 15"]
    call(args)
    

    The Dockerfile that for the container in which the cron jobs run is as follows:

    # BUILD-USING:        docker build -t test-cron .
    # RUN-USING docker run --detach=true --volumes-from t-logs --name t-cron test-cron
    
    FROM debian:wheezy
    #
    # Set correct environment variables.
    ENV HOME /root
    ENV TEST_ENV test-value
    
    RUN apt-get update && apt-get install -y software-properties-common python-software-properties && apt-get update
    
    # Install Python Setuptools
    RUN apt-get install -y python cron
    
    RUN apt-get purge -y python-software-properties software-properties-common && apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
    
    ADD cron-python /etc/cron.d/
    ADD test.py /
    ADD run-cron.py /
    
    RUN chmod a+x test.py run-cron.py
    
    # Set the time zone to the local time zone
    RUN echo "America/New_York" > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata
    
    CMD ["/run-cron.py"]
    

    Finally, create the containers and run them:

    1. Create the log volume (test-logs) container: docker build -t test-logs .
    2. Run log volume: docker run -d -v /t-logs --name t-logs test-logs
    3. Create the cron container: docker build -t test-cron .
    4. Run the cron container: docker run --detach=true --volumes-from t-logs --name t-cron test-cron
    5. To inspect the log files of the scripts running under cron: docker run -t -i --volumes-from t-logs ubuntu:latest /bin/bash. The log files are in /var/log.
    0 讨论(0)
  • 2020-12-04 09: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

    0 讨论(0)
提交回复
热议问题