Por que o systemd não sabe se um serviço falhou?

Por que o systemd não sabe se um serviço falhou?

Estou tentando provisionar aplicativos Spring-Boot (desenvolvidos por outra pessoa - não sou um programador Java) no Ubuntu 18.04. O desenvolvedor já havia adicionado links simbólicos /etc/init.dpara ativar o serviço - ele começa bem na inicialização. No entanto, se o serviço falhar posteriormente, o systemd ainda reportará que está em execução:

[email protected]:/var/log/apps# systemctl status crm-service
● crm-service.service - LSB: crm-service
   Loaded: loaded (/etc/init.d/crm-service; generated)
   Active: active (exited) since Wed 2020-04-15 12:27:15 BST; 3h 56min ago
     Docs: man:systemd-sysv-generator(8)
  Process: 8656 ExecStop=/etc/init.d/crm-service stop (code=exited, status=0/SUCCESS)
  Process: 8703 ExecStart=/etc/init.d/crm-service start (code=exited, status=0/SUCCESS)

Apr 15 12:27:15 example.com systemd[1]: Starting LSB: crm-service...
Apr 15 12:27:15 example.com crm-service[8703]: /var/services/crm-service.conf: line 1: -Xms96M: command not found
Apr 15 12:27:15 example.com crm-service[8703]: Started [8747]
Apr 15 12:27:15 example.com systemd[1]: Started LSB: crm-service.

Enquanto eu vejo omesmo arquivo de unidade systemdpara springboot postado em toda a Internet, não vejo nada que possa resolver esse problema.

  1. Como faço para que o systemd veja o verdadeiro status do serviço? (isso abrirá um soquete de escuta, mas em uma porta alta aleatória)
  2. Existe uma maneira de fazer o systemd tentarsuavementereiniciar um serviço que sabe que falhou?

Responder1

O Systemd tem muitos críticos e muitos deles são bons, mas não são.O Systemd pode rastrear todos os processos e threads bifurcados (ou clonados) do script de inicialização e considerar o serviço inativo se nenhum deles permanecer.

O primeiro problema que vejo: o systemd não usa scripts de início/parada no /etc/init.d, é apenas um complemento de compatibilidade para isso. Em vez disso, o systemd usa arquivos unitários, ou seja, um arquivo de configuração para todos os seus serviços.

O módulo systemd sysv init compat gera efetivamente um arquivo de unidade para todos os serviços em /etc/init.d. Isso nem sempre é correto, porque os scripts de inicialização perdem as informações necessárias (ou é impossível extraí-las deles).

Este módulo de compatibilidade funciona de forma que o systemd considere que o script de inicialização falhou e, portanto, o serviço não está funcionando, se seu código de saída for diferente de zero. Código de saída zero significa execução bem-sucedida. Se o script de inicialização apresentar erros e fornecer um código de saída zero, mesmo em caso de falha, ele enganará o systemd.

A causa mais provável do bug do seu script de inicialização é que ele inicia o processo em segundo plano e sai sempre com zero. Minha experiência comum com a maioria dos scripts de inicialização escritos por provedores personalizados é que... talvez a maioria deles tenha um grande espaço para melhorias. Não confie neles, veja o que eles fazem e conserte-os. No seu caso, o melhor seria verificar,

  • Como ele inicia seu aplicativo java
  • Onde isso começa
  • Como qual usuário ele inicia

E reproduza a mesma funcionalidade com um arquivo unitário.

Não há como reiniciar automaticamente os initscripts do systemd, mas é possível a partir de arquivos de unidade.

Observe que se um programa Java travar aleatoriamente, também será um problema sério. Todos os frameworks java sensatos lidam corretamente com seus próprios erros fatais (eles capturam todas as exceções, registram-nas e continuam).

Outro bug muito provável no script init é que ele não encontra sua JVM (provavelmente: /usr/bin/java), então ele a substitui por uma string vazia, resultando em uma tentativa de iniciar os sinalizadores da JVM como um comando shell . Obviamente não há -Xms96Mcomando em seu sistema, mas /usr/bin/java -Xms96M ...funcionaria.

Um exemplo de arquivo de unidade para um aplicativo Spring Boot:

[Unit]
Description=Crm Spring Boot App Example
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/java -Xms96M ...other flags... your.spring.boot.jar
User=exampleuser
Group=examplegroup
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=exampleapp
WorkingDirectory=/path/to/app/home

[Install]
WantedBy=multi-user.target
Alias=exampleapp.service

Este arquivo de unidade também redireciona a saída padrão e o erro do processo Java para o syslog.

Para reiniciar automaticamente o aplicativo, insira

RestartSec=5s
Restart=on-failure

na [Service]seção.

Há um tutorial do systemd emGoLinuxCloud.com.

informação relacionada