Cómo ejecutar cron jobs en un contenedor de Docker
Actualizada el 16 de octubre de 2026
Ejecutar cron dentro de Docker requiere ajustar cómo se inicia el proceso, dónde se guarda la salida y qué entorno reciben los jobs. Esta guía cubre esos pasos en imágenes basadas en Debian, Ubuntu y Alpine.
Un ejemplo completo en Debian o Ubuntu
Cuatro archivos en un directorio: el Dockerfile, el crontab, un entrypoint.sh que inicia cron, y el job, backup.sh.
Dockerfile:
FROM debian:12-slim
RUN apt-get update && apt-get install -y --no-install-recommends cron tzdata \
&& rm -rf /var/lib/apt/lists/*
COPY backup.sh entrypoint.sh /app/
COPY crontab /etc/cron.d/app
RUN chmod 0755 /app/backup.sh /app/entrypoint.sh && chmod 0644 /etc/cron.d/app
ENTRYPOINT ["/app/entrypoint.sh"]
crontab, con una línea temporal que se ejecuta cada minuto para comprobar la instalación:
# Temporal, para comprobar la instalación: cada minuto.
* * * * * root . /app/env.sh; date > /proc/1/fd/1 2>&1
0 3 * * * root . /app/env.sh; /app/backup.sh > /proc/1/fd/1 2>&1
entrypoint.sh:
#!/bin/sh
# Las variables del contenedor, para los jobs: cron los inicia sin ellas.
export -p > /app/env.sh
chmod 600 /app/env.sh
exec cron -f
backup.sh, tu job:
#!/bin/sh
echo "Respaldo iniciado: $(date)"
Constrúyela, iníciala y mira su salida:
docker build -t cron-app .
docker run -d --name cron-app -e TZ=America/Santiago cron-app
docker logs -f cron-app
Antes de un minuto, docker logs muestra una fecha en la zona horaria que pasaste en TZ. Después, quita la línea temporal del crontab y vuelve a construir la imagen.
Lo mismo en Alpine
Alpine ya trae el crond de BusyBox. Su crontab es /etc/crontabs/root, y sus líneas no llevan usuario después del horario. Pasa las variables del contenedor a los jobs, así que no necesita entrypoint.sh:
FROM alpine:3.20
RUN apk add --no-cache tzdata
COPY backup.sh /app/
COPY crontab /etc/crontabs/root
RUN chmod 0755 /app/backup.sh
CMD ["crond", "-f", "-l", "2"]
# Temporal, para comprobar la instalación: cada minuto.
* * * * * date > /proc/1/fd/1 2>&1
0 3 * * * /app/backup.sh > /proc/1/fd/1 2>&1
Por qué cada parte
-
cron -fmantiene cron en primer plano. Sin-f, cron pasa a segundo plano, el proceso principal del contenedor termina y el contenedor se detiene. -
El archivo de
/etc/cron.d/no puede tener permiso de escritura para el grupo ni para otros: con0664, cron lo ignora, y en un contenedor no hay syslog que lo avise. Sus líneas llevan el usuario (root) después del horario, su nombre no puede tener puntos (app, noapp.cron) y tiene que terminar con un salto de línea. -
> /proc/1/fd/1 2>&1envía la salida del job a la del contenedor, quedocker logsmuestra. El cron de Debian y Ubuntu solo registra en syslog, y no envía la salida de los jobs a ningún lugar que puedas ver. Funciona con los jobs de root: los jobs de otro usuario no pueden escribir en la salida del proceso 1, así que dales un archivo. -
env.shles da a los jobs las variables del contenedor. El cron de Debian y Ubuntu inicia cada job casi sin variables:HOME,LOGNAME,SHELLy unPATHde/usr/bin:/bin. Lo que pasas condocker run -e,env_fileo Kubernetes no está, así que un job que necesitaDATABASE_URLo una clave de API falla. El archivo tiene los secretos del contenedor, por eso solo root puede leerlo. -
tzdatayTZdefinen la zona horaria. Los contenedores normalmente están en UTC. ConTZ, cron sigue el horario en esa zona; en Debian y Ubuntu los jobs solo recibenTZa través deenv.sh, así que sin él undateen un job muestra UTC.
Si los jobs siguen sin ejecutarse
-
¿Sigue activo el contenedor?
docker ps. Si se detiene, revisacron -f. -
¿Es cron el proceso principal?
docker top cron-app. -
Escapa los
%del crontab:date +\%F. Un%sin\termina el comando, y el job no se ejecuta como está escrito. - El script tiene que ser ejecutable, con saltos de línea de Unix. El resto de las causas comunes están en por qué tu cron job no se ejecuta.
¿Necesitas cron dentro del contenedor?
A veces otra opción es más simple:
-
El cron del host, ejecutando el job en el contenedor con
docker exec. El cron del host decide cuándo, en la zona horaria del host. El comando se ejecuta dentro del contenedor, con el entorno del contenedor. Su salida va adonde la redirijas en el host:0 3 * * * docker exec cron-app /app/backup.sh >> "$HOME/backup.log" 2>&1 -
Un
CronJobde Kubernetes, que inicia un pod para cada ejecución. El recursoCronJobtiene su propia zona horaria enspec.timeZone, desde Kubernetes 1.27:spec: schedule: "0 3 * * *" timeZone: "America/Santiago" -
supercronic, un cron hecho para contenedores, que registra en la salida y conserva el entorno.
Entérate la próxima vez que no se ejecute
Un contenedor que se reinició, una variable que faltó o una zona horaria mal puesta pueden detener un job, y estos problemas pueden pasar inadvertidos hasta que alguien revisa los logs. El monitoreo te avisa cuando una ejecución no empieza, tarda demasiado o falla. Si usas la línea de CronDrive en /etc/cron.d/, agrega el usuario después del horario, e instala curl en la imagen.