Articles

Criar um serviço Linux com systemd

Posted on
Crafting os seus próprios serviços – Foto de Jeff Sheldon em Unsplash

enquanto escreve aplicações web, Preciso frequentemente de descarregar tarefas pesadas de computação para um guião de trabalhador assíncrono, agendar tarefas para mais tarde, ou mesmo escrever um daemon que ouça uma tomada para comunicar directamente com os clientes.

Embora por vezes possa haver melhores ferramentas para o trabalho – considere sempre primeiro a utilização de software existente, tal como um servidor de fila de tarefas – escrever o seu próprio serviço pode dar-lhe um nível de flexibilidade que nunca obterá quando estiver limitado pelas restrições de software de terceiros.

O interessante é que é bastante fácil criar um serviço Linux: utilize a sua linguagem de programação favorita para escrever um programa de longa duração, e transforme-o num serviço utilizando systemd.

Criemos um pequeno servidor utilizando PHP. Consigo ver as vossas sobrancelhas a subir, mas funciona surpreendentemente bem. Vamos ouvir a porta UDP 10000, e devolver qualquer mensagem recebida com uma transformação ROT13:

P>Vamos iniciá-lo:

$ php server.php

E testá-lo noutro terminal:

$ nc -u 127.0.0.1 10000
Hello, world!
Uryyb, jbeyq!

Cool, funciona. Agora queremos que este script funcione a todo o momento, seja reiniciado em caso de falha (saída inesperada), e mesmo que sobreviva ao reinício do servidor. É aí que o systemd entra em acção.

Torná-lo para um serviço

Vamos criar um ficheiro chamado /etc/systemd/system/rot13.service:


Description=ROT13 demo service
After=network.target
StartLimitIntervalSec=0
Type=simple
Restart=always
RestartSec=1
User=centos
ExecStart=/usr/bin/env php /path/to/server.php

WantedBy=multi-user.target

Terá de o fazer:

  • definir o seu verdadeiro nome de utilizador após User=
  • definir o caminho correcto para o seu script em

É isso. Podemos agora iniciar o serviço:

$ systemctl start rot13

E automaticamente começar no arranque:

$ systemctl enable rot13

Vai mais longe

Agora que o seu serviço (esperançosamente) funciona, pode ser importante mergulhar um pouco mais fundo nas opções de configuração, e garantir que funcionará sempre como espera.

Começar na ordem correcta

P>Pode ter-se perguntado o que a directiva After= fez. Isto significa simplesmente que o seu serviço deve ser iniciado depois de a rede estar pronta. Se o seu programa espera que o servidor MySQL esteja operacional, deve adicionar:

After=mysqld.service

Restarting on exit

Por defeito, o systemd não reinicia o seu serviço se o programa sair por qualquer razão. Normalmente não é isto que deseja para um serviço que deve estar sempre disponível, por isso estamos a instruí-lo para reiniciar sempre à saída:

Restart=always

Também pode usar on-failure para reiniciar apenas se o estado de saída não for 0.

Por defeito, o systemd tenta um reinício após 100ms. Pode especificar o número de segundos a esperar antes de tentar um reinício, usando:

RestartSec=1

Anular a armadilha: o limite de início

Cai pessoalmente nesta mais de uma vez. Por defeito, quando configura Restart=always como nós fizemos, o systemd desiste de reiniciar o seu serviço se não iniciar mais de 5 vezes num intervalo de 10 segundos. Forever.

Existem duas opções de configuração responsáveis por isto:

StartLimitBurst=5
StartLimitIntervalSec=10

A directiva RestartSec também tem um impacto no resultado: se o configurar para reiniciar após 3 segundos, então nunca poderá atingir 5 tentativas falhadas dentro de 10 segundos.

A correcção simples que funciona sempre é definir StartLimitIntervalSec=0. Desta forma, o systemd tentará reiniciar o seu serviço para sempre.

É uma boa ideia definir RestartSec para pelo menos 1 segundo no entanto, para evitar colocar demasiada tensão no seu servidor quando as coisas começarem a correr mal.

Como alternativa, pode deixar as configurações padrão, e pedir ao systemd para reiniciar o seu servidor se o limite de arranque for atingido, usando StartLimitAction=reboot.

Is that really it?

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *