Usando o systemd no Linux - Como criar seus próprios serviços e daemons no Linux?
- Como fazer um programa iniciar automaticamente no Linux após reiniciar o computador?
- Caso aconteça algum erro no programa e ele pare de funcionar, como reinicia-lo automaticamente?
O programa systemd (system daemon) do Linux pode gerenciar tudo isso para nós.
Se você está no Windows e quer criar serviços, use o NSSM, veja esse outro artigo aqui no blog.
O SystemD é um gerenciador de Serviços ou Daemons. O que é Serviço ou Daemon? São softwares/programas/aplicativos que tem as características de ficarem ligados por longos tempos e não ter uma interface gráfica. Geralmente eles iniciam automaticamente quando o computador é ligado, e quem faz isso no Linux é o systemd.
Ao iniciar o Linux ou instalar certos softwares, são criados automaticamente vários serviços, e você pode acessá-los com os comandos systemctl (use *sudo* se você estiver mexendo com serviços do sistema):
# Para descobrir todos os serviços instalados e se estão parados ou rodandosystemctl list-unit-files # Para ver o log e o estado de um serviço específico systemctl status nome-do-servico systemctl status nome-do-servico@subprocesso systemctl status nome-do-servico@* # Para parar um serviço systemctl stop nome-do-servico # Para iniciar um serviço systemctl start nome-do-servico # Para reiniciar um serviço systemctl restart nome-do-servico # Para fazer um serviço iniciar automaticamente quando o computador ligar systemctl enable nome-do-servico # Para impedir que um serviço inicie automaticamente quando o computador ligar systemctl disable nome-do-servico
Criando seu próprio serviço - fazendo um software ser iniciado automaticamente ao ligar o computador
Eis um exemplo de arquivo de serviço para o systemd no Ubuntu 16.04 (ATENÇÃO! Em versões diferentes do próprio Ubuntu esse arquivo pode mudar e precisar de comandos diferentes para executar uma mesma tarefa).
Nesse exemplo rodaremos um código em python 3.
O nome do arquivo deve terminar em .service (tipo seu-servico.service). O arquivo deve ser salvo na pasta /etc/systemd/system
sudo nano /etc/systemd/system/seu-servico.service
Conteúdo do arquivo:
[Unit]Description=Seu serviço customizado - Versão 1.0 After=network.target [Service] Type=simple Restart=always RestartSec=1 StartLimitInterval=0 ExecStart=/usr/bin/python3 /home/ubuntu/codigo/hello.py WorkingDirectory=/home/my-user/hello-logs/ User=my-user [Install] WantedBy=multi-user.target
Depois de alterar um serviço que já existe, faça o systemd recarregar a configuração dos serviços
sudo systemctl daemon-reload
Veja se seu serviço foi instalado corretamente usando
sudo systemctl status seu-servico.service# ou sudo systemctl status seu-servico
Para excluir de vez um serviço que não quer ser apagado:
systemctl stop [servicename]systemctl disable [servicename] rm /etc/systemd/system/[servicename] rm /etc/systemd/system/[servicename] # and symlinks that might be related rm /usr/lib/systemd/system/[servicename] rm /usr/lib/systemd/system/[servicename] # and symlinks that might be related systemctl daemon-reload systemctl reset-failed
Onde ficam os arquivos responsáveis por iniciar serviços?
Os serviços criados automaticamente por softwares baixados via apt install (por exemplo) são salvos em:
Debian e Ubuntu:
/lib/systemd/system/
Outras distribuições:
/usr/lib/systemd/
Os serviços customizados, criados por você ou por um administrador do sistema, podem ser colocados em:
/etc/systemd/system/
Uma lista completa da localização dos arquivos de serviço do systemd está aqui.
Costumo deixar que o dono dos serviços seja o usuário root, e a permissão 644.
chown root:root servico-teste.servicechmod 644 servico-teste.service
Executando o Python dentro de um Ambiente Virtual (Virtual Environment)
Dentro de [Service] coloque
[Service]... ... Environment="PYTHONPATH=/home/ubuntu/anaconda/envs/intel/lib/python3.6/site-packages" ...
Vendo logs ou saídas do systemd usando journalctl
# Para filtrar pelo nome do serviçojournalctl -u nome-do-servico.service # Para filtrar pelo nome do serviço usando grep journalctl | grep nome_do-servico # Para ver os logs do serviço em tempo real (também chamado de tail) journalctl --follow -u nome-do-servico.service
Usando o systemd a nível de usuário, sem precisar de sudo!
É possível criar serviços no systemd sem precisar de sudo, essa função do systemd se chama user lingering. Ela já funciona por padrão no Debian ou no Ubuntu.
O user lingering faz o systemd criar automaticamente uma sessão para aquele usuário com o lingering ativo. Isso permite que esse usuário rode comandos assim que o computador seja iniciado, sem precisar pedir permissão ao super usuário (sudo).
Se você quiser usar o systemd a nivel de usuário via SSH é preciso instalar um pacote adicional. Aqui vai os comandos:
# Instalando o libpam-systemd para corrigir bug de acesso ao systemd --user via ssh. Sessões via ssh normalmente não conseguem executar o comando systemd --user ..., mas com esse pacote os bugs são resolvidossudo apt install libpam-systemd# Criando um usuáriosudo adduser -m -s /bin/bash user-test# Habilitando o systemd a nível de usuário para um usuário específico.# Troque user-test pelo nome do usuario desejado.sudo loginctl enable-linger USERNAME
Agora faça login com o usuário desejado e crie o diretório para armazenar os arquivos de serviço
# Logado com o usuário desejado, crie as pastas do systemdmkdir -p ~/.config/systemd/user/
Se você quiser usar o systemd a nivel de usuário com um usuário trocado (utilizando o comando su -) é preciso fazer algumas configurações extras. Vamos alterar o arquivo ~/.profile e fazê-lo carregar uma variável de ambiente.
# Estando logado com o usuário comum (sem sudo), rode o seguinte comandoecho "export XDG_RUNTIME_DIR=/run/user/$UID" >> ~/.profile
Vamos também aplicar essa configuração para usuários futuros:
# Estando logado com o usuário root ou sudo, rode o seguinte comandosudo sh -c "echo 'export XDG_RUNTIME_DIR=/run/user/\$UID' >> /etc/skel/.profile"
Os arquivos de serviço a nivel de usuário estão em:
~/.config/systemd/user/
Ao criar o serviço (arquivo .service), é importante utilizar os seguintes parametros:
#esse é uma dica:[Service]...WorkingDirectory=/home/%u...#esse é importantíssimo!![Install]WantedBy=default.target
Para executar comandos basta usar:
systemctl --user status seu-servicosystemctl --user stop seu-servico systemctl --user start seu-servico systemctl --user enable seu-servico systemctl --user disable seu-servico # versões antigas do systemd journalctl --user --user-unit=seu-servico # versões novas do systemd journalctl --user -u seu-servico
Variáveis usadas em um arquivo do tipo .service
%n
: Anywhere where this appears in a template file, the full resulting unit name will be inserted.%N
: This is the same as the above, but any escaping, such as those present in file path patterns, will be reversed.%p
: This references the unit name prefix. This is the portion of the unit name that comes before the@
symbol.%P
: This is the same as above, but with any escaping reversed.%i
: This references the instance name, which is the identifier following the@
in the instance unit. This is one of the most commonly used specifiers because it will be guaranteed to be dynamic. The use of this identifier encourages the use of configuration significant identifiers. For example, the port that the service will be run at can be used as the instance identifier and the template can use this specifier to set up the port specification.%I
: This specifier is the same as the above, but with any escaping reversed.%f
: This will be replaced with the unescaped instance name or the prefix name, prepended with a/
.%c
: This will indicate the control group of the unit, with the standard parent hierarchy of/sys/fs/cgroup/ssytemd/
removed.%u
: The name of the user configured to run the unit.%U
: The same as above, but as a numericUID
instead of name.%H
: The host name of the system that is running the unit.%%
: This is used to insert a literal percentage sign.
Fazendo serviço reiniciar de tempos em tempos
Você pode comandar o systemd a reiniciar seu serviço a cada X segundos, no exemplo abaixo fazemos reiniciar a cada 300 segundos (5 minutos):
[Service]Type=simple Restart=always RuntimeMaxSec=300 RestartSec=1 StartLimitInterval=0
Referências
Tutorial: Criando um serviço no linux com o systemd
https://medium.com/@benmorel/creating-a-linux-service-with-systemd-611b5c8b91d6
Tutorial 2: Criando um serviço no linux com systemd
https://www.devdungeon.com/content/creating-systemd-service-files
Significado dos parêmetros usados no arquivo .service
https://www.digitalocean.com/community/tutorials/understanding-systemd-units-and-unit-files
Documentação oficial do Linux sobre os scripts de inicialização em /etc/init.d
http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/initscrcomconv.html
Cinco maneiras diferentes de rodar um programa automaticamente no Linux
https://www.dexterindustries.com/howto/run-a-program-on-your-raspberry-pi-at-startup/
Criando um systemd com timer (substituto do cron)
https://medium.com/horrible-hacks/using-systemd-as-a-better-cron-a4023eea996d
Documentação do Redhat Linux 7 sobre systemd
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-unit_files
Definindo usuários ao rodar um serviço
https://askubuntu.com/questions/676007/how-do-i-make-my-systemd-service-run-via-specific-user-and-start-on-boot
Compreendendo SystemD
https://www.digitalocean.com/community/tutorials/understanding-systemd-units-and-unit-files
Reiniciando serviço de tempos em tempos com systemd
https://stackoverflow.com/a/50332245
User Lingering - SystemD
Tutorial muito bom sobre systemd user services
https://www.unixsysadmin.com/systemd-user-services/
Documentação Arch Linux sobre user lingering
https://wiki.archlinux.org/title/systemd/User#Reading_the_journal
Unixadmin - User Lingering
https://www.unixsysadmin.com/systemd-user-services/
RHEL Forum
https://access.redhat.com/solutions/4661741
Rodando SystemD como usuário
https://superuser.com/questions/1025091/start-a-systemd-user-service-at-boot
https://unix.stackexchange.com/questions/438064/failed-to-determine-supplementary-groups-operation-not-permitted
Documentação do comando para habilitar systemd a nivel de usuário
https://www.freedesktop.org/software/systemd/man/loginctl.html#enable-linger%20USER%E2%80%A6
Journalctl com systemd a nivel de usuário
https://serverfault.com/questions/806469/how-to-allow-a-user-to-use-journalctl-to-see-user-specific-systemd-service-logs
Usando o systemd para outros usuários
https://unix.stackexchange.com/questions/423632/systemctl-user-not-available-for-www-data-user
Arrumando arquivo .profile para o user lingering após troca de usuário via shell (sudo su -)
https://unix.stackexchange.com/questions/462845/how-to-apply-lingering-immedeately