10

我有两个服务 A 和 B。

A 在启动时在 etcd 中设置一个值,比如它从环境文件中获取的公共 IP 地址:

ExecStartPost=/usr/bin/etcdctl set /A_ADDR $COREOS_PUBLIC_IPV4

B 在启动时需要该值以及它自己的 IP 地址。所以这样的事情会很好:

ExecStart=/usr/bin/docker run -e MY_ADDR=$COREOS_PUBLIC_IPV4 -e A_ADDR=$ETCD_A_ADDR mikedewar/B

但这显然是不可能的,因为 etcd 变量不会像这样的 systemd 环境变量出现。/usr/bin/bash -c 'run stuff'相反,我可以在 my中做一些事情,ExecStart但这很尴尬,尤其是当我需要 systemd 来扩展$COREOS_PUBLIC_IPV4和我的新 bash shell 来扩展时$(etcdctl get /A_ADDR)。它还散发着代码气味,让我觉得我错过了一些重要的东西。

有人能告诉我从 etcd 获取值到我的ExecStart声明中的“正确”方式吗?

- 更新

所以我准备好了

ExecStart=/usr/bin/bash -c 'source /etc/environment && /usr/bin/docker run -e A_ADDR=$(/usr/bin/etcdctl get /A_ADDR) -e MY_ADDR=$COREOS_PUBLIC_IPV4 mikedewar/B'

但这很丑陋。仍然不敢相信我没有错过任何东西..

4

3 回答 3

12

直到最近,我一直在为同样的事情而苦苦挣扎。在阅读了 CoreOS 和 systemd 的大部分文档之后,这里有一个稍微“更干净”的版本:

[Service]
EnvironmentFile=/etc/environment
ExecStart=/bin/sh -c '/usr/bin/docker run -e A_ADDR=$(/usr/bin/etcdctl get /A_ADDR) -e MY_ADDR=$COREOS_PUBLIC_IPV4 mikedewar/B'

此外,我采用了一种模式,其中我的服务依赖于 systemd 的“oneshot”服务,该服务将计算一些值并将其写入 /etc/environment。这允许您将更复杂的 shell 脚本保留在主服务单元之外,并将其放入它自己的 oneshot 服务单元中。

以下是 EnvironmentFile 的文档:http ://www.freedesktop.org/software/systemd/man/systemd.exec.html#EnvironmentFile=

最后,一个快速的问题:如果您在 ExecStart/Stop 命令中使用任何变量,则必须使用 shell 调用。systemd 在执行您提供的命令时不会调用 shell,因此不会扩展变量。

于 2014-10-08T05:47:11.910 回答
3

我目前正在使用这样的解决方法:

我创建了从特定 etcd 目录中提取数据的脚本

#! /bin/sh
for entry in `etcdctl ls /my_dir --recursive`  ; do
  echo ' -e '`grep -o '[^/]*$'  <<< ${entry}`=`etcdctl get ${entry}`
done

它的输出如下所示:

 -e DATABASE_URL=postgres://m:m@mi.cf.us-.rds.amazonaws.com:5432/m
 -e WEB_CONCURRENCY=4

所以最终我可以在我的初始化文件中以这种方式放置

/bin/sh -c '/usr/bin/docker run -p 9000:9000 $(/home/core/envs.sh) me/myapp -D FOREGROUND'

这不是最优雅的方式,我很想知道如何改进它,但是将 for 循环作为单线放置需要大量转义。

于 2015-03-18T14:37:26.280 回答
1

etcd您可以容器在启动时直接通过docker0网桥 IP读取,而不是传入值吗?这也将允许您对响应执行更复杂的逻辑,解析 JSON(如果您将其存储为 etcd 值等)。

于 2014-08-20T03:22:51.390 回答