Enable crond in an Alpine container
Asked Answered
F

5

9

Context

I'm trying to schedule some ingestion jobs in an Alpine container. It took me a while to understand why my cron jobs did not start: crond doesn't seems to be running

rc-service -l | grep crond 

According to Alpine's documentation, crond must first be started with openrc (i.e. some kind of systemctl). Here is the Dockerfile

FROM python:3.7-alpine

# set work directory
WORKDIR /usr/src/collector

RUN apk update \
    && apk add curl openrc

# ======>>>> HERE !!!!! 
RUN rc-service crond start && rc-update add crond

# install dependencies
RUN pip install --upgrade pip
RUN pip install pipenv
COPY ./Pipfile /usr/src/collector/Pipfile
RUN pipenv install --skip-lock --system --dev

# copy entrypoint.sh
COPY ./entrypoint.sh /usr/src/collector/entrypoint.sh

# copy project
COPY . /usr/src/collector/

# run entrypoint.sh
ENTRYPOINT ["/usr/src/collector/entrypoint.sh"]

entrypoint.sh merely appends the jobs at the end of /etc/crontabs/root

Problem

I'm getting the following error:

 * rc-service: service `crond' does not exist
ERROR: Service 'collector' failed to build: The command '/bin/sh -c rc-service crond start && rc-update add crond' returned a non-zero code: 1

Things are starting to feel a bit circular. How can rc-service not recognizing a service while, in the same time:

  • sh seems to know the name crond,

  • there was a /etc/crontabs/root

What am I missing?

Freyah answered 5/7, 2019 at 10:58 Comment(5)
Check out #56804312, where I outlined how to build a simple CRON container and have it run commands in other containers in a docker-compose environment.Rattletrap
Try to replace RUN rc-service crond start && rc-update add crond with RUN crond Sukiyaki
@Rattletrap interesting post but it does not solve my issue. I tried to add RUN crond or CMD crond -f at the end of the docker file but it does not seem to change a thing: no cron jobs and crond is still missing from the list of rc-services. I think that this is th issueFreyah
Ther's a basic difference in both approaches. You try to make cron run in the same container as your application, I believe. That just causes drama, every time ;-). My approach, and the one that I have seen used by many others, is to run it in a separate container.Rattletrap
I am still puzzled. Why is that so? This container does not contain the DB nor the application but merely simple injestion jobs to populate the DB. This container is already simple enough without spliting it. I'll figure it out and keep you postedFreyah
D
3

Some Alpine Docker containers are missing the busybox-initscripts package. Just append that to the end of your apk add command, and crond should run as a service.

You might also need to remove the following line from your Dockerfile since it seems as if busybox-initscripts runs crond as a service immediately after installation:

RUN rc-service crond start && rc-update add crond
Dabber answered 27/10, 2019 at 9:41 Comment(1)
The busybox-initscripts module doesn't exist anymore. It was split into other packages, as discussed hereSeagoing
B
3
FROM alpine:latest

RUN touch crontab.tmp \
    && echo '* * * * * echo "123"' > crontab.tmp \
    && crontab crontab.tmp \
    && rm -rf crontab.tmp

CMD ["/usr/sbin/crond", "-f", "-d", "0"]

ref: https://gist.github.com/mhubig/a01276e17496e9fd6648cf426d9ceeec

Barbabra answered 26/12, 2022 at 16:42 Comment(2)
I wasn't sure if I liked how you provision the initial crontab here but this is still the best answer of all. The cron service should run as a foreground service in the container. If it needs access to either file system or network of other services it should use volumes or shared networks. Everything else is non idiomatic to containers and working against the basics.Autoradiograph
yeah, if anyone ever asks me about cronjobs in docker containers I answer: Don't even try :D I ended up writing a while-true loop in bash to check the time every second and execute some script when the time is fitting (p.-) Here is another great article: jhooq.com/docker-run-cron-job-inside-containerBarbabra
G
0

I was able to fix this by adding the crond command to the docker-entrypoint.sh, prior to the actual script commands.

e.g.:

#!/bin/sh
set -e

crond &

...(rest of the original script)

This way the crond is reloaded as a detached process.

So all the steps needed was to

  • Find and copy the entrypoint.sh to the build folder. I did this from a running container:
docker cp <running container name>:<path to script>/entrypoint.sh <path to Dockerfile folder>/entrypoint.sh
  • Modify the entrypoint.sh as stated above
  • Include the entrypoint.sh again in the Dockerfile used for building the custom image. Dockerfile example:
...
COPY docker-entrypoint.sh <path to script>/entrypoint.sh
RUN chmod +x <path to script>/entrypoint.sh
...
  • And then just build and use the new custom image:
docker build -t <registry if used>/<image name>:<tag> .
Gloaming answered 27/1, 2021 at 8:50 Comment(0)
R
0

Have faced the issue either. My solution for containers is to execute crond inside of screen

# apk add screen --no-cache
# screen -dmS crond crond -f -l 0
Romany answered 30/3, 2021 at 17:36 Comment(0)
S
-2

Run this one: apk add openrc --no-cache

Shoshana answered 6/12, 2019 at 7:58 Comment(3)
Please give some explanation how will it helpMotta
openrc doesn't work in a container. it doesn't like not being pid 1Nicotine
We do not have the full context here but for sure container processes in regular Docker workflows have the ability to run as process 1. It's actually the default.Autoradiograph

© 2022 - 2024 — McMap. All rights reserved.