使用CoreOS,Docker和systemd来pipe理我的服务我想正确执行服务发现。 由于CoreOS使用etcd(分布式键值),因此有一个非常方便的方法来做到这一点。 在systemd的ExecStartPost上,我可以将启动的服务插入到etcd中而没有问题。 我的用例需要这样的东西:
ExecStartPost=/usr/bin/etcdctl set /services/myServiceName '{ \"host\": \"%H\", \"port\": 5555 }'
它像一个魅力。
但这是我的想法popup的地方。 如果我只是运行docker run -p 5555
,Docker有权随机分配一个端口,因为我不必在* .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)'}'
不知怎的,我得到了一些错误,但很难debugging,因为它在terminalinput时工作。
systemd ExecStart
选项不执行任何shell插值,因此不理解像$(echo 'Hello')
ExecStart
$(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)'}'"
我结束了使用这样的事情:
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}}