0

I have built the container using Dockerfile, in which I am using PHP-FPM Alpine Linux image. I need to run a cron job inside this container periodically. Once the application file is copied to the /var/www directory, created a user group and user as www, then switch to that user.  At the entry point script I am starting crond using the command crond -fbS -d 8 -L. Then I added the docker-entrypoint as PHP-FPM. I am trying to execute command

* * * * * php /var/www/artisan schedule:run >> /tmp/mycommand.log 2>> /var/tmp/cronjob.log

as the cronjob.  And there is a startup_script.sh as entrypoint. Below is my Dockerfile.

FROM php:7.3-fpm-alpine
RUN mkdir -p /etc/cron.d
WORKDIR /var/www

RUN apk update && apk add \
 rsyslog\
 openrc \
 busybox-suid \
 postgresql-dev \
 build-base \
 freetype-dev \
 libjpeg-turbo-dev \
 libpng-dev \
 libzip-dev \
 zip \
 jpegoptim optipng pngquant gifsicle \
 vim \
 unzip \
 git \
curl \
busybox-initscripts
RUN docker-php-ext-install pdo_pgsql pdo_mysql mbstring zip exif 
 pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype- 
 dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png- 
 dir=/usr/include/
RUN docker-php-ext-install gd



RUN addgroup -g 8877 -S www && \
 adduser -u 8877 -S www -G www

COPY /src/crontab /etc/crontabs/www
COPY /src/cron.allow /etc/cron.d
USER www

COPY --chown=www:www ./src /var/www


CMD ./start_script.sh

EXPOSE 9000

And below is my start_script.sh which will start the cronjob:

  #!/bin/sh

  # turn on bash's job control
  set -m
  # Start the primary process and put it in the background

  #php-fpm &
  #php artisan schedule:run

  echo "TEST" >> /var/tmp/cronjob.log
  crond -fbS -d 8 -L /var/tmp/cronjob.log &
  docker-php-entrypoint php-fpm
  # Start the helper process
  #php artisan migrate --force
  # the my_helper_process might need to know how to wait on the
  # primary process to start before it does its work and returns
  #su www
  #chown -R www:www /var/www/*

  # now we bring the primary process back into the foreground
  # and leave it there
  fg %1

Docker container is perfectly build and running, but when the cron tries to execute the cronjob in crontabs, it's getting the error "root:permission denied." along with "this group can't permit the operation."

Is it possible to run cron as a non-root user?  How can I do it?

3
  • Is it possible to run cron as non root user?
    – astrosixer
    Mar 30 at 20:54
  • 2
    IMO all your idea is fishy, it contradicts approach of containerizing each app individually. What you basically want is to have multiple processes inside one container without any init for it. Strange. Anyway, I doubt busybox crond (fork of dcron) works under ordinary user, see git.busybox.net/busybox/tree/miscutils/crond.c#n3 (it does not in my local test on Alpine). IMO you have two choices, either split your fat container into two and create an "orchestration" (you probably do not run k8s, so check HashiCorp nomad for example), or go with fat container with systemd.
    – Jiri B
    Mar 30 at 22:13
  • BTW if you would have an external scheduler, then you can run your artisan via docker exec.
    – Jiri B
    Mar 30 at 22:30
1

Two things worked for me:

a) The crontab file for www in /etc/crontabs must be owned by root. Then this CMD runs both cron and PHP:

CMD crond -l 0 && php-fpm

The drawback is that I don't get cron output in docker logs.

b) Using supervisor to run multiple services like cron, php-fpm (and NGINX in my case) in a single container (this helped a lot):

Here's a supervisord.conf file that might work for you, too:

[supervisord]
nodaemon=true

[program:php]
command=php-fpm -F
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/2
stderr_logfile_maxbytes=0

[program:cron]
command=crond -l 0 -f
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
stderr_logfile=/dev/fd/2
stderr_logfile_maxbytes=0

Dockerfile extract:

RUN apk --update upgrade && apk update && apk add supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

This has the benefit that supervisor will take care of both services always running (or the container exiting) and I will also get both services' output in docker logs.

2
  • Are u running it as non root user?
    – astrosixer
    Jul 23 at 14:36
  • @astrosixer Cron runs as root, but the jobs are run as the respective user as determined by the filename in /etc/crontabs - www in your case. All files there must be owned by root though.
    – Ronino
    Jul 25 at 11:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.