如何在 cron 任务中访问 Docker 容器的环境变量?
cron 守护进程不读取容器启动时的环境变量,常见解法:启动脚本把 env 导出到文件(env > /etc/environment)让 cron 源它,或用 docker run -e 显式传入。本文给出可靠做法。
问题本质:容器启动时通过 docker run -e 传入的环境变量只对 PID 1 进程生效;容器内另起的 cron 守护进程不继承这些变量**,所以 cron 任务里取不到。最常用解法:容器启动脚本把当前环境导出到文件(printenv > /etc/environment),cron 任务执行前先 source 它。**
症状
docker run -e DB_HOST=mysql myapp
容器里 echo $DB_HOST 有值,但 cron 任务里同样的变量是空的——cron 以最小环境启动任务。
解法一:导出环境到文件(推荐)
容器入口脚本(entrypoint)里加一行:
#!/bin/bash
printenv | grep -v 'no_proxy' > /etc/environment
cron -f # 或 exec 主进程,cron 后台
cron 任务里先加载:
* * * * * . /etc/environment; /app/backup.sh >> /var/log/backup.log 2>&1
解法二:crontab 里写死变量
直接在 crontab 顶部声明:
DB_HOST=mysql
DB_PASS=secret
0 3 * * * /app/backup.sh
适合变量少且固定的场景;变量来自编排系统时不适用。
解法三:任务命令里显式注入
0 3 * * * /usr/bin/env DB_HOST=mysql /app/backup.sh
解法四:让 PID 1 调度,绕开 cron
容器最佳实践倾向单进程。定时任务改用:
- K8s CronJob:每个任务独立 Pod,环境变量天然注入
- 应用内调度器:APScheduler(Python)、node-cron 等,进程内调度直接用进程环境
- 宿主机 cron 调 docker exec:
docker exec myapp /app/backup.sh,exec 会带上容器主进程的环境
观测云对照
定时任务跑没跑、成没成,要有监控。 无论哪种方案,任务日志集中采集到观测云后,用监控器对"预期时间点未产生日志/出现错误关键字"做告警,避免 cron 静默失效。
常见问题(FAQ)
Q:为什么 docker exec 里能拿到变量而 cron 不行?
A:docker exec 会继承容器主进程的环境;cron 是独立守护进程,环境自己造。
Q:/etc/profile.d/ 里的脚本 cron 会读吗?
A:不会。cron 不跑登录 shell,profile 系列文件都不生效。
Q:变量保密怎么处理的?
A:不要写进 crontab 明文;用 K8s Secret + CronJob,或 entrypoint 从密管系统拉取后写 /etc/environment(注意文件权限 600)。