Geração de sistema e processo

14

Normalmente não poste aqui, mas estou arrancando meu cabelo com este. Eu tenho um script Python que bifurca quando é iniciado e é responsável por iniciar vários outros processos. Esse script costumava ser iniciado na inicialização via sysvinit, mas recentemente eu atualizei para o Debian Jessie, então o adaptei para iniciar via systemd.

Infelizmente, estou com um problema que não consigo resolver. Quando você inicia o script diretamente no shell do usuário, ele inicia os processos filhos corretamente e, quando o script sai, os processos filhos ficam órfãos e continuam em execução.

Quando lançados pelo systemd, se o processo pai sair, todos os filhos também sairão (bem, as telas que eles lançam morrem e aparecem como mortas ???)

Idealmente, preciso poder reiniciar o script pai sem matar todos os processos filhos. Existe algo que estou faltando?

Obrigado!

[Unit]
Description=Server commander
After=network.target

[Service]
User=serveruser
Type=forking
PIDFile=/var/Server/Server.pid

ExecStart=/var/Server/Server.py
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

Edit: Provavelmente é relevante para mim salientar que o script Python é essencialmente um 'controlador' para seus processos filhos. Ele inicia e para servidores em telas gnu, conforme solicitado de um servidor central. Normalmente está sempre em execução, não gera serviços e sai. No entanto, há casos em que eu gostaria de poder recarregar o script sem matar processos filhos, mesmo que isso signifique que os processos fiquem órfãos até o pid 1. Na verdade, não importaria se o script Python iniciasse os processos como um processo pai, se isso for possível.

Uma explicação melhor de como funciona:

  • Systemd gera /Server.py
  • Server.py bifurca e grava o arquivo pid para Systemd
  • O Server.py gera processos do servidor na tela gnu com base em suas instruções
  • Server.py continua em execução para executar qualquer reinicialização solicitada do servidor

Ao iniciar sem o Systemd, o Server.py pode ser reiniciado e as telas gnu iniciadas não são afetadas. Ao iniciar com o Systemd, quando o Server.py é encerrado, em vez de os processos de tela ficarem órfãos para o pid 1, eles são mortos.

Bottswana
fonte
1
É difícil fornecer uma solução sem ter o Server.pycódigo e uma descrição de como os serviços lançados bifurcam (se bifurcam). No entanto, de um modo geral, esse é um problema de incompatibilidade do protocolo de prontidão .
Intelfx
Entre, o ExecStop=não é necessário. A ação padrão do systemd ao parar é matar processos. Você pode dar uma olhada na documentação da KillMode=diretiva.
Intelfx 21/05
1
E, finalmente ... Se não existe um protocolo prontidão adequada (um dos simpleou forking, na verdade), o último recurso seria Type=oneshot, RemainAfterExit=yese KillMode=control-group.
Intelfx
@intelfx Essencialmente, o script Python inicia um servidor em uma tela usando Subprocess.call. É mais complicado do que isso, porque o script recebe comandos de outros lugares, informando quais telas iniciar e quais não. Quais telas disponíveis também são dinâmicas, por isso, elas não podem ser serviços de sistema por si só. Idealmente, não quero que o systemd trate essas telas como parte do serviço, mas atualmente elas são despejadas no mesmo grupo de processos e morrem com o mestre se elas forem reiniciadas.
Bottswana
Meu palpite é que o systemd não "manipula" um processo de controle como esse (ele apenas consulta os PIDs no horário de início, não reconhece os posteriores ...): |
Rogerdpack 9/07/19

Respostas:

9

Eu consegui consertar isso simplesmente configurando o KillMode para processar em vez do grupo de controle (padrão). Obrigado a todos

Bottswana
fonte
Isso parece mais um trabalho do que uma correção, veja as outras respostas ... se você fizer isso e fizer uma "parada do systemctl", isso não matará os processos filhos que eles ainda estarão executando [?] fora da supervisão do systemctl?
Rogerdpack 8/07/19
5

