Systemd 服务从 Docker 使用动态端口值启动

Systemd 服务从 Docker 使用动态端口值启动

使用 CoreOS、Docker 和 systemd 来管理我的服务,我希望正确执行服务发现。由于 CoreOS 使用 etcd(分布式键值),因此有一种非常方便的方法可以做到这一点。在 systemd 的 ExecStartPost 上,我可以将启动的服务插入到 etcd 中,不会出现任何问题。我的用例需要类似以下内容:

ExecStartPost=/usr/bin/etcdctl set /services/myServiceName '{ \"host\": \"%H\", \"port\": 5555 }'

效果非常好。

但这正是我的想法出现的地方。如果我只是运行,Docker 就可以随机分配一个端口,docker run -p 5555这很棒,因为我不必在 *.service 文件中静态设置它,而且我可能在同一主机上运行多个实例。如果我可以获取随机分配的端口并插入而不是静态的,会怎么样5555

事实证明,我可以使用docker port命令来获取端口,并且通过一些格式化,我们可以只获取端口

$(echo $(/usr/bin/docker port my-container-name 5555) | cut -d':' -f2)

如果我像这样设置它(使用 bash),它就会起作用:

/usr/bin/etcdctl set /services/myServiceName '{ \"host\": \"%H\", \"port\": '$(echo $(/usr/bin/docker port my-container-name 5555) | cut -d':' -f2)' }'

但使用 systemd 我无法让它工作。这是我使用的代码:

ExecStartPost=/usr/bin/etcdctl set /services/myServiceName '{ \"host\": \"%H\", \"port\": '$(echo $(/usr/bin/docker port my-container-name 5555) | cut -d':' -f2)'}'

不知怎的,我犯了个错误,但很难调试,因为它在终端中输入时可以工作。

答案1

systemdExecStart选项不执行任何 shell 插值,因此无法理解诸如 之类的内容$(echo 'Hello')。但是,您可以启动执行命令的 shell 来获得这样的行为。尝试以下操作:

ExecStartPost=/bin/sh -c "/usr/bin/etcdctl set /services/myServiceName '{ \"host\": \"%H\", \"port\": '$(echo $(/usr/bin/docker port my-container-name 5555) | cut -d':' -f2)'}'"

答案2

我最终使用了类似这样的东西:

ExecStart=/bin/sh -c "port=$(docker port [CONTAINER-NAME] [CONTAINER-EXPOSED-PORT] | cut -d ':' -f 2); echo Connected to $port, publishing to etcd...; while netstat -lnt | grep :$port >/dev/null; do etcdctl set /services/[CONTAINER-NAME]/[SOME-IDENTIFIER] $port --ttl 60 >/dev/null; sleep 45; done"

但我的问题的答案确实是我需要说明在哪个 shell 中运行该命令。

编辑:添加 Go 模板逻辑

[Service]
EnvironmentFile=/etc/environment
ExecStartPre=/bin/sh -c "until docker port {{.Name}} {{.Port}} >/dev/null 2>&1; do echo Waiting for {{.Name}}; sleep 2; done; port=$(docker port {{.Name}} {{.Port}} | cut -d ':' -f 2); echo Waiting for $port/tcp...; until netstat -lnt | grep :$port >/dev/null; do sleep 1; done"
ExecStart=/bin/sh -c "port=$(docker port {{.Name}} {{.Port}} | cut -d ':' -f 2); echo Connected to $COREOS_PRIVATE_IPV4:$port/tcp, publishing to etcd...; while netstat -lnt | grep :$port >/dev/null; do etcdctl set /services/{{.Service}}/{{.Name}} $COREOS_PRIVATE_IPV4:$port --ttl 60 >/dev/null; sleep 45; done"
ExecStop=/usr/bin/etcdctl rm --recursive /services/{{.Service}}/{{.Name}}

相关内容