我有两项服务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变量并不像那样存在系统环境变量。相反,我可以在我的/usr/bin/bash -c 'run stuff'
中执行某种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'
但它非常丑陋。仍然无法相信我没有错过任何东西..
答案 0 :(得分:12)
[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'
此外,我采用了一种模式,我的服务依赖于系统化的&one;'将计算某些值并将其写入/ etc / environment的服务。这允许您将更复杂的shell脚本保留在主服务单元之外,并将其放入其自己的onehot服务单元。
以下是EnvironmentFile的文档:http://www.freedesktop.org/software/systemd/man/systemd.exec.html#EnvironmentFile=
最后,快速了解一下:如果在ExecStart / Stop命令中使用任何变量,则必须使用shell调用。执行您提供的命令时,systemd不执行shell调用,因此不会扩展变量。
答案 1 :(得分: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
所以最后我可以在我的init文件中以这种方式放置
/bin/sh -c '/usr/bin/docker run -p 9000:9000 $(/home/core/envs.sh) me/myapp -D FOREGROUND'
这不是最优雅的方式,而且我很想知道如何改进它,但是将它作为单行代码放置需要大量的逃避。
答案 2 :(得分:1)
您可以在etcd
桥接IP上通过docker0
直接读取容器,而不是传递值吗?这也将允许您在响应上执行更复杂的逻辑,如果您将其存储为etcd值,则解析JSON等。