如何在 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 服务中?的主要内容,如果未能解决你的问题,请参考以下文章

分布式键值存储系统ETCD调研

etcd 集群部署

etcd

etcd教程

Etcd-Etcd快速入门及PromQL查询etcd指标

etcd工作原理和部署指南