如何从 cron 作业访问 Docker 集环境变量



>我最近尝试从链接的 docker 容器中运行 cron 作业并遇到了问题。我的主 docker 容器链接到 postgres 容器,其端口号在创建容器时由 docker 设置为环境变量。此环境变量未在 ~/.profile 或运行 cron 作业时可以加载的任何其他源文件中设置。然后,如何从我的 cron 作业访问这些环境变量?

谢谢!

我遇到了同样的问题。我有一个运行 cron 的 docker 容器来定期执行一些 shell 脚本。我也很难找出为什么当我在容器内手动执行脚本时我的脚本会运行良好。我尝试了创建首先运行以设置环境的 shell 脚本的所有技巧,但它们从未对我有用(很可能我做错了什么)。但我继续寻找并发现它确实有效。

  1. 为 cron 容器设置起始点或入口点 shell 脚本
  2. 将此作为执行printenv | grep -v "no_proxy" >> /etc/environment的第一行

这里的诀窍是/etc/environment文件。当构建容器时,该文件是空的,我认为是故意的。我在 cron(8) 的手册页中找到了对该文件的引用。在查看了所有版本的 cron 之后,它们都躲避到一个 /etc/? 文件中,您可以使用该文件将环境变量提供给子进程。

另外,请注意,我创建了 docker 容器以在前台运行 cron,cron -f .这帮助我避免了运行tail以保持容器正常运行的其他技巧。

这是我 entrypoint.sh 文件供参考,我的容器是一个 debian:jessie 基础映像。

printenv | grep -v "no_proxy" >> /etc/environment
cron -f

此外,此技巧甚至适用于在命令期间设置的环境变量docker run

我建议使用declare导出您的环境并避免逃避问题。可以在CMD或ENTRYPOINT中使用,也可以直接在包装脚本中使用,该脚本可能由其中一个调用:

declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env

Grep -v 负责过滤掉只读变量。

稍后,您可以像这样轻松加载此环境:

SHELL=/bin/bash
BASH_ENV=/container.env
* * * * * root /test-cron.sh

可以使用包装 shell 脚本运行 cron 守护程序,将系统环境变量附加到 crontab 文件的顶部。下面的例子来自 CentOs 7,

在 Dockerfile 中

COPY my_cron /tmp/my_cron
COPY bin/run-crond.sh run-crond.sh
RUN chmod -v +x /run-crond.sh
CMD ["/run-crond.sh"]

run_cron.sh:

#!/bin/bash
# prepend application environment variables to crontab
env | egrep '^MY_VAR' | cat - /tmp/my_cron > /etc/cron.d/my_cron
# Run cron deamon
# -m off : sending mail is off 
# tail makes the output to cron.log viewable with the $(docker logs container_id) command
/usr/sbin/crond -m off  && tail -f /var/log/cron.log

这是基于某处的一篇很棒的博客文章,但我丢失了链接。

灵感来自@Kannan Kumarasamy的回答:

  for variable_value in $(cat /proc/1/environ | sed 's/x00/n/g'); do
    export $variable_value
  done

我不能肯定地说,pid1 是什么进程,以及它在操作系统的生命周期内是稳定的。 但由于它是第一个要运行的进程,在容器内,我想我们可以理所当然地认为它是一个具有所需 env vars 集的进程。 用 pich of salt 来考虑所有这些,除非一些 Linux/docker 文档证明这是完全可以的。

您可以运行以下命令

. <(xargs -0 bash -c 'printf "export %qn" "$@"' -- < /proc/1/environ)

当您拥有具有特殊字符(如 ' " =)的环境变量时,这非常有效

环境已设置,但对 cron 作业不可用。 要解决这个问题,你可以做这两件简单的事情

1) 将环境保存到入口点或 CMD 中的文件中

CMD env > /tmp/.MyApp.env && /bin/MyApp

2)然后将该环境读入您的cron命令中,如下所示:

0 5 * * * . /tmp/.MyApp.env; /bin/MyApp

您应该在运行 cronjobs 之前导出环境变量。

其他解决方案很好,但是当环境变量中存在任何特殊字符时,它们将失败。

我找到了解决方案:

eval $(printenv | awk -F= '{print "export " """$1""""=""""$2""" }' >> /etc/profile)

为了逃避任何可能破坏你的脚本的奇怪字符,并根据马克回答的推理,在你的entrypoint.sh中添加这一行:

env | sed -r "s/'/\'/gm" | sed -r "s/^([^=]+=)(.*)$/1'2'/gm"  > /etc/environment

这样,如果你有任何像 affinity:container==My container's friend 这样的变量,它将被转换为 affinity:container='=My container's friend ,依此类推。

最新更新