Telemetria leve no Debian: monitorando CPU, memória, disco, rede e Docker por meses

Recentemente precisei resolver um problema relativamente simples: acompanhar a performance de um servidor Debian durante vários meses, sem instalar uma plataforma inteira de observabilidade só para isso.

A necessidade era bem objetiva:

  • registrar CPU, memória, load average, disco e rede;
  • acompanhar também os containers Docker;
  • manter histórico por alguns meses;
  • gerar arquivos pequenos;
  • causar o mínimo possível de impacto no servidor;
  • permitir que os dados fossem baixados periodicamente para análise;
  • ter informação suficiente para justificar posteriormente um dimensionamento de infraestrutura.

A primeira ideia poderia ser instalar Prometheus, Grafana, Netdata, InfluxDB ou alguma solução semelhante.

Mas, para esse cenário, seria exagero.

O próprio Linux já possui uma ferramenta excelente para isso: o sysstat.

A solução ficou baseada em:

  • sysstat / sar para telemetria do sistema operacional;
  • docker stats para telemetria dos containers;
  • systemd timers para execução periódica;
  • arquivos locais compactados;
  • retenção automática;
  • exportação semanal em .tar.gz.

Sem banco de dados.

Sem painel web.

Sem mais uma stack para administrar.


O que é o sysstat?

O pacote sysstat é uma coleção de ferramentas tradicionais de monitoramento do Linux.

Entre elas estão:

  • sar
  • iostat
  • mpstat
  • pidstat
  • sadf

O diferencial é que o sysstat não serve apenas para visualizar o estado atual da máquina.

Ele também pode coletar e armazenar métricas continuamente.

Depois é possível voltar para um determinado dia e perguntar, por exemplo:

Como estava a CPU às 14h de terça-feira?

Ou:

Houve saturação de disco naquele período?

Ou ainda:

Quanto de memória estava sendo utilizada quando o load subiu?

É exatamente o tipo de informação necessária quando queremos analisar capacidade e performance retroativamente.


Arquitetura da coleta

A configuração que utilizei ficou assim:

Componente Intervalo
CPU, memória, disco, rede etc. 1 minuto
Docker 5 minutos
Retenção 180 dias
Compressão automática
Exportação manual/semanal

Os dados do sistema ficam em:

/var/log/sysstat/

Os dados adicionais do Docker ficam em:

/var/log/telemetry/docker/

Também mantemos um pequeno arquivo contendo o baseline da máquina:

/var/log/telemetry/baseline.txt

Isso registra informações como:

  • sistema operacional;
  • kernel;
  • CPU;
  • memória;
  • discos;
  • filesystems;
  • interfaces de rede;
  • versão do Docker;
  • containers existentes no início da coleta.

Esse baseline é importante porque daqui a alguns meses talvez ninguém lembre exatamente qual era a configuração original daquele servidor.


Script completo de instalação

Crie o arquivo:

nano install-telemetry.sh

E coloque:

#!/usr/bin/env bash

set -Eeuo pipefail

SYSSTAT_RETENTION_DAYS=180
DOCKER_RETENTION_DAYS=180

if [[ $EUID -ne 0 ]]; then
    echo "Execute como root:"
    echo "  sudo $0"
    exit 1
fi

echo "============================================================"
echo " Instalando telemetria leve"
echo "============================================================"

apt-get update
apt-get install -y sysstat gzip

# ----------------------------------------------------------------------
# SYSSTAT
# ----------------------------------------------------------------------

echo
echo "Configurando sysstat..."

if [[ -f /etc/default/sysstat ]]; then
    if grep -q '^ENABLED=' /etc/default/sysstat; then
        sed -i 's/^ENABLED=.*/ENABLED="true"/' /etc/default/sysstat
    else
        echo 'ENABLED="true"' >> /etc/default/sysstat
    fi
fi

SYSSTAT_CONFIG="/etc/sysstat/sysstat"

