如何在启动 unit/service 之前等待设置 etcd 变量

How to wait for an etcd variable is set before starting the unit/service

我目前正在 CoreOS 集群中使用 ELK(Elasticsearch、Logstash、Kibana)堆栈进行日志记录。我发现,您可以使用 gelf 自动将日志从 docker 发送到 logstash。我正在使用 sidekick 编写 logstash 容器 IP 地址的 etcd 变量。因为我必须将 logstash 的 IP 传递给 docker 运行 命令中的标志,所以我需要等到设置变量。

我的问题是如何才能等到 etcdctl get /network/logstash returns IP 地址。

这是我的单元文件目前的样子:

[Unit]
Description=nginx with elk logging
After=logstash-discovery.service
Requires=docker.service

[Service]
TimeoutStartSec=0
ExecStartPre=/usr/bin/bash -c "/usr/bin/systemctl set-environment ADDR=$(etcdctl get /network/logstash)"
ExecStartPre=-/usr/bin/docker kill nginx1
ExecStartPre=-/usr/bin/docker rm nginx1
ExecStartPre=/usr/bin/docker pull 10.0.2.2:5000/nginx
ExecStart=/usr/bin/docker run -p 80:80 --name=nginx1 --net=host --log-driver=gelf --log-opt gelf-address=udp://${ADDR}:12201 --log-opt gelf-tag="fe" 10.0.2.2:5000/nginx
ExecStop=/usr/bin/docker stop nginx1

[X-Fleet]
Conflicts=logstash.service

你的问题归结为一个关于 bash 编程的问题:你如何等到变量被设置后再继续?

该问题的变体已在 How to create a loop in bash that is waiting for a webserver to respond? 中得到解答。

这通常需要一行以上的代码,因此您可能需要将逻辑放在一个文件中并指向 ExecStartPre 而不是使用一行代码。

解决方案是使用 etcdctl watch 而不是 etcdctl get,但要先检查变量是否尚未设置。 所以整行看起来像这样:

ExecStartPre=/usr/bin/bash -c \
"if [ -z $(etcdctl get /network/logstash) ]; \
then /usr/bin/systemctl set-environment ADDR=$(etcdctl watch /network/logstash); \
else /usr/bin/systemctl set-environment ADDR=$(etcdctl get /network/logstash); \
fi"