Systemd: gerenciando serviços no Linux

1. Introdução ao Systemd no contexto DevOps

Systemd é o sistema de init e gerenciador de serviços padrão na maioria das distribuições Linux modernas. Ele substituiu o antigo SysVinit, oferecendo paralelismo na inicialização, dependências declarativas e monitoramento ativo de processos. Para profissionais DevOps, dominar Systemd é essencial porque:

  • Serviços críticos como Docker Engine, containerd e kubelet são gerenciados por ele
  • Permite criar serviços customizados para aplicações que rodam em contêineres
  • Oferece controle granular sobre dependências e ordem de inicialização
  • Substitui scripts de inicialização frágeis por arquivos de configuração declarativos

Diferente do SysVinit, que usava scripts shell sequenciais, Systemd usa arquivos de unidade (unit files) que descrevem serviços, sockets, dispositivos e timers de forma padronizada. Essa abordagem é fundamental para ambientes de contêineres, onde múltiplos serviços precisam iniciar na ordem correta.

2. Comandos essenciais para gerenciamento de serviços

O comando systemctl é a principal ferramenta para interagir com Systemd. Veja os comandos mais usados no dia a dia DevOps:

# Verificar status de um serviço
systemctl status docker.service

# Iniciar/parar/reiniciar um serviço
systemctl start docker.service
systemctl stop docker.service
systemctl restart docker.service

# Habilitar/desabilitar inicialização automática
systemctl enable docker.service
systemctl disable docker.service

# Listar todas as unidades ativas
systemctl list-units --type=service

# Listar dependências de um serviço
systemctl list-dependencies docker.service

# Verificar se um serviço está ativo
systemctl is-active docker.service

Em ambientes produtivos, enable e disable são cruciais para garantir que serviços essenciais como Docker e kubelet iniciem automaticamente após uma reinicialização do servidor.

3. Criando e editando unit files (serviços customizados)

Um arquivo .service possui três seções principais. Veja um exemplo prático para uma aplicação Node.js:

[Unit]
Description=API de Microsserviço Node.js
Documentation=https://docs.exemplo.com/api
After=network.target docker.service
Requires=docker.service