set_sysstat_option() {
    local key="$1"
    local value="$2"

    if grep -qE "^[[:space:]#]*${key}=" "$SYSSTAT_CONFIG"; then
        sed -ri "s|^[[:space:]#]*${key}=.*|${key}=${value}|" "$SYSSTAT_CONFIG"
    else
        echo "${key}=${value}" >> "$SYSSTAT_CONFIG"
    fi
}

set_sysstat_option "HISTORY" "${SYSSTAT_RETENTION_DAYS}"
set_sysstat_option "COMPRESSAFTER" "2"
set_sysstat_option "SADC_OPTIONS" '"-S DISK"'

# Desabilita o timer padrão do Debian, normalmente de 10 minutos.
# Será utilizado um timer próprio de 1 minuto.
systemctl disable --now sysstat-collect.timer 2>/dev/null || true

cat >/etc/systemd/system/telemetry-sysstat.service <<'EOF'
[Unit]
Description=Coleta de telemetria sysstat
ConditionPathExists=/usr/lib/sysstat/sa1

[Service]
Type=oneshot
ExecStart=/usr/lib/sysstat/sa1 1 1
EOF

cat >/etc/systemd/system/telemetry-sysstat.timer <<'EOF'
[Unit]
Description=Coleta sysstat a cada minuto

[Timer]
OnCalendar=*-*-* *:*:00
AccuracySec=2s
Persistent=true

[Install]
WantedBy=timers.target
EOF

# Mantém o processamento diário fornecido pelo próprio sysstat.
systemctl enable --now sysstat-summary.timer 2>/dev/null || true

# ----------------------------------------------------------------------
# DIRETÓRIOS
# ----------------------------------------------------------------------

install -d -m 0750 /var/log/telemetry
install -d -m 0750 /var/log/telemetry/docker

# ----------------------------------------------------------------------
# BASELINE DA MÁQUINA
# ----------------------------------------------------------------------

echo
echo "Gravando configuração base da máquina..."

{
    echo "================================================================"
    echo "TELEMETRY BASELINE"
    echo "================================================================"
    echo

    echo "Timestamp:"
    date --iso-8601=seconds
    echo

    echo "Hostname:"
    hostname
    echo

    echo "Sistema operacional:"
    cat /etc/os-release
    echo

    echo "Kernel:"
    uname -a
    echo

    echo "CPU:"
    lscpu
    echo

    echo "Memória:"
    free -h
    echo

    echo "Discos:"
    lsblk -e7 \
        -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS,MODEL,ROTA
    echo

    echo "Filesystems:"
    df -hT
    echo

    echo "Interfaces:"
    ip -br link 2>/dev/null || true
    echo

    if command -v docker >/dev/null 2>&1; then
        echo "Docker:"
        docker version 2>/dev/null || true
        echo

        echo "Containers atuais:"
        docker ps \
            --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}' \
            2>/dev/null || true
    fi

} >/var/log/telemetry/baseline.txt

chmod 0640 /var/log/telemetry/baseline.txt

# ----------------------------------------------------------------------
# DOCKER STATS
# ----------------------------------------------------------------------

if command -v docker >/dev/null 2>&1; then

    echo
    echo "Configurando telemetria Docker..."

    cat >/usr/local/sbin/telemetry-docker <<'EOF'
#!/usr/bin/env bash

set -Eeuo pipefail

LOGDIR="/var/log/telemetry/docker"

mkdir -p "$LOGDIR"

exec 9>/run/telemetry-docker.lock

if ! flock -n 9; then
    exit 0
fi

DATE="$(date +%F)"
TIMESTAMP="$(date --iso-8601=seconds)"
FILE="${LOGDIR}/docker-${DATE}.tsv"

if [[ ! -f "$FILE" ]]; then
    printf '%s\n' \
'timestamp container_id    name    cpu_percent memory_usage    memory_percent  net_io  block_io    pids' \
        >"$FILE"
fi

