Serviço Systemd iniciar com valor de porta dinâmica do Docker

5

Usando o CoreOS, o Docker e o systemd para gerenciar meus serviços, quero executar adequadamente a descoberta de serviços. Como o CoreOS utiliza o etcd (valor-chave distribuído), existe uma maneira muito conveniente de fazer isso. No ExecStartPost do systemd eu posso apenas inserir o serviço iniciado no etcd sem problemas. Meu usecase precisa de algo assim:

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

que funciona como um encanto.

Mas é aí que minha ideia apareceu. O Docker tem o poder de atribuir aleatoriamente uma porta se eu executar apenas docker run -p 5555 , o que é incrível, pois não preciso configurá-la estaticamente no arquivo * .service e possivelmente executar várias instâncias no mesmo host. E se eu pudesse obter a porta atribuída aleatoriamente e inserir em vez da estática 5555 ?

Acontece que eu posso usar o comando docker port para obter a porta e com alguma formatação podemos obter apenas a porta com

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

que funciona se eu configurá-lo (usando o bash) assim:

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

mas usando systemd eu simplesmente não consigo fazer funcionar. Este é o código que estou usando:

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

De alguma forma, eu entendi algo errado, mas é difícil depurar, já que funciona quando digitado no terminal.

    
por gust1n 15.04.2014 / 14:59

2 respostas

2

A opção systemd ExecStart não faz nenhuma interpolação de shell e, portanto, não entende coisas como $(echo 'Hello') . Mas, você pode iniciar um shell que executa o comando para obter um comportamento como este. Tente algo como:

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)'}'"
    
por 12.06.2014 / 21:42
0

Acabei usando algo assim:

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"

Mas a resposta para a minha pergunta foi, de fato, que eu precisava informar qual shell executar o comando.

Editar: Adicionando a lógica de modelagem 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}}
    
por 29.07.2014 / 08:23