Como criar um serviço systemd virtual para parar / iniciar várias instâncias juntas?

11

Pretendo hospedar várias instâncias do mesmo aplicativo da Web para clientes que usam systemd . Gostaria de poder stop e start cada instância do cliente usando systemd , além de tratar toda a coleção de instâncias do cliente como um único serviço que pode ser interrompido e iniciado em conjunto.

systemd parece fornecer os blocos de construção que eu preciso usando PartOf e arquivos de unidade de modelo, mas fui parar o serviço pai, o serviço ao cliente filho não é interrompido. Como posso fazer isso funcionar com o systemd? Aqui está o que eu tenho até agora.

O arquivo da unidade pai, app.service :

[Unit]
Description=App Web Service

[Service]
# Don't run as a deamon (because we've got nothing to do directly)
Type=oneshot
# Just print something, because ExecStart is required
ExecStart=/bin/echo "App Service exists only to collectively start and stop App instances"
# Keep running after Exit start finished, because we want the instances that depend on this to keep running
RemainAfterExit=yes
StandardOutput=journal

Um arquivo de modelo de unidade chamado [email protected] , usado para criar instâncias do cliente:

[Unit]
Description=%I Instance of App Web Service

[Service]
PartOf=app.service
ExecStart=/home/mark/bin/app-poc.sh %i
StandardOutput=journal

My app-poc.sh script (Prova de conceito que apenas imprime no arquivo de log em um loop):

#!/bin/bash
# Just a temporary code to fake a full daemon.
while :
do
  echo "The App PoC loop for $@"
  sleep 2;
done

Para a prova de conceito, eu tenho os arquivos unitários do systemd em ~/.config/systemd/user .

Em seguida, inicio o pai e uma instância com base no modelo (após systemctl --user daemon-reload ):

systemctl --user start app
systemctl --user start [email protected]

Ao usar journalctl -f , posso ver que os dois começaram e que a instância do cliente continua a ser executada. Agora eu espero que o desligamento do pai pare o filho (porque eu usei PartOf ), mas isso não acontece. Além disso, iniciar o pai não está iniciando o filho como esperado.

systemctl --user stop app

Obrigado!

(estou usando o Ubuntu 16.04 com o systemd 229).

    
por Mark Stosberg 17.05.2016 / 18:25

2 respostas

7

Você precisa mover a linha

PartOf=app.service

de [Service] e na seção [Unit] e adicione à [Unit] de app.service a lista de clientes para iniciar, por exemplo

[email protected] [email protected]

ou como sourcejedi disse nos comentários, Requires= a mesma coisa. Você pode manter o PartOf para interromper os serviços iniciados manualmente que não estão na lista acima, como systemctl --user start [email protected] .

    
por 17.05.2016 / 18:47
10

Eu aprendi que isso é o que systemd "Target Units" é para. Ao usar uma Unidade de Destino, recebo os benefícios que desejo sem precisar criar a seção [Service] falsa que eu tinha acima. Um exemplo de exemplo de "unidade de destino" é assim:

# named like app.target
[Unit]
Description=App Web Service

# This collection of apps should be started at boot time.
[Install]
WantedBy=multi-user.target

Em seguida, cada instância do cliente deve incluir PartOf na seção [Unit] (como apontado por @meuh) e também deve ter uma seção [Install] para que enable e disable funcionem no específico serviço:

# In a file name like [email protected]
[Unit]
Description=%I Instance of App Web Service
PartOf=app.target

[Service]
ExecStart=/home/mark/bin/app-poc.sh %i
Restart=on-failure
StandardOutput=journal

# When the service runs globally, make it run as a particular user for added security
#User=myapp
#Group=myapp

# When systemctl enable is used, make this start when the App service starts
[Install]
WantedBy=app.target

Para exibir a instância do cliente e iniciá-la quando o destino é iniciado, esse comando de ativação única é usado:

 systemctl enable app

Agora, neste momento, posso usar stop e start on app@customer para uma instância específica ou posso usar start app e stop app para interromper todos os aplicativos juntos.

    
por 17.05.2016 / 22:13