如何在 coreOS 上将 etcd 值添加到我的 systemd 服务中?
Posted
技术标签:
【中文标题】如何在 coreOS 上将 etcd 值添加到我的 systemd 服务中?【英文标题】:how do I get etcd values into my systemd service on coreOS? 【发布时间】:2014-10-13 07:21:00 【问题描述】:我有两个服务 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 环境变量出现。相反,我可以在我的ExecStart
中执行某种/usr/bin/bash -c 'run stuff'
,但这很尴尬,特别是因为我需要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'
但它很丑陋。仍然不敢相信我没有错过任何东西..
【问题讨论】:
这有点用——但是当你的 docker 容器跌倒时 systemd 服务有时并没有意识到这一点。 【参考方案1】:直到最近,我一直在为同样的事情苦苦挣扎。在阅读了 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,因此不会扩展变量。
【讨论】:
检查 PassEnvironment= - 这有助于我在 docker systemd 设置中传递环境变量。【参考方案2】:我目前正在使用这样的解决方法:
我创建了从特定 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 循环作为单线放置需要大量转义。
【讨论】:
【参考方案3】:容器能否在启动时通过 docker0
桥 IP 直接从 etcd
读取,而不是传入值?这也将允许您对响应执行更复杂的逻辑,如果您将其存储为 etcd 值,则解析 JSON,等等。
【讨论】:
我不知道可以从容器中读取 etcd。也就是说,我正在运行一个 3rd 方二进制文件作为容器的入口点,因此无法从 Dockerfile 中读取 etcd(这似乎有点吓人)我不确定这是否能解决问题......以上是关于如何在 coreOS 上将 etcd 值添加到我的 systemd 服务中?的主要内容,如果未能解决你的问题,请参考以下文章