[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/minha-api
ExecStart=/usr/bin/node /opt/minha-api/server.js
Restart=always
RestartSec=10
Environment=NODE_ENV=production
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Principais diretivas:
- Restart=always: reinicia automaticamente se o processo falhar
- RestartSec: tempo de espera antes de reiniciar
- After: define ordem de inicialização
- Requires: dependência obrigatória

Para ativar o serviço:

sudo systemctl daemon-reload
sudo systemctl enable minha-api.service
sudo systemctl start minha-api.service

4. Gerenciamento de dependências e ordem de inicialização

Controlar a sequência de inicialização é vital em ambientes com múltiplos contêineres. As principais diretivas são:

[Unit]
Description=App com dependência de banco
After=docker.service postgres.service
Requires=docker.service
Wants=redis.service
BindsTo=postgres.service
PartOf=minha-aplicacao.target
  • After: define que este serviço inicia após os listados
  • Requires: se o serviço falhar, este também falha
  • Wants: dependência opcional (não quebra se falhar)
  • BindsTo: serviço fortemente acoplado (se parar, este para junto)
  • PartOf: agrupa serviços em um target comum

Exemplo prático: serviço que só inicia após o Docker Engine estar pronto:

[Unit]
Description=Worker de processamento
After=docker.service
Requires=docker.service

[Service]
ExecStartPre=/usr/bin/docker pull minha-imagem:latest
ExecStart=/usr/bin/docker run --rm minha-imagem:latest
ExecStopPost=/usr/bin/docker system prune -f

5. Logs e monitoramento com journald

Systemd integra logging via journald, acessível com journalctl. Comandos essenciais para DevOps:

# Ver logs de um serviço específico
journalctl -u docker.service

# Últimos 50 logs com atualização contínua
journalctl -u kubelet.service -n 50 -f

# Logs das últimas 2 horas
journalctl -u containerd.service --since "2 hours ago"

# Logs por prioridade (0=emerg, 3=err, 6=info)
journalctl -u docker.service -p err

# Exportar logs para análise
journalctl -u kubelet.service --output=json > kubelet-logs.json

Para integrar com sistemas externos como Fluentd (usado em clusters Kubernetes), configure o rsyslog:

# /etc/rsyslog.d/journal-forward.conf
module(load="imjournal")
*.* action(type="omfwd" target="fluentd-host" port="514" protocol="tcp")

6. Timers do Systemd (substituto do cron para DevOps)

Timers oferecem mais controle que o cron tradicional. Exemplo: limpeza automática de imagens Docker:

# /etc/systemd/system/docker-cleanup.service
[Unit]
Description=Limpeza de imagens Docker não utilizadas

[Service]
Type=oneshot
ExecStart=/usr/bin/docker image prune -af
# /etc/systemd/system/docker-cleanup.timer
[Unit]
Description=Timer para limpeza de imagens Docker

[Timer]
OnCalendar=daily
OnBootSec=10min
RandomizedDelaySec=30min
Persistent=true

[Install]
WantedBy=timers.target

Ativando o timer:

sudo systemctl daemon-reload
sudo systemctl enable docker-cleanup.timer
sudo systemctl start docker-cleanup.timer

Diretivas de tempo:
- OnCalendar: agendamento estilo cron (daily, weekly, Mon..Fri 02:00:00)
- OnUnitActiveSec: executa X tempo após última ativação
- OnBootSec: executa X tempo após boot

7. Systemd e Docker: integração prática

Serviços Systemd podem gerenciar contêineres Docker diretamente. Exemplo de serviço que mantém um contêiner sempre rodando:

[Unit]
Description=Contêiner Nginx gerenciado por Systemd
After=docker.service
Requires=docker.service

[Service]
ExecStartPre=-/usr/bin/docker rm -f nginx-app
ExecStart=/usr/bin/docker run --name nginx-app -p 8080:80 nginx:latest
ExecStop=/usr/bin/docker stop nginx-app
ExecStopPost=/usr/bin/docker rm -f nginx-app
Restart=always
RestartSec=5
TimeoutStartSec=60

[Install]
WantedBy=multi-user.target

Para controle de recursos:

[Service]
CPUQuota=50%
MemoryMax=256M
MemoryHigh=200M

O ExecStartPre com - ignora erros (útil se o contêiner não existir ainda).

8. Boas práticas para ambientes Kubernetes

Em clusters Kubernetes, Systemd gerencia os componentes críticos:

# Verificar status do kubelet
systemctl status kubelet.service

# Verificar dependências do kubelet
systemctl list-dependencies kubelet.service

# Logs de falha do containerd
journalctl -u containerd.service -p err --since "1 hour ago"

Configuração típica para workers:

[Unit]
Description=Kubernetes Kubelet
Documentation=https://kubernetes.io/docs/
After=containerd.service
Wants=containerd.service
Requires=network.target

[Service]
ExecStart=/usr/bin/kubelet \
  --container-runtime=remote \
  --container-runtime-endpoint=unix:///run/containerd/containerd.sock
Restart=always
RestartSec=10
CPUQuota=80%

[Install]
WantedBy=multi-user.target

Troubleshooting rápido:

# Diagnóstico de falha no kubelet
systemctl status kubelet.service
journalctl -u kubelet.service -n 100 --no-pager

# Verificar se containerd está rodando
systemctl is-active containerd.service

# Ver dependências não atendidas
systemctl list-dependencies kubelet.service --reverse

Systemd é a espinha dorsal da inicialização e gerenciamento de serviços no Linux moderno. Para profissionais DevOps, dominar seus comandos, unit files e integração com Docker/Kubernetes é indispensável para manter ambientes estáveis, diagnosticáveis e automatizados.

Referências