Solución de problemas · Docker

¿Cron no funciona en tu contenedor Docker? Soluciones que realmente funcionan

Por qué cron falla silenciosamente dentro de un contenedor Docker — PID 1, variables de entorno ausentes, sin servidor de correo — y cómo resolver cada problema.

Ejecutar cron dentro de un contenedor confunde a mucha gente porque un contenedor no es una VM normal. Aquí están las causas más comunes, con las soluciones primero.

1. Cron no está corriendo como PID 1

Un contenedor ejecuta un único proceso en primer plano. Si tu CMD arranca tu app, cron nunca se inicia — y si tu CMD es cron, puede que termine de inmediato porque intenta daemonizarse. Ejecútalo en primer plano:

# Base Debian/Ubuntu
CMD ["cron", "-f"]

Para ejecutar cron y tu app, usa un supervisor pequeño (supervisord, s6) o un gestor de procesos — no dependas del backgrounding en un CMD de shell.

2. Las variables de entorno desaparecen bajo cron

Este es el problema más importante. Docker inyecta las variables de entorno en PID 1, pero cron inicia los jobs con un entorno limpio, así que tu DATABASE_URL y las claves de API desaparecen. Vuelca el entorno del contenedor a un archivo al arrancar y cárgalo en el job:

CMD printenv | sed 's/^\(.*\)$/export \1/' > /etc/container.env && cron -f
# en el crontab
0 * * * * . /etc/container.env && /app/run.sh

3. El crontab necesita el formato correcto y una línea en blanco al final

Una línea de crontab de sistema necesita una columna de usuario, y el archivo debe terminar con una nueva línea o el último job será ignorado:

# /etc/cron.d/app  — observa el campo de usuario "root"
0 2 * * * root /app/run.sh >> /var/log/cron.log 2>&1
COPY app-cron /etc/cron.d/app
RUN chmod 0644 /etc/cron.d/app && crontab /etc/cron.d/app

4. “Cron no puede enviar correo” — no hay servidor de correo

Un clásico: el crontab de un contenedor intenta enviar la salida por correo, pero no hay ningún MTA, así que los jobs parecen “fallar”. No dependas del correo local. Redirige la salida a stdout para que aparezca en docker logs:

0 2 * * * root /app/run.sh > /proc/1/fd/1 2>/proc/1/fd/2

5. Consulta la salida

docker logs -f <container>
docker exec -it <container> sh -c "crontab -l"

El problema más profundo: los contenedores se reinician y cron lo olvida

Un redespliegue, un OOM kill, un crash loop — cualquiera de estos puede detener tu cron dentro del contenedor, y nadie te avisa. Monitorizar desde fuera del contenedor es la única señal fiable.

Haz que el job haga ping a una URL de heartbeat cuando tenga éxito. Si el contenedor está caído o el job deja de ejecutarse, el ping no llega y recibes una alerta:

HEALTHCHECK --interval=5m --timeout=10s \
  CMD curl -fsS https://ping.steadycron.com/<tu-ping-token> || exit 1