Linux: Automação de Tarefas — cron / systemd / journalctl
Tudo num servidor tem que ser automatizado — backups agendados, limpeza de logs, health checks. O Linux oferece soluções de automação que vão do simples (cron) ao moderno (systemd timers).
📋 Pré-requisitos: Você já deve conhecer
- Aula 21: Script Bash Avançado
1. O Que Você Vai Aprender
- Sintaxe de tarefas agendadas com crontab
- Como escrever units de serviço do systemd
- systemd timer como substituto do cron
- Consultas de log com journalctl
- Rotação de logs com logrotate
2. A História do "Nunca Mais Acordar às 2 da Manhã Pra Rodar Script"
(1) O Problema: Backup Manual Todo Dia
O script de backup do Xiaoming precisava ser rodado manualmente todo dia. Ele colocava despertador — acordava às 2 da manhã pra rodar ./backup.sh. Depois de uma semana, estava exausto.
(2) O cron Trouxe a Liberdade
O Bob ensinou o crontab pra ele:
crontab -e
# Adicione:
0 2 * * * /home/alice/scripts/backup.sh > /dev/null 2>&1
A partir daí, o sistema rodava o backup automaticamente todo dia às 2 da manhã. O Xiaoming só precisava olhar os logs de vez em quando.
(3) O Benefício: Deixe a Máquina Fazer o que a Máquina Tem que Fazer
Depois de aprender cron, o Xiaoming automatizou tudo de uma vez: backup diário, relatórios semanais, limpeza de logs, health checks. O tempo gasto com operação caiu de 2 horas pra 10 minutos por dia.
3. Pontos-Chave
(1) crontab — Tarefas Agendadas
Sintaxe do cron: minute hour day month weekday command
min hora dia mes weekday comando
(0-59)(0-23)(1-31)(1-12)(0-7)
(0=Domingo 7=Domingo)
# Sintaxe especial
@reboot # Roda na inicialização
@daily # Todo dia às 0:00 (igual a 0 0 * * *)
@hourly # A cada hora (igual a 0 * * * *)
@weekly # Toda segunda às 0:00
@monthly # Dia 1 de cada mês às 0:00
Exemplos Comuns:
# Ver o cron do usuário atual
crontab -l
# Editar o crontab
crontab -e
# Apagar todas as tarefas agendadas
crontab -r
# Exemplos comuns
0 2 * * * /scripts/backup.sh # Todo dia às 2:00
*/5 * * * * /scripts/health-check.sh # A cada 5 minutos
0 0 * * 0 /scripts/weekly-report.sh # Todo domingo às 0:00
0 0 1 * * /scripts/monthly-cleanup.sh # Dia 1 de cada mês
0 9-17 * * 1-5 /scripts/business-hours.sh # Dias úteis 9-17, a cada hora
crontab -r apaga todas as tarefas do usuário atual sem pedir confirmação! A recuperação só é possível a partir de um backup. Sempre faça backup com crontab -l antes de apagar, ou crie o hábito de editar com crontab -e em vez de apagar com crontab -r.
~/.bashrc, ~/.profile etc., e o PATH normalmente só tem /usr/bin:/bin. Se o seu script depende de variáveis de ambiente customizadas, faça source dos arquivos de configuração no topo, ou use caminhos absolutos pros comandos no crontab.
(2) Serviço do systemd
# Caminho da unit de serviço
/etc/systemd/system/meuapp.service
# Estrutura básica
[Unit]
Description=Minha Aplicação Web
After=network.target
[Service]
Type=simple
User=alice
WorkingDirectory=/opt/meuapp
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
# Como usar
sudo systemctl daemon-reload # Recarregar a configuração
sudo systemctl start meuapp # Iniciar
sudo systemctl enable meuapp # Habilitar no boot
sudo systemctl status meuapp # Ver o status
sudo journalctl -u meuapp -f # Ver os logs
(3) Timer do systemd
Persistent=true). Pra scripts periódicos simples sem essas necessidades, o cron é mais leve e intuitivo. Projetos novos deveriam começar pelo systemd timer.
# Unit de timer (substitui o cron)
/etc/systemd/system/backup.timer
[Unit]
Description=Timer do Backup Diário
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
# Serviço correspondente
/etc/systemd/system/backup.service
[Unit]
Description=Serviço de Backup Diário
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
# Como usar
sudo systemctl enable --now backup.timer
sudo systemctl list-timers --all
Sintaxe do OnCalendar:
OnCalendar=daily # Todo dia às 0:00
OnCalendar=hourly # A cada hora
OnCalendar=*-*-* 02:00:00 # Todo dia às 2:00
OnCalendar=Mon *-*-* 03:00:00 # Toda segunda às 3:00
OnCalendar=*-*-1 00:00:00 # Dia 1 de cada mês
OnCalendar=*:0/5 # A cada 5 minutos
(4) journalctl — Visualizador de Logs
# Básico
journalctl # Todos os logs
journalctl -u nginx # Serviço específico
journalctl -u nginx -f # Acompanhar em tempo real
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --until "2026-07-07 10:00"
journalctl -p err # Só nível de erro ou acima
journalctl -p err -u nginx # Logs de erro do nginx
# Gerenciamento
journalctl --disk-usage # Conferir o uso de disco dos logs
sudo journalctl --vacuum-size=500M # Limitar o tamanho dos logs
sudo journalctl --vacuum-time=7d # Manter só 7 dias
(5) logrotate — Rotação de Logs
/etc/cron.daily/logrotate). Você só precisa escrever a configuração em /etc/logrotate.d/. Depois de alterar uma config, use logrotate -d /etc/logrotate.d/sua-config em modo debug pra previsualizar, e depois entre em vigor automaticamente.
# Locais de configuração
/etc/logrotate.conf # Config global
/etc/logrotate.d/ # Configs por aplicação
# Exemplo: rotação de logs do Nginx
/var/log/nginx/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 640 www-data adm
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
Diretivas Comuns:
| Diretiva | Significado |
|---|---|
daily/weekly/monthly |
Frequência da rotação |
rotate N |
Mantém N cópias arquivadas |
compress |
Compacta os arquivos (gzip) |
delaycompress |
Atrasa a compactação em um ciclo |
missingok |
Não dá erro se o arquivo estiver faltando |
notifempty |
Não rotaciona arquivos vazios |
size 100M |
Só rotaciona quando o arquivo atinge o tamanho definido |
maxage 30 |
Apaga arquivos com mais de 30 dias |
(6) ▶ Exemplo: Configuração do crontab
# Editar o crontab
crontab -e
# Escreva o conteúdo abaixo
# ┌───── minuto (0-59)
# │ ┌───── hora (0-23)
# │ │ ┌───── dia do mês (1-31)
# │ │ │ ┌───── mês (1-12)
# │ │ │ │ ┌───── dia da semana (0-7, 0=Domingo)
# * * * * * comando
# Backup automático todo dia às 2:00
0 2 * * * /home/alice/scripts/backup.sh
# Health check a cada 5 minutos
*/5 * * * * /home/alice/scripts/health-check.sh
# Relatório semanal toda segunda às 3:00
0 3 * * 1 /home/alice/scripts/weekly-report.sh
# Limpeza de arquivos no dia 1 de cada mês
0 0 1 * * /home/alice/scripts/cleanup.sh
(7) ▶ Exemplo: Criando um Serviço systemd
# Criar um serviço systemd pra uma aplicação Node.js
sudo tee /etc/systemd/system/webapp.service << 'EOF'
[Unit]
Description=Aplicação Web Node.js
Documentation=https://example.com/docs
After=network.target
[Service]
Type=simple
User=alice
Group=alice
WorkingDirectory=/opt/webapp
Environment=NODE_ENV=production
Environment=PORT=3000
ExecStart=/usr/bin/node /opt/webapp/server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
# Opções de segurança
ProtectSystem=full
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now webapp
sudo systemctl status webapp
Saída:
TEXT● webapp.service - Aplicação Web Node.js Loaded: loaded (/etc/systemd/system/webapp.service; enabled) Active: active (running) since Tue 2026-07-07 10:23:45 UTC Main PID: 5678 (node) Tasks: 12 (limit: 4915) Memory: 45.2M CPU: 1.234s
(8) ▶ Exemplo: systemd Timer Substituindo o cron
# Serviço de backup
sudo tee /etc/systemd/system/backup.service << 'EOF'
[Unit]
Description=Backup Diário
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
User=alice
EOF
# Timer de backup
sudo tee /etc/systemd/system/backup.timer << 'EOF'
[Unit]
Description=Roda o backup todo dia às 2h
Requires=backup.service
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
sudo systemctl list-timers --all
Saída:
TEXTNEXT LEFT LAST PASSED Tue 2026-07-07 02:00:00 UTC 15h left Mon 2026-07-06 02:00:00 UTC 9h ago n/a n/a n/a n/a 1 timers listed.
(9) ▶ Exemplo: Consultas de Log com journalctl
# Ver os erros do nginx na última hora
journalctl -u nginx -p err --since "1 hour ago"
# Ver todos os logs de ontem
journalctl --since yesterday --until today
# Ver os logs de um PID específico
journalctl _PID=1234
# Acompanhar vários serviços em tempo real
journalctl -u nginx -u webapp -f
# Exportar logs pra um arquivo
journalctl -u webapp --since "2026-07-06" > webapp-logs.txt
# Conferir o uso de disco dos logs
journalctl --disk-usage
# Archived and active journals take up 512.0M
# Limpar
sudo journalctl --vacuum-size=200M
Saída:
TEXTJul 07 10:23:45 server nginx[1234]: GET /api/users 200 1234 Jul 07 10:23:50 server nginx[1234]: POST /api/data 500 0 Jul 07 10:24:01 server webapp[5678]: Error: ECONNREFUSED -- Logs begin at Mon 2026-07-06 00:00:01 -- Jul 07 09:00:00 server sshd[890]: Accepted publickey for alice Archived and active journals take up 512.0M Deleted archived journals: 23 Vacuuming done, freed 312.0M of archived journals
(10) ▶ Exemplo: Configuração do logrotate
# Configurar a rotação de logs pra uma aplicação customizada
sudo tee /etc/logrotate.d/custom-app << 'EOF'
/var/log/custom-app/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 640 www-data www-data
sharedscripts
postrotate
systemctl reload custom-app > /dev/null 2>&1 || true
endscript
}
EOF
# Testar a configuração
sudo logrotate -d /etc/logrotate.d/custom-app
# Forçar a execução manualmente
sudo logrotate -f /etc/logrotate.d/custom-app
Saída:
TEXTreading config file /etc/logrotate.d/custom-app Handling 1 logs rotating pattern: /var/log/custom-app/*.log rotating 14 kept versions considering log /var/log/custom-app/app.log log needs rotating renaming /var/log/custom-app/app.log to /var/log/custom-app/app.log.1 creating new /var/log/custom-app/app.log mode=0640 user=www-data group=www-data
(11) ▶ Exemplo Abrangente: Sistema de Operações Automatizadas
#!/bin/bash
# setup-automation.sh - Configura o sistema de operações automatizadas
set -euo pipefail
echo "=== Configurando o Sistema de Operacoes Automatizadas ==="
# 1. Criar diretório de scripts
mkdir -p /opt/scripts
# 2. Script de backup
cat > /opt/scripts/backup.sh << 'BACKUPEOF'
#!/bin/bash
# Backup automático - disparado todo dia às 2h pelo cron ou systemd timer
SOURCE="/var/www"
DEST="/backup"
RETENTION=30
mkdir -p "$DEST"
BACKUP_FILE="${DEST}/backup_$(date +%Y%m%d).tar.gz"
tar -czf "$BACKUP_FILE" \
--exclude=node_modules \
--exclude=.git \
"$SOURCE" 2>/dev/null
# Limpar backups expirados
find "$DEST" -name "backup_*.tar.gz" -mtime +$RETENTION -delete
# Log
echo "[$(date)] Backup: $BACKUP_FILE ($(du -h "$BACKUP_FILE" | cut -f1))" >> /var/log/backup.log
BACKUPEOF
chmod +x /opt/scripts/backup.sh
# 3. Script de health check
cat > /opt/scripts/health-check.sh << 'HEALTHEOF'
#!/bin/bash
# Health check - roda a cada 5 minutos
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
SERVICES=("nginx" "postgresql" "webapp")
for svc in "${SERVICES[@]}"; do
if ! systemctl is-active --quiet "$svc"; then
MESSAGE="❌ Servico $svc com problema $(date)"
echo "$MESSAGE" | mail -s "Alerta de Servico" admin@example.com
# curl -X POST -d "text=$MESSAGE" "$WEBHOOK_URL"
fi
done
# Verificação de disco
DISK_USAGE=$(df -h / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$DISK_USAGE" -gt 85 ]; then
echo "⚠️ Uso de disco: ${DISK_USAGE}%" >> /var/log/disk-alert.log
fi
HEALTHEOF
chmod +x /opt/scripts/health-check.sh
# 4. Configurar o cron
(crontab -l 2>/dev/null; echo "") | crontab -
(crontab -l 2>/dev/null; echo "# Backup automático - todo dia às 2:00") | crontab -
(crontab -l 2>/dev/null; echo "0 2 * * * /opt/scripts/backup.sh > /dev/null 2>&1") | crontab -
(crontab -l 2>/dev/null; echo "# Health check - a cada 5 minutos") | crontab -
(crontab -l 2>/dev/null; echo "*/5 * * * * /opt/scripts/health-check.sh > /dev/null 2>&1") | crontab -
(crontab -l 2>/dev/null; echo "# Limpeza de logs - todo domingo") | crontab -
(crontab -l 2>/dev/null; echo "0 0 * * 0 journalctl --vacuum-size=200M > /dev/null 2>&1") | crontab -
echo ""
echo "=== Sistema de Operacoes Automatizadas Configurado ==="
echo "Tarefas configuradas:"
crontab -l | grep -v "^#"
echo ""
echo "Verificacao manual: crontab -l"
❓ Perguntas Frequentes
P: As variáveis de ambiente do crontab são as mesmas do terminal? R: Não! O PATH no ambiente de execução do cron é bem mínimo (geralmente
/usr/bin:/bin). Se o seu script depende do PATH definido em~/.bashrc, defina o PATH no topo do script ou use caminhos absolutos no comando do cron.
P: Que vantagens o systemd timer tem sobre o cron? R: 1) Gerenciamento de dependências: timers podem depender de outros serviços. 2) Integração com logs: journalctl automático. 3) Execução perdida:
Persistent=truecompensa na próxima inicialização. 4) Mais preciso: aceita precisão de milissegundos. 5) Gerenciamento unificado:systemctl list-timers.
P: Os logs do journalctl podem encher o disco? R: O padrão é no máximo 10% do disco (mas limitado a 4 GB). Use
journalctl --vacuum-size=500Mou configureSystemMaxUse=500Mno/etc/systemd/journald.confpra limitar.
P: O logrotate roda sozinho ou preciso configurar no cron? R: O logrotate é executado diariamente pelo cron nativo do sistema (em
/etc/cron.daily/logrotate). Você só precisa configurar as regras em/etc/logrotate.d/— não precisa de configuração adicional no cron.
P: Como debugar quando o crontab não executa? R: Troubleshooting em três passos: 1) Verifique se o serviço de cron está rodando:
systemctl status cron. 2) Confira os logs do cron:grep CRON /var/log/syslog. 3) Rode o script manualmente pra confirmar que funciona:bash /caminho/do/script.sh.
📖 Resumo
- crontab:
minute hour day month weekday comando,crontab -epra editar - Serviço do systemd:
[Service] ExecStart=,Restart=on-failure - Timer do systemd:
OnCalendar=,Persistent=true - journalctl:
-u serviçopor serviço,-p errpor nível,-facompanhamento em tempo real - logrotate:
daily / rotate 7 / compressrotaciona os logs automaticamente
📝 Exercícios
- Básico (⭐): Configure o crontab pra rodar
datea cada hora e anexar a saída em/tmp/cron-test.log, depois use journalctl pra ver os logs de inicialização do nginx ou do sshd - Intermediário (⭐⭐): Crie um
hello.servicesimples e inicie-o (Type=simple), depois crie uma config do logrotate pra/var/log/test-app/*.logcom rotação diária mantendo 7 dias - Desafio (⭐⭐⭐): Escreva um timer do systemd que limpa arquivos expirados em
/tmptodo dia às 3:00 da manhã, com o arquivo de serviço correspondente, e configure o journalctl pra ver os logs de execução