Running Crons in your Docker Container

Monday, 05 March 2018

I'm currently build an app using laravel, that I am only going to run locally using Docker, however, I do need to run the scheduler, so I started looking into how to run crons within the docker container.

I came across a few different ways of doing, from people who clearly know more about Docker than I do, however, I am going to share the way that I was able to get it to work.

Below is what you need (at a minimum) to get the cron service running within your docker container.

FROM php:7.1-fpm

WORKDIR /var/www

RUN apt-get update
RUN apt-get install -y \
        cron

# Create the log file
RUN touch /var/log/schedule.log
RUN chmod 0777 /var/log/schedule.log

# Add crontab file in the cron directory
ADD scheduler /etc/cron.d/scheduler

# Run the cron
RUN crontab /etc/cron.d/scheduler
CMD ["cron", "-f"]

Lets break this down, firstly we need to pull in cron using apt-get so that we have what we need to run the crons.

Next, and this is optional, we create a file for the cron logs to be stored into.

We then add the cron to the crontab, by storing the cron in a file called scheduler (in the same folder as your docker file), which just contains a standard crontab command.

* * * * * su -c 'php /var/www/artisan schedule:run >> /var/log/schedule.log 2>&1'

These commands, then add it to the crontab in the docker:

ADD scheduler /etc/cron.d/scheduler
RUN crontab /etc/cron.d/scheduler

And then all we need to do is run the cron command with CMD ["cron", "-f"].

Now, I do need to add one issue I ran into with this. I first tried adding this into my php container, and allow it does work, and the crons where running, for some reason, that I couldn't figure out, it prevented the app it self from loading in the browser.

To get around this, I simply copied by php docker file, and created a cron docker file. So my docker-compose.yml file looks like this:

version: '2'
services:
  php:
    build: ./docker/php
    volumes:
     - .:/var/www
    links:
      - mysql
  cron:
    build: ./docker/cron
    volumes:
     - .:/var/www
    links:
      - mysql
  redis:
    build: ./docker/redis
    volumes:
     - redisdata:/data
    links:
      - php
  nginx:
    build: ./docker/nginx
    ports:
     - "8008:80"
    volumes:
     - .:/var/www
    links:
     - php
    depends_on:
     - php
  mysql:
    ports:
     - "33060:3306"
    image: 'mysql:5.6'
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_DATABASE=tasks
    volumes:
     - mysqldata:/var/lib/mysql
volumes:
  mysqldata:
    driver: "local"
  redisdata:
    driver: "local"