timeout 30 docker stats \
    --no-stream \
    --format '{{.Container}}   {{.Name}}   {{.CPUPerc}}    {{.MemUsage}}   {{.MemPerc}}    {{.NetIO}}  {{.BlockIO}}    {{.PIDs}}' \
    2>/dev/null |
while IFS= read -r line; do
    printf '%s\t%s\n' "$TIMESTAMP" "$line"
done >>"$FILE"

chmod 0640 "$FILE"
EOF

    chmod 0755 /usr/local/sbin/telemetry-docker

    cat >/etc/systemd/system/telemetry-docker.service <<'EOF'
[Unit]
Description=Coleta de telemetria Docker

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/telemetry-docker
EOF

    cat >/etc/systemd/system/telemetry-docker.timer <<'EOF'
[Unit]
Description=Coleta de telemetria Docker a cada 5 minutos

[Timer]
OnCalendar=*-*-* *:0/5:00
AccuracySec=10s
Persistent=true

[Install]
WantedBy=timers.target
EOF
fi

# ----------------------------------------------------------------------
# LIMPEZA E COMPRESSÃO
# ----------------------------------------------------------------------

cat >/usr/local/sbin/telemetry-housekeeping <<EOF
#!/usr/bin/env bash

set -Eeuo pipefail

LOGDIR="/var/log/telemetry/docker"

# Comprime arquivos Docker com mais de um dia.
find "\$LOGDIR" \
    -type f \
    -name 'docker-*.tsv' \
    -mtime +1 \
    -exec gzip -6 {} \;

# Remove telemetria Docker além do período de retenção.
find "\$LOGDIR" \
    -type f \
    \( -name 'docker-*.tsv' -o -name 'docker-*.tsv.gz' \) \
    -mtime +${DOCKER_RETENTION_DAYS} \
    -delete
EOF

chmod 0755 /usr/local/sbin/telemetry-housekeeping

cat >/etc/systemd/system/telemetry-housekeeping.service <<'EOF'
[Unit]
Description=Compressão e limpeza da telemetria

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/telemetry-housekeeping
EOF

cat >/etc/systemd/system/telemetry-housekeeping.timer <<'EOF'
[Unit]
Description=Manutenção diária da telemetria

[Timer]
OnCalendar=daily
RandomizedDelaySec=10m
Persistent=true

[Install]
WantedBy=timers.target
EOF

# ----------------------------------------------------------------------
# EXPORTAÇÃO
# ----------------------------------------------------------------------

cat >/usr/local/sbin/telemetry-export <<'EOF'
#!/usr/bin/env bash

set -Eeuo pipefail

DAYS="${1:-8}"

if ! [[ "$DAYS" =~ ^[0-9]+$ ]]; then
    echo "Uso:"
    echo "  sudo telemetry-export [dias]"
    exit 1
fi

HOST="$(hostname -s)"
NOW="$(date +%Y%m%d-%H%M%S)"
OUTPUT="${PWD}/${HOST}-telemetry-${NOW}.tar.gz"

cd /

FILES=()

while IFS= read -r -d '' file; do
    FILES+=("$file")
done < <(
    find \
        var/log/sysstat \
        var/log/telemetry \
        -type f \
        -mtime "-${DAYS}" \
        -print0 2>/dev/null
)

# O baseline sempre entra no pacote.
if [[ -f var/log/telemetry/baseline.txt ]]; then
    FILES+=("var/log/telemetry/baseline.txt")
fi

