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

我最近尝试从链接的 Docker 容器中运行 cron 作业,结果遇到了一个问题。我的主 docker 容器链接到 postgres 容器,它的端口号在容器创建时被 docker 设置为一个环境变量。这个环境变量没有设置在 ~/。在运行 cron 作业时可以加载的配置文件或任何其他源文件。然后如何从 cron 作业访问这些环境变量?

谢谢!

27762 次浏览

通过使用包装器 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

这是基于一个伟大的博客帖子的地方,但我失去了链接。

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

1)将 env 保存到 ENTRYPOINT 或 CMD 中的文件

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

2)然后像下面这样将 env 读入 cron 命令:

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

我也遇到了同样的问题。我有一个 docker 容器,它运行 cron 来定期执行一些 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 base 映像。

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


cron -f

此外,这个技巧甚至可以在 docker run命令期间设置环境变量。

为了避免任何可能破坏脚本的奇怪字符,根据 马克的回答的推理,在 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,以此类推。

我建议使用 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

可以运行以下命令

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

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

灵感来自@Kannan Kumarasamy 回答:

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

我不能肯定地说,pid1的进程是什么,它在操作系统的生命周期内是稳定的。但是因为它是第一个运行的进程,在一个容器中,我想我们可以理所当然地认为它是一个设置了所需的 env 变量的进程。除非一些 linux/docker 文档证明这是完全可以的,否则这些都是无稽之谈。

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

其他的解决方案也可以,但是如果你的环境变量中有任何特殊的字符,它们就会失败。

我已经找到了解决办法:

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