Eu tenho um script Python que bifurca quando é iniciado e é responsável por iniciar vários outros processos.

O que indica que você está fazendo errado. Mais nisso daqui a pouco.

quando o script sai, os processos filhos ficam órfãos e continuam em execução.

Este não é o comportamento correto daemon. Se o processo "principal" - nesse caso, o filho que você bifurcou, desde que você especificou Type=forking- sair, o systemd considera o serviço desativado e encerra outros processos ainda em execução (no grupo de controle) para arrumar .

Às vezes, a conversão dos rcscripts do sistema 5 para o systemd não é direta, porque a maneira correta de fazer as coisas no systemd é bem diferente. A maneira correta de fazer (digamos) OpenVPN, OpenStack ou OSSEC HIDS no systemd não é a mesma que se faria com um rcscript. O fato de você ter um script que está bifurcando, gerando uma carga inteira de processos de netos e saindo esperando que esses netos continuem funcionando indica que você está cometendo o mesmo tipo de horror que ossec-control, embora com dois níveis menores de bifurcação. Se você se encontra escrevendo um script "mestre" que verifica os sinalizadores "ativar" e executa processos filhos para as partes "ativadas" do seu sistema, estará cometendo o mesmo erro que o horrendo ossec-control.

Não existem mecanismos caseiros com o systemd. Ele já é um gerente de serviço. Por /unix//a/200365/5132 , o caminho certo para fazer isso no systemd não é ter um serviço que gera alguma tentativa maluca e confusa de ter "sub-serviços". É ter cada processo filho como um serviço de sistema completo por direito próprio. Então, habilita-se e desabilita-se e inicia-se e para-as várias partes do sistema, usando os controles normais do sistema. Como você pode ver no caso OSSEC HIDS, uma unidade de serviço de modelo simples cobre quase todos os serviços (uma exceção está em /ubuntu//a/624871/43344 ), permitindo que você faça coisas como systemctl enable [email protected]ativar um opcionalagentlessdserviço, sem nenhuma necessidade do horrendo mecanismo de "script mestre" necessário ao Sistema 5 rc.

Existem muitos casos, talvez não tão extremos quanto o OSSEC HIDS, em que é necessário repensar. MTSes como exim e sendmail são dois. Pode-se ter um único rcscript que gera um corredor de fila, um daemon SMTP Submission e um daemon SMTP Relay, com várias variáveis ​​de shell ad hoc em um arquivo de configuração para controlar exatamente quais são executadas. Mas a maneira correta de fazer isso com o systemd é ter três unidades de serviço apropriadas (duas das quais têm unidades de soquete associadas ) e nenhum material ad hoc, apenas os mecanismos regulares do gerenciador de serviços.

JdeBP
fonte
Agradeço o feedback sobre isso. Embora eu concorde que ter serviços de subconjunto faça sentido, isso foi feito no Python por um motivo no qual não posso entrar. Minha única solução é encontrar uma maneira de fazer esse método funcionar. Obrigado, no entanto. Eu adoraria fazer isso corretamente.
Bottswana
Os 'sub-serviços que o script inicia são apenas servidores rodando na tela do gnu como um usuário específico. Esses servidores mudam muito, alguns são adicionados, outros são removidos e isso é controlado em outros lugares, portanto, eles não podem realmente ser serviços reais no systemd, porque isso aumenta a complexidade e não pode ser gerenciado centralmente. Além disso, o mesmo script também é usado em servidores não systemd.
Bottswana
O systemd possui recursos explícitos para permitir que serviços sejam adicionados e removidos sem a necessidade de acesso root. O "também usado em serviços que não são do systemd" é o único dos argumentos acima que não pode ser corrigido adicionando mais systemd ... bem, sem dúvida, até esse também poderia ser. :)
Charles Duffy
0

Você pode simplesmente dormir com o pai e esperar que o systemd o mate no momento da parada.

Craig Hicks
fonte