Um servidor se paga fazendo coisas enquanto você dorme: backups, rotação de logs, renovação de certificados, um relatório às nove. O Linux tem dois agendadores para isso. O cron tem quarenta anos e ocupa uma linha. Os timers do systemd ocupam dois arquivos pequenos e dão em troca logs, recuperação após paradas e hora exata. Este guia cobre os dois no Ubuntu 24.04, com cada comportamento verificado num servidor novo da nossa imagem, incluindo os três erros que fazem uma tarefa do cron falhar sem dizer nada.
Você precisa de um usuário com sudo; o guia de configuração do Ubuntu cria um.
1. Cron em cinco minutos
O cron vem instalado e rodando nas nossas imagens Ubuntu e Debian. Cada usuário tem uma tabela de tarefas; edite a sua com:
crontab -e
Cada linha tem cinco campos de tempo e um comando:
# min hour day month weekday command
30 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * /usr/local/bin/check.sh
0 9 * * 1-5 /usr/local/bin/report.sh
@reboot /usr/local/bin/start-tunnel.sh
Ou seja: às 03:30 toda noite, a cada 5 minutos, às 09:00 em dias úteis e uma vez após cada boot. */5 significa um a cada cinco valores, 1-5 um intervalo, 1,15 uma lista. Vale o fuso horário do servidor, UTC nas nossas imagens; defina o seu uma vez com o guia de nome do host e fuso horário e o cron segue.
Veja o que rodou com journalctl -u cron. Cada execução registra o usuário e o comando, e é aí que aparecem as três armadilhas.
Armadilha 1: a saída some. O cron envia por e-mail a saída de uma tarefa ao usuário. Nossa imagem não tem servidor de e-mail, então o journal dizia (CRON) info (No MTA installed, discarding output) e a saída sumia. Redirecione você mesmo, como no primeiro exemplo com >> /var/log/backup.log 2>&1.
Armadilha 2: o sinal de porcentagem. Num crontab, % encerra o comando e transforma o resto em entrada padrão. Agendamos date +%F > /tmp/today. O journal mostra o que o cron rodou de fato: CMD (date +). Nenhum arquivo foi gravado e nenhum erro chegou até nós. Escreva \%, ou coloque o comando num script e agende o script.
Armadilha 3: um ambiente diferente. O cron roda tarefas com /bin/sh, não bash, no seu diretório pessoal e com ambiente enxuto. No Ubuntu 24.04 o PATH foi melhor que a sua fama: o caminho completo do sistema, incluindo /usr/local/bin e /snap/bin, para root e para um usuário comum. O que ainda falta é tudo o que fica no seu diretório pessoal: ~/.local/bin, o node do nvm, pipx, cargo. Use caminhos completos na tarefa ou comece a linha com . $HOME/.profile;.
Tarefas que pertencem ao sistema e não a um usuário vão em /etc/cron.d/, como arquivo com um campo a mais, o usuário:
30 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
O Ubuntu também roda tudo em /etc/cron.hourly, cron.daily, cron.weekly e cron.monthly, aos 17 minutos de cada hora, às 06:25, às 06:47 aos domingos e às 06:52 no dia 1. Coloque ali um script executável e ele roda junto com os outros.
2. Timers do systemd
Um timer são duas unidades: um serviço que faz o trabalho e um timer que diz quando. Crie primeiro o script, depois as unidades.
sudo nano /usr/local/bin/backup.sh
sudo chmod +x /usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run the backup every night at 03:30
[Timer]
OnCalendar=*-*-* 03:30
Persistent=true
AccuracySec=1m
[Install]
WantedBy=timers.target
Ative o timer, não o serviço:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
O list-timers mostra a próxima execução, quanto falta e a última execução. Logs não precisam de configuração: journalctl -u backup.service tem cada início, cada fim e cada linha de saída, com horário. Para rodar a tarefa agora, sudo systemctl start backup.service; é também assim que você testa o script antes de confiar no horário.
Sintaxe do calendário. OnCalendar se lê diadasemana ano-mês-dia hora:minuto:segundo, com * para qualquer valor. Teste uma expressão antes de usar:
systemd-analyze calendar "Mon..Fri *-*-* 03:00" --iterations 2
Ele imprime a forma normalizada e as próximas datas. Algumas expressões que verificamos:
| OnCalendar | Significado |
|---|---|
*-*-* 03:30 | Todo dia às 03:30 |
Mon..Fri *-*-* 09:00 | Dias úteis às 09:00 |
*:0/15 | A cada 15 minutos |
weekly | Segundas às 00:00 |
*-*-01 04:00 | Dia 1 de cada mês às 04:00 |
*-*-* 03:00 Europe/Kyiv | 03:00 no horário de Kyiv; rodou às 01:00 UTC no nosso teste |
As três configurações que vale conhecer. Persistent=true grava a última execução em disco e recupera uma execução perdida enquanto o servidor estava desligado ou o timer parado. Paramos nosso timer de dois em dois minutos, esperamos passar uma execução agendada e o iniciamos de novo: a execução perdida disparou no mesmo segundo. Sem Persistent, ele simplesmente espera o próximo horário.
AccuracySec é a surpresa. Por padrão o systemd agrupa os timers numa janela de um minuto para economizar despertares, então nossa primeira execução veio às 07:42:18, não às 07:42:00. Com AccuracySec=1s as seguintes caíram em 07:46:00 e 07:48:00 no segundo exato. Ajuste quando o minuto importar; deixe o padrão para um backup noturno.
RandomizedDelaySec=10m faz o oposto de propósito: espalha o início numa janela para que dez servidores não batam no mesmo armazenamento de backup no mesmo segundo.
Para uma tarefa avulsa, nenhum arquivo:
sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh
Isso cria um timer transitório que dispara uma vez e some; até lá, o systemctl list-timers o mostra.
3. Qual usar
| Cron | Timer do systemd | |
|---|---|---|
| Configuração | 1 linha | 2 arquivos |
| Logs | Só se você redirecionar a saída | journalctl -u name.service |
| Execução perdida com o servidor desligado | Perdida | Roda no boot com Persistent=true |
| Tarefa ainda rodando no próximo ciclo | Uma segunda cópia inicia | Pulada até a primeira terminar |
| Hora exata | No minuto | No segundo com AccuracySec=1s |
| Status | Nenhum | list-timers, systemctl status |
Use o cron para uma linha rápida que você vai reconhecer daqui a um ano. Use um timer para tudo cuja falha você precisa ver, que não pode se sobrepor ou que precisa rodar depois de um reboot perdido: backups, renovação de certificados, limpeza de bancos de dados. Se uma tarefa do cron pode se sobrepor, envolva-a: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, e a segunda cópia sai na hora.
Os dois agendadores rodam uma tarefa e param. Para um programa que deve rodar o tempo todo e voltar depois de uma falha, você precisa de um serviço, não de um horário; veja como criar um serviço do systemd e, para Windows, como rodar um script 24/7 no Windows Server. Um bom primeiro timer é o do nosso guia de backup com restic; as atualizações de segurança automáticas são um timer que o Ubuntu já traz, apt-daily-upgrade.timer, um dos 17 que rodam num servidor novo.
Comentários
Nenhum comentário ainda. Seja o primeiro.