if [[ ${#FILES[@]} -eq 0 ]]; then
    echo "Nenhum arquivo de telemetria encontrado."
    exit 1
fi

tar -czf "$OUTPUT" "${FILES[@]}"

sha256sum "$OUTPUT" >"${OUTPUT}.sha256"

if [[ -n "${SUDO_USER:-}" && "$SUDO_USER" != "root" ]]; then
    USER_GROUP="$(id -gn "$SUDO_USER")"
    chown "$SUDO_USER:$USER_GROUP" \
        "$OUTPUT" \
        "${OUTPUT}.sha256"
fi

echo
echo "Pacote criado:"
echo "  $OUTPUT"
echo
echo "Hash:"
cat "${OUTPUT}.sha256"
EOF

chmod 0755 /usr/local/sbin/telemetry-export

# ----------------------------------------------------------------------
# ATIVAÇÃO
# ----------------------------------------------------------------------

systemctl daemon-reload

systemctl enable --now telemetry-sysstat.timer
systemctl enable --now telemetry-housekeeping.timer

if command -v docker >/dev/null 2>&1; then
    systemctl enable --now telemetry-docker.timer
fi

echo
echo "============================================================"
echo " Telemetria instalada"
echo "============================================================"
echo
echo "Sysstat:"
echo "  /var/log/sysstat/"
echo
echo "Docker:"
echo "  /var/log/telemetry/docker/"
echo
echo "Configuração da máquina:"
echo "  /var/log/telemetry/baseline.txt"
echo
echo "Exportar os últimos 8 dias:"
echo
echo "  sudo telemetry-export 8"
echo
echo "Timers:"
echo

systemctl list-timers \
    'telemetry-*' \
    --no-pager

Depois:

chmod +x install-telemetry.sh
sudo ./install-telemetry.sh

Verificando se está funcionando

Para conferir os timers:

systemctl list-timers 'telemetry-*'

Também podemos verificar individualmente:

systemctl status telemetry-sysstat.timer
systemctl status telemetry-docker.timer
systemctl status telemetry-housekeeping.timer

Após alguns minutos:

ls -lh /var/log/sysstat/

E:

ls -lh /var/log/telemetry/docker/

Consultando o histórico

É aqui que o sysstat começa a mostrar seu valor.

Supondo que exista:

/var/log/sysstat/sa23

Podemos analisar diversos aspectos daquele dia.

CPU

sar -u ALL -f /var/log/sysstat/sa23

Isso permite analisar utilização de CPU ao longo do dia.


Memória

sar -r ALL -f /var/log/sysstat/sa23

Podemos observar:

  • memória utilizada;
  • memória disponível;
  • cache;
  • buffers;
  • pressão de memória.

Load average

sar -q -f /var/log/sysstat/sa23

Aqui aparecem informações como:

  • quantidade de processos na fila;
  • load average de 1 minuto;
  • 5 minutos;
  • 15 minutos.

Isso é especialmente útil para identificar períodos em que a máquina estava recebendo mais trabalho do que conseguia processar imediatamente.


Disco

sar -d -p -f /var/log/sysstat/sa23

Essa é uma das métricas mais importantes em servidores.

É possível identificar, entre outras coisas:

  • quantidade de operações;
  • throughput;
  • tamanho das requisições;
  • tempo médio das operações;
  • utilização do dispositivo.

Um servidor com CPU relativamente baixa pode estar lento simplesmente porque o storage está saturado.

Sem telemetria histórica isso costuma passar despercebido.


Rede

sar -n DEV -f /var/log/sysstat/sa23

Podemos acompanhar:

  • pacotes recebidos;
  • pacotes enviados;
  • bytes recebidos;
  • bytes enviados;
  • utilização das interfaces.

Ver praticamente tudo

Também existe:

sar -A -f /var/log/sysstat/sa23

O -A significa basicamente:

mostre tudo que estiver disponível.

Para investigação rápida é extremamente útil.


Telemetria dos containers Docker

O sysstat mostra muito bem o que aconteceu com a máquina.

Mas em um servidor com Docker existe outra pergunta importante:

Quem causou isso?

É justamente por isso que acrescentei a coleta periódica de docker stats.

A cada cinco minutos é registrado um snapshot dos containers.

O arquivo fica semelhante a:

/var/log/telemetry/docker/docker-2026-08-23.tsv

Exemplo:

timestamp   container_id    name    cpu_percent memory_usage    memory_percent  net_io  block_io    pids
2026-08-23T16:00:00-03:00   76d...  erlang  19.6%   324.8MiB / 4GiB 7.93%   122MB / 84MB    31MB / 18MB 38
2026-08-23T16:00:00-03:00   7d2...  redis   8.0%    41.5MiB / 4GiB  1.01%   45MB / 39MB 8MB / 2MB   6

O formato TSV foi escolhido propositalmente.

É simples, compacto e pode posteriormente ser aberto ou processado facilmente com:

  • Excel;
  • LibreOffice;
  • Python/Pandas;
  • shell;
  • PostgreSQL;
  • DuckDB;
  • qualquer ferramenta de análise.

Correlacionando servidor e aplicação

Esse é provavelmente o ponto mais importante de toda a solução.

Sem essa coleta, normalmente temos algo assim:

O servidor estava lento às 14h.

Ou no máximo:

A CPU chegou a 80%.

Com histórico podemos investigar muito melhor:

Entre 14h02 e 14h11 a CPU permaneceu acima de 80%, o load average aumentou, o disco apresentou maior utilização e determinado container estava utilizando grande parte da CPU disponível.

Isso muda completamente a conversa sobre infraestrutura.

Passamos de percepção para evidência.


Exportando os dados toda semana

Criei também o comando:

telemetry-export

Por padrão ele exporta os últimos oito dias.

Execute:

sudo telemetry-export 8

Será gerado algo parecido com:

vps-mvp-01-telemetry-20260830-150000.tar.gz

E também:

vps-mvp-01-telemetry-20260830-150000.tar.gz.sha256

O segundo arquivo contém o hash SHA-256 do pacote.

Assim podemos verificar posteriormente se o arquivo baixado continua exatamente igual ao original.


Baixando o pacote

Por exemplo, usando scp:

scp usuario@servidor:~/vps-mvp-01-telemetry-20260830-150000.tar.gz .

E o hash:

scp usuario@servidor:~/vps-mvp-01-telemetry-20260830-150000.tar.gz.sha256 .

Depois:

sha256sum -c vps-mvp-01-telemetry-20260830-150000.tar.gz.sha256

Se estiver tudo correto:

OK

Quanto espaço isso consome?

Uma das preocupações era justamente deixar a coleta funcionando durante meses sem começar a consumir gigabytes desnecessariamente.

O sysstat é muito eficiente nesse aspecto.

Ele foi desenvolvido justamente para esse tipo de coleta.

O tamanho exato depende de:

  • quantidade de CPUs;
  • quantidade de discos;
  • quantidade de interfaces;
  • intervalo da coleta;
  • quantidade de containers.

Mas para uma VPS normal estamos falando de um volume bastante pequeno quando comparado a plataformas completas de observabilidade.

Depois de uma semana, podemos conferir o consumo real:

sudo du -sh /var/log/sysstat

E:

sudo du -sh /var/log/telemetry

A partir disso fica muito fácil estimar o consumo para seis meses.

Por exemplo, se uma semana gerar 30 MB:

30 MB × 26 semanas ≈ 780 MB

Ou seja: menos de 1 GB para aproximadamente seis meses de histórico.

O importante é medir na própria máquina, já que cada ambiente possui características diferentes.


Por que não coletar top ou ps continuamente?

Também seria possível executar algo como:

ps aux

a cada minuto.

Ou armazenar repetidamente a saída do top.

Mas preferi não fazer isso.

A quantidade de dados aumentaria consideravelmente e provavelmente guardaríamos muito mais informação do que realmente precisaríamos.

Além disso, linhas de comando de processos podem conter:

  • caminhos;
  • argumentos;
  • parâmetros;
  • informações internas da aplicação.

Não havia necessidade disso.

Para análise de capacidade, a combinação:

sysstat + docker stats

já fornece uma relação custo/benefício excelente.


Por que não Prometheus + Grafana?

Prometheus e Grafana são ferramentas excelentes.

Eu utilizaria tranquilamente essa stack se precisasse de:

  • dashboards em tempo real;
  • alertas;
  • observabilidade centralizada;
  • dezenas ou centenas de servidores;
  • histórico consultável constantemente;
  • integração com várias fontes;
  • SRE/NOC;
  • monitoramento operacional permanente.

Mas esse não era o problema.

O objetivo era:

deixar uma máquina sendo observada durante alguns meses para posteriormente analisar sua utilização e ajudar no dimensionamento.

Adicionar:

Prometheus
Grafana
Exporters
Banco de séries temporais
Containers
Volumes
Configurações
Atualizações
Backups
Segurança

seria criar uma infraestrutura para monitorar outra infraestrutura.

Neste caso, não precisava.


E por que não Netdata?

O Netdata também é excelente e extremamente prático para investigação em tempo real.

Mas novamente existe uma diferença entre:

quero enxergar meu servidor agora

e:

quero coletar dados discretamente durante vários meses para analisá-los posteriormente.

Para a segunda situação, prefiro algo simples e tradicional.

O sysstat existe há décadas justamente porque resolve muito bem esse problema.


O que podemos calcular depois

Depois de acumular algumas semanas ou meses de dados, podemos transformar essa telemetria em números realmente úteis.

Por exemplo:

CPU

  • média;
  • máximo;
  • P50;
  • P90;
  • P95;
  • P99.

Memória

  • média;
  • máximo utilizado;
  • mínimo disponível;
  • ocorrência de swap.

Disco

  • throughput;
  • IOPS;
  • latência;
  • utilização;
  • períodos de saturação.

Rede

  • tráfego médio;
  • picos;
  • volume diário;
  • volume por interface.

Containers

  • CPU média;
  • CPU máxima;
  • memória média;
  • memória máxima;
  • crescimento de memória;
  • tráfego;
  • I/O;
  • quantidade de processos.

E principalmente podemos correlacionar tudo isso.


Média não basta

Esse detalhe merece atenção.

Se um servidor permanecer:

23 horas e 50 minutos com CPU em 10%

e:

10 minutos com CPU em 100%

a média diária provavelmente parecerá excelente.

Mas talvez justamente aqueles dez minutos correspondam ao período em que os usuários reclamam de lentidão.

Por isso métricas como:

P90
P95
P99

são tão importantes.

O percentil 95, por exemplo, ajuda a responder:

Qual utilização não foi excedida durante 95% do período?

Esse tipo de informação é muito mais útil para dimensionamento do que simplesmente olhar a média mensal.


Resultado

No final ficamos com uma solução bastante pequena:

Debian
  │
  ├── sysstat
  │     └── CPU / RAM / load / disco / rede
  │
  ├── docker stats
  │     └── CPU / RAM / rede / I/O por container
  │
  ├── systemd timers
  │
  └── arquivos locais
        │
        ├── retenção automática
        ├── compressão
        └── exportação semanal

Sem banco.

Sem aplicação web.

Sem serviço externo.

Sem depender de SaaS.

Sem uma segunda infraestrutura para administrar.

E, principalmente, sem perder a informação que realmente interessa.


Conclusão

Às vezes a solução certa não é instalar mais software.

O Linux já possui ferramentas extremamente maduras que resolvem problemas desse tipo há muitos anos.

Para uma análise de capacidade de médio prazo, o sysstat oferece uma quantidade surpreendente de informação consumindo poucos recursos e pouco espaço.

O complemento com docker stats resolve a outra metade do problema nos ambientes modernos: descobrir não apenas como estava o servidor, mas também qual workload estava utilizando seus recursos.

Agora basta deixar a coleta trabalhar.

Daqui a algumas semanas teremos dados.

Daqui a alguns meses teremos histórico.

E quando chegar a hora de discutir se a máquina precisa de:

  • mais CPU;
  • mais memória;
  • storage mais rápido;
  • redistribuição dos containers;
  • ou absolutamente nada;

a decisão poderá ser baseada em números — e não em uma screenshot do top.


Publicado

em

por

Tags: