quinta-feira, 24 de abril de 2025

Descritores de Arquivo e Swappiness


DESCRITORES DE ARQUIVO (File Descriptors)

   Vamos começar com um bla bla bla técnico, mas que é necessário, então procurei amenizar o bla bla bla numa linguagem acessível, senão nem eu entenderia.
   Um Descritor de Arquivo (FD - File Descriptor) é um número inteiro não negativo retornado pelo sistema (Linux) quando o acesso para um arquivo é permitido sendo que o processo o usa para referenciar um determinado arquivo aberto. É também chamado de Identificador de Arquivo.
   "Arquivo" aqui não é somente um arquivo em si, mas tudo o que acontece quando você utiliza o Linux, quando você abre um programa é criado um descritor de arquivo, uma espécie de índice, também um "cache", veremos mais adiante.
   Lembrando que tem esse nome: "descritores de arquivo"; mas para cada programa, ou melhor ainda, para cada coisa, vamos dizer assim, para cada coisa que você faz no Linux é aberto um descritor de arquivo, uma espécie de índice para que não se tenha de lidar com o arquivo propriamente dito. É uma questão de integridade dos dados, isso vem desde o UNIX.
   Lembrando aquela máxima (que não é tão verdadeira, mas está valendo): Tudo no Linux é arquivo!

   Imagina que você está escrevendo num papel e outra pessoa vem escrever outra coisa nesse mesmo papel... dará bagunça.
   Então você escreve no papel e dá uma cópia para outra pessoa corrigir, acrescentar, modificar, etc.
   Caso forem muitos papéis você organiza numa tabela e/ou num arquivo quem está com qual papel.
   Quando um processo precisa acessar um arquivo ele faz isso através do descritor do arquivo.
   Os descritores são mantidos pelo Kernel através de uma tabela. O tamanho dessa tabela varia.
   Os descritores de arquivo não descrevem exatamente um arquivo, mas sim referenciam e controlam o acesso e modificação dos mesmos.
   Os descritores de arquivo de cada processo são controlados pela tabela de "file descriptors" do kernel que por sua vez referenciam arquivos reais nos sistemas de arquivos (ext4, btrfs, etc) utilizados pelo sistema operacional.
   Sempre existirá ao menos 1 descritor de arquivo no Kernel para cada arquivo aberto no sistema operacional.
   Pode acontecer de um único arquivo ter mais de um descritor.

   Caso você esteja procurando uma fórmula mágica para setar os valores dos descritores de arquivo para deixar seu Linux turbinado e extrapolando o hardware da tua máquina, sinto muito, isso não existe, mas deixo aqui uma sugestão para todos que tem um desktop/laptop de uso normal:

   NÃO MEXA EM NADA, DEIXE NO PADRÃO!

   Citarei aqui alguns casos específicos onde se faz necessário alterar os limites.

Servidores Web com Alta Conexão (Apache, Nginx, etc.)
Problema: Cada conexão pode usar pelo menos um descritor de arquivo.
Sintoma: Erros como "Too many open files".
Necessidade: Aumentar o limite para permitir milhares de conexões simultâneas, nesse caso o Linux avisa que você deve aumentar o limite: Too many open files.

Bancos de Dados (PostgreSQL, MySQL, Oracle, etc.)
Problema: Conexões simultâneas e manipulação de arquivos de dados e logs consomem muitos FDs (File Descriptors).
Necessidade: Bancos como o PostgreSQL recomendam aumentar o limite para centenas de milhares em ambientes de produção.

Aplicações Multithread com Alto I/O
Problema: Programas que lidam com muitos arquivos, conexões de rede, pipes ou sockets ao mesmo tempo.
Exemplo: Aplicações Java, Node.js ou Python com centenas/milhares de conexões.

Sistemas de Monitoramento, Backup e Indexação (ElasticSearch, Logstash, rsync, etc.)
Problema: Precisam manter milhares de arquivos abertos ao mesmo tempo.
ElasticSearch, por exemplo, recomenda um limite de 65536 ou mais.

Ambientes de Desenvolvimento com Muitos Arquivos Abertos
Problema: Editores de texto como o VSCode, ou compiladores, podem abrir muitos arquivos simultaneamente em grandes projetos.
Necessidade: Ajuste para evitar falhas durante builds ou operações em massa.

Cluster de modo geral
Cada processo pode abrir múltiplas conexões de rede para comunicação ponto a ponto.
Em execuções com muitos processos (por exemplo, milhares de ranks), o número de conexões simultâneas cresce exponencialmente.
Além disso, cada processo no cluster pode manter arquivos abertos para logs, checkpoints, e arquivos temporários.


   Porém, contudo, todavia, entretanto, caso mesmo assim você queira ou precise modificar os valores, no final desta página tem como fazer isso, resumidamente, com o título MODIFICANDO OS LIMITES.

   Vamos executar agora:
$ cat /proc/sys/fs/file-nr

Exemplo da saída:
11808    0    9223372036854775807

   O primeiro número é o uso atual que mostra quantos descritores (ou identificadores) de arquivo estão atualmente alocados no sistema inteiro.
O segundo valor indica o número de descritores de arquivo alocados, mas não utilizados.
O terceiro número indica o número máximo de descritores de arquivo.
O Linux Kernel 2.6 e versões posteriores sempre relatam 0 como o número de descritores de arquivo livres — isso não é um erro, significa apenas que o número de descritores de arquivo alocados corresponde exatamente ao número de identificadores de arquivo utilizados.

   Se o primeiro valor estiver perto do terceiro valor é hora de aumentar o número de descritores de arquivo.

   Vamos entender esses limites.

   A saída de cat /proc/sys/fs/file-max é o valor global máximo de descritores de arquivo que o Kernel alocará - isso é feito para impedir um uso descabido de memória por um processo mal intencionado;
   A saída de cat /proc/sys/fs/nr_open é o número máximo de descritores de arquivo que um único processo pode alocar, o valor padrão é 1024*1024 (1048576), o que deve ser suficiente para a maioria das máquinas.
   A saída de ulimit (-Sn e -Hn) são os valores por sessão/processo do Shell por usuário.
   O parâmetro DefaultlimitNOFILE dentro de /etc/systemd/system.conf define o limite somente para os serviços gerenciados pelo Systemd.
   O arquivo /etc/security/limits.conf seta os limites para um usuário em específico.

   Vendo o limite atual por sessão do Shell do usuário logado:
$ ulimit -Sn # soft limit
1024

$ ulimit -Hn # hard limit
1048576

   Ao alterar com "ulimit -n algum_numero" vale somente até fechar o terminal, ou seja, serve para testar se a configuração dará problema.
   O comando ulimit no Linux não busca diretamente um arquivo específico, mas ele é influenciado por configurações que podem estar em vários arquivos do sistema, geralmente em /proc/<PID>/limits.
   Essas configurações determinam os limites de recursos para processos do usuário (como número máximo de arquivos abertos, tamanho máximo de arquivos, etc).

   Aliás, na própria "man ulimit" avisa que esse comando ficará obsoleto devendo utilizar "prlimit".
   Veremos adiante os arquivos no diretório /proc.

$ prlimit -n (-n, --nofile número máximo de arquivos abertos)
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE número máximo de arquivos abertos 126639 1048576 arquivos

$ prlimit -u (-u, --nproc número máximo de processos de usuário)
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE número máximo de processos 126639 126639 arquivos

$ prlimit --help
$ man prlimit

   O limite rígido (hard) é o valor máximo para o limite flexível (soft). Somente usuários root têm permissão para alterar o limite rígido.
   É preciso entender que o limite flexível (soft) não é exatamente um limite mínimo, é um limite inicial para o mínimo de arquivos que um processo pode abrir no sistema.
   O Soft limit pode ser alterado pelo próprio processo — até o valor de hard.
   O Hard limit só pode ser aumentado pelo root (ou com permissões elevadas - sudo, su, etc).
  O limite soft é o valor que o Kernel impõe para o recurso correspondente.
   O limite hard atua como um teto para o limite soft.

   O que significa Soft e Hard na prática:
   O processo (serviço) começa com permissão para abrir até 1.024 arquivos.
   Porém, se o processo quiser, ele pode elevar esse limite até 1.048.576 (desde que tenha permissão pra isso, claro).
   O file-max não restringe usuários diretamente, só protege o sistema de esgotar descritores globalmente.

   Além de tudo tem o Systemd se metendo na parada:
"Os sysctls fs.nr_open e fs.file-max agora são automaticamente elevados para os valores mais altos possíveis, pois a contabilização separada de descritores de arquivo não é mais necessária porque o memcg já os rastreia corretamente como parte da contabilização de memória. Assim, dos quatro limites para descritores de arquivo atualmente aplicados (fs.file-max, fs.nr_open, RLIMIT_NOFILE hard, RLIMIT_NOFILE soft) desativamos os dois primeiros e mantemos apenas os dois últimos."
   Veja maiores explicações adiante.

   Tudo isso significa que um processo/programa/aplicativo/etc aberto no Linux tem aqueles limites iniciais e finais para trabalhar, senão o Kernel impede.
   Como já visto, os limites globais são os mais altos possíveis.
   Os outros limites podem ser definidos pelo processo e/ou pelo usuário.
  Vemos aí surgir a famosa liberdade do Linux e começamos a entender também porque é muito difícil fazer um malware para Linux mesmo ele tendo seu código fonte aberto a todos.
   Vejam bem, falei "difícil", não impossível, mas essa é uma outra discussão que não cabe agora no momento.
   Veremos adiante que "malware" pode ser qualquer software que trava/prejudica o sistema, como a própria definição do limite nr_open, como veremos adiante na seção MODIFICANDO OS LIMITES > AVISO IMPORTANTE.

   Aconselho a alterar somente o limite global fs.file-max em /etc/sysctl.conf definindo-o com o mesmo valor da saída de "ulimit -Hn" ou "prlimit" na linha NOFILE coluna HARD:
$ prlimit
RESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE número máximo de arquivos abertos 1024 1048576 arquivos

   Como já dito, caso for desktop/laptop de uso diário/cotidiano não precisa alterar nada.

$ cat /proc/sys/fs/file-max
9223372036854775807
Valor padrão do Kernel automaticamente elevado para o valor mais alto possível.
Esse valor mais alto possível é determinado pelos desenvolvedores do Kernel seguindo o bom senso e a experiência.

   Grosso modo, caso um processo/programa/aplicativo querer alocar mais de 9.223.372.036.854.775.807 arquivos então obviamente trata-se de um software mal intencionado que quer travar o sistema.

   Depois de alterar o /etc/sysctl.conf para, por exemplo, 1048576, a saída do comando cat /proc/sys/fs/file-max será 1048576. É preciso reiniciar.

Veremos agora essa tabela no código fonte do Kernel Linux.


A partir da linha 26 do arquivo fdtable.h (Linguagem C):

struct fdtable {
unsigned int max_fds;
struct file __rcu **fd; /* current fd array */
unsigned long *close_on_exec;
unsigned long *open_fds;
unsigned long *full_fds_bits;
struct rcu_head rcu;
};

   Interessante no momento é a variável max_fds que faz o Kernel retornar o erro de "Too many open files" (Muitos arquivos abertos) quando um computador, por exemplo, está com muitos sockets abertos.
   Cada processo tem a sua própria tabela de descritores de arquivo, lembrando que todo o Kernel Linux tem a estrutura de "árvore", uma árvore invertida, uma árvore genealógica, basicamente um organograma - processos pais e processos filhos.

   Somente para complementar e para não se tornar chato veremos a última parte do arquivo (a partir da linha 107):

struct files_struct *dup_fd(struct files_struct *, struct fd_range *) __latent_entropy;
void do_close_on_exec(struct files_struct *);
int iterate_fd(struct files_struct *, unsigned,
int (*)(const void *, struct file *, unsigned),
const void *);

extern int close_fd(unsigned int fd);
extern struct file *file_close_fd(unsigned int fd);

extern struct kmem_cache *files_cachep;

   Logo no começo temos ponteiros para files_struct e fd_range com um retorno para uma nova files_struct que é uma duplicata da original.
   A função do_close_on_exec fecha os descritores de arquivo marcados com FD_CLOEXEC.
   A função iterate_FD itera (executa um bloco de código repetidamente para processar uma coleção de dados) sobre os descritores.
   A função close_fd fecha um descritor.
   A linha final faz o cache de alocação de memória onde kmem_cache é o gerenciamento de memória eficiente do Kernel Linux.

   Na prática quando você clica numa pasta acontece todo esse processo - além de vários outros - e depois você abre um arquivo nessa pasta acontece todo esse processo - além de vários outros - e depois você clica... já deu para entender. Quanto mais arquivos e programas você vai abrindo mais descritores de arquivo são abertos.

   Em essência, um descritor de arquivo é uma forma abstrata de identificar um arquivo aberto permitindo ao processo realizar operações sem ter de se preocupar com o nome do arquivo físico.
   Os descritores de arquivo 0, 1 e 2 são convencionalmente associados à entrada padrão (stdin), saída padrão (stdout) e saída de erro padrão (stderr), respectivamente.
   Entrada padrão (stdin) na prática, basicamente, é quando você tem de digitar seu nome num formulário de cadastro na internet; saída padrão (stdout) é quando abre seu programa depois de clicar no ícone; saída de erro padrão (stderr) são as mensagens de erro, por exemplo, quando aparece "arquivo não encontrado".

   Os descritores de arquivo são índices para a tabela do descritor de arquivo na área u_block mantida pelo kernel para cada processo.
   Os descritores de arquivo no Linux são armazenados na memória RAM no espaço do Kernel na tabela fdtable; o que fica no disco (HD ou SD) é o arquivo em si com seu conteúdo.
   O FD, em uma analogia, pode ser como um número de protocolo que te dão quando você vai num órgão público, ele só serve enquanto você estiver ali. Daí você sai do órgão público e joga fora o papel do protocolo, porém, no órgão fica guardado esse protocolo por um tempo: esse é o cache do descritor de arquivo (kmem_cache).
   O Kernel, depois que você fecha um programa, um arquivo, etc, guarda, na maioria das vezes, em /tmp essa informação para que depois seja mais rápido encontrar o programa, o arquivo, etc. Mas veja bem, essa informação é o cache guardado no HD/SD, não é o descritor em si, pois todo descritor é fechado quando você fecha o arquivo. E tem cache na memória RAM e no disco HD ou SSD.
   Ao acessar o mesmo arquivo depois de fechá-lo (sem reiniciar o sistema), o sistema busca no cache em disco ou na RAM para ver se tem essa informação e, tendo ou não, ele abre um novo descritor de arquivo na RAM de qualquer maneira.
   O que fica no disco são os arquivos de verdade, não essas informações temporárias chamadas "descritores de arquivo".
   Quando você reinicia a máquina essa informação no cache desaparece, por isso os programas, arquivos, etc, demoram um pouco mais para abrir.
   Quando você desliga a máquina por um bom tempo as coisas demoram mais para iniciar, pois até a memória RAM perdeu as informações.
   O reinicio "a quente" é o popular reinicio em si e o reinicio "a frio" é o popular desligamento da máquina.

   Lembrando que "cache" é quando você copia ou mantém no lugar certo o que você mais usa para ganhar tempo.
   Por exemplo, você deixa a escova e a pasta de dentes no "cache" do armário do banheiro e não na gaveta de talheres da cozinha ou na gaveta de congelados da geladeira.
   Suas chaves você costuma deixar perto da porta ou no chaveiro da cintura na calça, ou no seu bolso, na sua bolsa, etc.
   A idéia de "cache" em informática é evitar acessar "coisas lentas" umas em relação a outras, por exemplo, o acesso à memória RAM é mais rápido do que o acesso ao disco, então é melhor guardar em cache na RAM, contudo, a RAM tem menos espaço do que o disco e, além disso, é memória de acesso aleatório e temporário, então o sistema tem de lidar com isso e faz cache no disco o que é do disco e cache na RAM o que é da RAM; vai da programação otimizar essa parte e nisso o Linux é imbatível!

   Fazendo uma abstração: sua casa é o hardware e sua mente é o sistema tentando otimizar sua casa.
   Quando você larga suas chaves num lugar aleatório (randômico) e depois não lembra onde as deixou (não guardou um índice ou um cache porque estava distraído e não era o lugar usual das chaves) podemos dizer que deu um "bug" no sistema e você perde um tempão procurando as chaves e durante esse "tempão" você não consegue entrar em casa (não consegue acessar o hardware).

   Um descritor de arquivo ocupa, em média, uns 170 bytes na RAM. Mil descritores abertos ocuparão ~170 KB.

   Vamos ver mais na prática ainda.

Abra o terminal.
Crie o arquivo:
$ sudo vim descreve.sh
Utilizei o vim, você use teu editor preferido.

Coloque dentro:

#!/bin/bash

PID=$1
FD_COUNT=$(ls /proc/$PID/fd | wc -l)
MEM_ESTIMATE=$(($FD_COUNT * 170))

echo "Processo $PID tem $FD_COUNT descritores abertos"
echo "Estimativa de memória: $MEM_ESTIMATE bytes (~$(($MEM_ESTIMATE / 1024)) KB)"

Salve e saia.
$ sudo chmod +x descreve.sh

Para ver o pid temos várias maneiras.

$ pidof nome_processo

$ pidof apache2
1020 1019 1018 1017 1016 1015

Ou use o top ou htop:
$ top
top - 21:53:30 up 3:04, 1 user, load average: 0,21, 0,15, 0,14
Tarefas: 312 total, 1 em exec., 311 dormindo, 0 parado, 0 zumbi
%CPU(s): 3,3 us, 1,7 sy, 0,0 ni, 95,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st
MB mem : 31752,7 total, 26776,2 free, 3672,2 used, 1808,3 buff/cache
MB swap: 1907,0 total, 1907,0 free, 0,0 used. 28080,5 avail mem
Máx. de tarefas = 0, alterar para (0 é ilimitado) q
PID USUARIO PR NI VIRT RES SHR S %CPU %MEM TEMPO+ COMANDO
2104 aristot+ 20 0 4333536 317508 138132 S 7,3 1,0 2:52.19 cinnamon
4693 aristot+ 20 0 1392,1g 218908 132792 S 7,3 0,7 7:40.18 chrome

Vamos ver o Cinnamon.
$ sudo ./descreve.sh 2104
Processo 2104 tem 43 descritores abertos
Estimativa de memória: 7310 bytes (~7 KB)

Agora o Chrome:
$ sudo ./descreve.sh 4693
Processo 4693 tem 52 descritores abertos
Estimativa de memória: 8840 bytes (~8 KB)

   E assim você faz para cada PID que for do seu interesse.

   Para ver o PID do próprio top você terá de abrir outra janela do terminal:
5832 aristot+ 20 0 11804 5532 3364 R 0,3 0,0 0:00.03 top

$ sudo ./descreve.sh 5852
Processo 5852 tem 6 descritores abertos
Estimativa de memória: 1020 bytes (~0 KB)

   Para ver o PID do shell em uso (bash, sh, etc):
$ echo "O PID do Shell é $$"
O PID do Shell é 5864

$ sudo ./descreve.sh 5864
Processo 5864 tem 4 descritores abertos
Estimativa de memória: 680 bytes (~0 KB)

   Para ver tudo:
$ sudo prlimit --pid 2040
RESOURCE     DESCRIPTION                                                    SOFT                 HARD             UNITS
AS                     limite de espaço de endereços                            ilimitado             ilimitado         bytes
CORE                tamanho máximo de arquivo do núcleo              0                         ilimitado         bytes
CPU                  Tempo da CPU                                                    ilimitado              limitado          segundos
DATA                 tamanho máximo de dados                                 ilimitado              ilimitado         bytes
FSIZE                tamanho máximo de arquivo                               ilimitado             limitado           bytes
LOCKS              número máximo de travas de arquivo mantidos ilimitado              ilimitado          travas
MEMLOCK espaço máximo de endereço travado na memória    4161884160       4161884160   bytes
MSGQUEUE máximo de bytes nos módulos POSIX                    819200               819200           bytes
NICE prioridade máxima de nice permitida                                   0                         0
NOFILE número máximo de arquivos abertos                                         1024        1048576         arquivos
NPROC número máximo de processos                                        126639               126639           processo
RSS tamanho máximo de conjunto residente                               ilimitado               ilimitado         bytes
RTPRIO prioridade máxima de tempo real 0 0
RTTIME tempo limite para tarefas em tempo real                        ilimitado                ilimitado        microssegundos
SIGPENDING número máximo de sinais pendentes                   126639                 126639          sinais
STACK tamanho máximo da pilha                                                8388608               ilimitado         bytes


Na saída do comando
$ lsof -p $(echo $$)
vemos os arquivos abertos pela sessão do shell.

   Repare na coluna FD (File Descriptors) os arquivos 0u, 1u e 2u.
   São, respectivamente, os descritores de arquivo stdin, stdout e stderr.
   Os descritores de arquivo não tem somente um número, também tem um nome, uma string.


Nessa imagem vemos a saída do comando
$ cat /proc/sys/fs/file-max
9223372036854775807

   Isso é coisa do famigerado Systemd:
"Após discussões com o pessoal do Kernel um sistema com memcg realmente não deveria mais precisar de limites rígidos extras para descritores de arquivo já que eles são devidamente contabilizados pelo memcg de qualquer maneira. Portanto, vamos aumentar esses valores para seus valores máximos. Isso também adiciona uma opção em tempo de compilação para desativar isso para atender aos usuários que não desejam usar o memcg.
55
Os sysctls fs.nr_open e fs.file-max agora são automaticamente elevados para os valores mais altos possíveis, pois a contabilização separada de descritores de arquivo não é mais necessária porque o memcg já os rastreia corretamente como parte da contabilização de memória. Assim, dos quatro limites para descritores de arquivo atualmente aplicados (fs.file-max, fs.nr_open, RLIMIT_NOFILE hard, RLIMIT_NOFILE soft) desativamos os dois primeiros e mantemos apenas os dois últimos.
Um conjunto de opções em tempo de compilação (-Dbump-proc-sys-fs-file-max=no e -Dbump-proc-sys-fs-nr-open=no) foi adicionado para reverter essa mudança de comportamento, o que pode ser uma opção para sistemas que desativam o memcg no kernel.
1168
Vamos aumentar fs.file-max e fs.nr_open para seus respectivos máximos. Nos Kernels atuais um grande número de descritores de arquivo não representa mais um problema de desempenho e sua memória é rastreada adequadamente pelo memcg, contá-los e limitá-los em mais duas camadas de limites é desnecessário e apenas complica as coisas. Esta função, portanto, desativa 2 dos 4 níveis de limites para descritores de arquivo e torna RLIMIT_NOLIMIT (soft + hard) os únicos que realmente importam.
1199
Arg! O kernel impõe valores máximos e mínimos em fs.nr_open, mas não sabemos exatamente quais são. A expressão pela qual o máximo é determinado depende da arquitetura e é algo que não queremos copiar para o espaço do usuário, pois depende dos detalhes de implementação do kernel. Como o kernel não nos expõe o valor máximo, só nos resta tentar e torcer. Portanto, vamos começar com INT_MAX e, em seguida, reduzir o valor pela metade até encontrarmos um que funcione. Feio? Sim, com certeza, mas APIs do kernel são APIs do kernel, então o que podemos fazer..."

   Confira aqui:

   Veremos na prática.

   fs.file-max é o número máximo de descritores de arquivo que todo o sistema Linux pode ter aberto ao mesmo tempo.
   fs.nr_open é o número máximo de descritores de arquivo que um único processo pode abrir.

   Foi esses dois que o Systemd liberou até o máximo delimitado pelo Kernel (unlimited, lembrando que 'unlimited' não significa um valor infinito).

$ cat /proc/sys/fs/file-max
9223372036854775807

$ cat /proc/sys/fs/nr_open
1048576

   O máximo delimitado pelo Kernel é o valor que aparece ali nas saídas, então vemos que, de certa maneira, o Systemd está certo em liberar esse limites, pois o Kernel já os limita.
   Isso inclui arquivos normais, sockets, pipes, etc.
   soft é o limite atual que um processo pode usar normalmente;
   hard é o limite máximo que o soft pode ser elevado (sem privilégios).
   O Soft limit pode ser alterado pelo próprio processo — até o valor de hard.
   O Hard limit só pode ser aumentado pelo root (ou com permissões elevadas - sudo, su, etc).

   Contudo, agora entenderemos na prática.
   O comando ulimit modifica limites de recursos do shell, até fechar o terminal.
$ ulimit --help
O parâmetro -S usa um limite 'soft' de recursos;
O parâmetro -H usa um limite 'hard' de recursos;
O parâmetro -u o número máximo de processos de usuário;
O parametro -n o número máximo de descritores de arquivo abertos;
O parâmetro -a todos os limites atuais são relatados

$ ulimit -S
unlimited

$ ulimit -H
unlimited

$ ulimit -u
29196

$ ulimit -n
1024

Limite Soft:
$ ulimit -Sn
1024

Limite Hard:
$ ulimit -Hn
1048576

$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 29196
max locked memory (kbytes, -l) 951984
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 29196
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

Valores padrões no Kernel do Debian 12.
$ uname -r
6.1.0-33-amd64

No arquivo do Systemd citado anteriormente vemos nas linhas 1187 e 1230, respectivamente:
r = sysctl_write("fs/file-max", t); e
r = sysctl_write("fs/nr_open", t);

onde vê-se que os valores aumentados até o máximo são aqueles constantes nos arquivos /proc/sys/fs/file-max e /proc/sys/fs/nr_open.

$ cat /proc/sys/fs/file-max
9223372036854775807

$ cat /proc/sys/fs/nr_open
1048576

Então os limites Soft e Hard ("...torna RLIMIT_NOLIMIT (soft + hard) os únicos que realmente importam...") são os que realmente importam: ulimit -Sn e ulimit -Hn.

Porém, vemos que a saída de 'ulimit -Hn' é a mesma de 'cat /proc/sys/fs/nr_open': 1048576, sendo que -Hn é o limite Hard e nr_open é o número máximo de descritores de arquivo que um único processo pode abrir.
Testei em 4 máquinas com Debian 12 e as saídas padrões foram as mesmas.
O que se entende é que o limite Hard é o número máximo de descritores de arquivo que um único processo pode abrir. Um único processo pode abrir 1.048.576 descritores de arquivo.
O limite Soft é 1024, porém, o limite Soft não é exatamente um limite mínimo, o limite Soft é um valor inicial.

No caso, limite Soft só pode ser mudado até 1048576 (saída de ulimit -Hn), mais do que isso causará um erro, pois é tratado no Kernel.

Tente colocar um valor maior do que 1048576 (saída de ulimit -Hn):
$ ulimit -n 1048576346
bash: ulimit: open files: impossível modificar limite: Operação não permitida

Como root:
# ulimit -n 10485761
-bash: ulimit: open files: impossível modificar limite: Operação não permitida

O limite Soft pode ser alterado para menos do que o limit de 1024:
# ulimit -n 10
# ulimit -Sn
10

$ ulimit -n 2
$ ulimit -Sn
2

Porém, como já foi dito isso vale só até fechar e abrir o terminal (Shell).
Depois o valor volta a 1024.

Acredito que o Systemd está certo porque se o próprio Kernel já limita os descritores de arquivo (unlimited não significa um valor infinito), não faz sentido limitar duas vezes os valores fs.nr_open e fs.file-max.
E atualmente os computadores trabalham com memória RAM generosa em relação à antigamente.
Essa limitação dos descritores de arquivo afetam somente máquinas muito antigas oque é natural, pois ninguém espera que um computador dure para sempre em relação a seu hardware.
Apesar de que os computadores de naves espaciais tem um hardware considerado obsoleto hoje e com pouca RAM, isso tem pouco a ver com descritores de arquivo, pois eles trabalham basicamente com cálculos.

Os descritores de arquivo são armazenados na memória RAM, a swappiness no disco (HD ou SD).

MODIFICANDO OS LIMITES

Execute:
$ cat /proc/sys/fs/file-nr

Exemplo da saída:
11808 0 9223372036854775807

O primeiro número é o uso atual que mostra quantos descritores (ou identificadores) de arquivo estão atualmente alocados no sistema inteiro.
O segundo valor indica o número de descritores de arquivo alocados, mas não utilizados.
O terceiro número indica o número máximo de descritores de arquivo.
O Linux Kernel 2.6 e versões posteriores sempre relatam 0 como o número de descritores de arquivo livres — isso não é um erro, significa apenas que o número de descritores de arquivo alocados corresponde exatamente ao número de identificadores de arquivo utilizados.
https://docs.kernel.org/admin-guide/sysctl/fs.html

Se o primeiro valor estiver perto do terceiro valor é hora de aumentar o número de descritores de arquivo.

1. Vendo o limite atual
$ ulimit -Sn # soft limit
1024

$ ulimit -Hn # hard limit
1048576

O limite Soft (inicial) padrão geralmente é o mesmo para as várias distribuições, o limite Hard (máximo) pode mudar.

2. Aumentar limite por processo (permanente)
$ sudo vim /etc/security/limits.conf
Adicione essas linhas no final ou descomente:

* soft nofile 1048576
* hard nofile 1048576
O * aplica pra todos os usuários.
Pode trocar o * por um nome de usuário específico, caso quiser, por exemplo:

usuario soft nofile 65536
usuario hard nofile 1048576

*O valor a ser colocado depende da sua carga de trabalho.
Como já dito, caso for desktop/laptop de uso diário/cotidiano não precisa alterar nada.

Caso estiver usando PAM — geralmente sim -, Verifique se esses arquivos existem e têm a linha "session required pam_limits.so" habilitada:

$ cat /etc/pam.d/common-session
$ cat /etc/pam.d/common-session-noninteractive

Adicione (ou descomente) a linha neles:
session required pam_limits.so
Como já dito, caso for desktop/laptop de uso diário/cotidiano não precisa alterar nada.

3. Editar fs.nr_open e fs.file-max (limites do kernel)

Temporário:
sudo sysctl -w fs.nr_open=65536
sudo sysctl -w fs.file-max=1048576

$ cat /proc/sys/fs/file-max
1048576

$ cat /proc/sys/fs/nr_open
1048576

AVISO IMPORTANTE
Não coloque o parâmetro fs.nr_open no sysctl.conf com um valor menor do que a saída de cat /proc/sys/fs/nr_open.
Caso colocar um valor menor isso travará o Systemd na primeira reinicialização tendo que acessar com um sistema Live para comentar o parâmetro e assim poder entrar no sistema navamente.

Erro com posterior travamento ao reinicializar.
[FAILED] Failed to start systemd-udevd.service - Rule-based Manager for Device Events and Files. See 'systemctl status systemd-udevd.service' for details.

Teste primeiro colocando um valor maior do que a saída de cat /proc/sys/fs/nr_open e execute:
$ sudo sysctl -p

Feche o terminal e tente abrir o terminal novamente, caso não abrir mais o terminal execute Ctrl+Alt+F1 ou F2 ou F3, etc (depende do sistema) que abrirá o login sem interface gráfica. Logue como root e comente o valor em fs.nr_open e execute sysctl -p e depois reboot:

Ctrl+Alt+F1
Logue como root.
# nano /etc/sysctl.conf
Comente o parâmetro.
Salve e saia.
# sysctl -p
# reboot

Aconselho a não mexer no parâmetro nr_open caso a saída deste já estiver num valor alto como 1048576 em relação à saída de ulimit -Sn.
Lembram que eu mencionei antes:
"Vejam bem, falei "difícil", não impossível, mas essa é uma outra discussão que não cabe agora no momento.
Veremos adiante que "malware" pode ser qualquer software que trava/prejudica o sistema, como a própria definição do limite nr_open, como veremos adiante na seção MODIFICANDO OS LIMITES > AVISO IMPORTANTE."

Permanente:
Adicione ao final do /etc/sysctl.conf:
fs.file-max=1048576

E depois aplique:
$ sudo sysctl -p

O arquivo /etc/security/limits.conf só pode definir limites de recursos para usuários que efetuam login por meio do PAM; ele não afeta os limites de recursos dos serviços do sistema.
Portanto, quando sev inicia um serviço, por exemplo, com "sudo systemctl start servico" ou "sudo service servico start" este serviço não será afetado pelas limitações em /etc/security/limits.conf.

O número máximo de descritores de arquivo disponíveis para serviços de sistemas com Systemd é determinado pelo parâmetro DefaultLimitNOFILE no arquivo /etc/systemd/system.conf ou pelo parâmetro LimitNOFILE no arquivo /usr/lib/systemd/system/<Service Name>.service.
O primeiro é uma configuração padrão global aplicada a todos os serviços do sistema enquanto que o último é um limite individual opcional para cada serviço. LimitNOFILE substituirá DefaultLimitNOFILE.

4. Se estiver usando Systemd temos duas maneiras de fazer: se quiser alterar os descritores para cada processo (programa, aplicativo, etc) com um valor específico, caso não, altere somente o arquivo /etc/systemd/system.conf.

4.1- Editar o arquivo ".service":
$ sudo systemctl edit nome-do-servico
Acrescente na posição indicada:

[Service]
LimitNOFILE=1024:1048576

Salve e saia.

4.2- Altere o arquivo /etc/systemd/system.conf
Perceba que você pode alterar nesse arquivo os vários limites de Soft e Hard para cada serviço básico: CPU, MEMLOCK, etc.
Ou altere somente o DefaultLimitNOFILE=1024:1048576 que valerá como padrão para todos os serviços controlados pelo Systemd.

Depois para o caso 4.1:
$ sudo systemctl daemon-reload
$ sudo systemctl restart nome-do-servico

Para o caso 4.2:
$ sudo systemctl daemon-reexec
$ sudo systemctl daemon-reload

5. Para verificar se um serviço ou processo está com o novo limite:
$ cat /proc/<PID>/limits

Ou, com lsof:
$ lsof -p <PID> | wc -l

Para ver o PID:

$ pidof nome_processo

$ pidof apache2
1020 1019 1018 1017 1016 1015

Ou
$ top
ou
$ htop
ou
$ ps aux | grep nome_servico
$ ps aux | grep java
kluster 37360 0.0 0.0 6352 2076 pts/0 S+ 08:47 0:00 grep java

O PID é o primeiro número da linha, no caso: 37360.

$ cat /proc/37360/limits
cat: /proc/37360/limits: Arquivo ou diretório inexistente

$ lsof -p 37360 | wc -l
0


PID Pulseaudio: $ cat /proc/1298/limits


INFORMAÇÕES EXTRAS

Para verificar os limites de cada processo com um PID no diretório /proc:
$ cat /proc/<PID>/limits

Exemplo:
$ ps aux | grep pulseaudio
kluster 1298 0.0 0.3 842804 29244 ? S<sl 07:49 0:00 /usr/bin/pulseaudio --daemonize=no --log-target=journal
kluster 121329 0.0 0.0 6352 2180 pts/0 S+ 11:11 0:00 grep pulseaudio

Temos dois PIDs, daremos cat em cada um:
$ cat /proc/121329/limits
cat: /proc/121329/limits: Arquivo ou diretório inexistente


$ cat /proc/1298/limits

Vemos que o PID do pulseaudio tem um diretório <PID> dentro de /proc, enquanto que o outro PID (que não é do pulseaudio, mas do grep) não criou um diretório em /proc, o que é óbvio, pois é um comando do shell e é temporário.
Podemos ver que cada coisa que se faz no Linux cria um PID e, no mínimo, um descritor de arquivo que são "apagados" depois de acordo com as suas atribuições.

Veja:
$ ps aux | grep pulseaudio
kluster 1298 0.0 0.3 842804 29244 ? S<sl 07:49 0:00 /usr/bin/pulseaudio --daemonize=no --log-target=journal
kluster 131308 0.0 0.0 6352 2168 pts/0 S+ 11:27 0:00 grep pulseaudio

Já foi criado um novo PID para o 'grep pulseaudio' enquanto que o PID do Pulseaudio permanece o mesmo.

Agora vamos entrar no diretório /proc:
$ cd /proc
$ ls
1 1358 16 26 46383 62693 8215 cgroups locks
10 1364 160 262 46396 631 8219 cmdline meminfo
10261 1367 161 2690 47 642 8227 consoles misc
10271 1372 162 29 48 649 8235 cpuinfo modules
102741 1386 163 291 4828 65 8487 crypto mounts
Coloquei somente as 5 primeiras linhas.

Entrando num diretório PID:
$ cd 1372
$ ls

Entrando em um diretório /proc/pid.


Vendo o conteúdo do arquivo limits.

Vemos que a trama se complica, pois tem vários limites Soft e vários limites Hard.

Aqueles limites Soft e Hard que podem ser definidos pelo usuário e/ou pelo root são limites genéricos máximos.

Pode verificar também com:
$ prlimit --pid <PID> --nofile

Exemplo:
$ prlimit --pid 1298 --nofile
RESOURCE DESCRIPTION                                     SOFT     HARD     UNITS
NOFILE        número máximo de arquivos abertos    256        256          arquivos




SWAPPINESS


Swappiness é o processo de troca responsável por controlar a quantidade de memória RAM e swap que será utilizada pelo sistema. É uma variável contida no código fonte do kernel.
O padrão do kernel é vm.swappiness=60. Este valor geralmente não é tão ruim para a maioria das cargas de trabalho, mas é difícil ter um padrão geral que se adapte a todos, pois a swappiness depende da quantidade de RAM física, depende do disco (se é HD ou SD), depende do uso do computador, etc.
A RAM é alocada em espaços chamados "páginas" que têm um tamanho fixo. Esse tamanho é determinado pelo kernel na inicialização que detecta a arquitetura do computador.
Normalmente o tamanho da página em um computador Linux é de 4 Kbytes.

$ getconf PAGESIZE
4096

Swappiness é também uma proporção de quão custoso é recuperar e restaurar memória anônima em comparação com a memória de arquivo para seu hardware e carga de trabalho . Quanto menor o valor mais você diz ao kernel que páginas anônimas acessadas com pouca frequência são caras para trocar para fora e para dentro em seu hardware. Quanto maior o valor mais você diz ao kernel que o custo de trocar páginas anônimas e páginas de arquivo é semelhante em seu hardware.
Memória de Arquivo é, de modo geral, o cache de dados e metadados responsáveis por armazenar o código de cada processo em execução no computador em uma área de troca reservada (swap) do armazenamento secundário, como uma unidade de disco rígido (HD) ou uma unidade de estado sólido (SD).
Memória Anônima, de modo geral, são as alocações de memória feitas dentro desse código de cada processo, por exemplo, quando uma nova memória é alocada ela não é apoiada por nada, ou seja, não está ligada a nenhum processo, por isso são chamadas de anônimas.
Existem outros tipos de memória — memória compartilhada, memória slab, memória de pilha do kernel, buffers e similares — mas a memória anônima e a memória de arquivo são as mais conhecidas e fáceis de entender e se aplicam igualmente a esses outros tipos também.
"Memória anônima", no contexto da RAM, refere-se a uma área de memória que o sistema operacional utiliza para fins de armazenamento temporário (no caso no HD ou SD), sem que seja associada a um arquivo ou processo específico. É utilizada quando é necessário alocar grandes blocos de memória geralmente para evitar a fragmentação do heap (área de memória principal).
Paginas anônimas não têm suporte ao sistema de arquivos e devem permanecer na memória enquanto forem necessárias para um programa, a menos que haja espaço de swap para armazená-las.

Temos ainda as variáveis anon_prio que é definida como o valor de swappiness do Linux e a variável file_prio que é definida como 200 menos o valor da anon_prio.
file_prio é a disposição do sistema em liberar páginas de arquivo e anon_prio é a disposição do sistema em liberar páginas anônimas.
Esses dois valores alimentam um algoritmo complexo que determina se o kernel Linux é executado com preferência para recuperar/liberar páginas de arquivo ou páginas anônimas.
O valor da swappiness depende do hardware, da carga de trabalho, do tipo de disco (HD ou SD) e se o seu computador é um desktop ou um servidor e, obviamente, esta não será uma configuração única para todos.
Exemplo: colocando a swappiness como 20 teremos que anon_prio será 20 e file_prio será 180 (200-20).
O valor da swappiness fica entre os limites 0-100. Colocando a swappiness como 100 teremos um equilíbrio com os dois valores como 100.

Por que 60, 100 e 200?
São valores convencionados pelos desenvolvedores de acordo com o bom senso.
A swappinnes (junto com os descritores) às vezes são supervalorizados como se fossem um truque mágico que fará o computador sair voando.

Da página oficial do Kernel Linux, versão estável no momento:

Arquivo vmscan.c do código fonte do Kernel Linux, a partir da linha 200 vemos o padrão do Kernel setado em 60:

/*
* From 0 .. MAX_SWAPPINESS. Higher means more swappy.
*/
int vm_swappiness = 60;

Arquivo vmscan.c do código fonte do Kernel Linux, a partir da linha 2469:

/*
* Calculate the pressure balance between anon and file pages.
*
* The amount of pressure we put on each LRU is inversely
* proportional to the cost of reclaiming each list, as
* determined by the share of pages that are refaulting, times
* the relative IO cost of bringing back a swapped out
* anonymous page vs reloading a filesystem page (swappiness).
*
* Although we limit that influence to ensure no list gets
* left behind completely: at least a third of the pressure is
* applied, before swappiness.
*
* With swappiness at 100, anon and file have equal IO cost.
*/
total_cost = sc->anon_cost + sc->file_cost;
anon_cost = total_cost + sc->anon_cost;
file_cost = total_cost + sc->file_cost;
total_cost = anon_cost + file_cost;

ap = swappiness * (total_cost + 1);
ap /= anon_cost + 1;

fp = (MAX_SWAPPINESS - swappiness) * (total_cost + 1);
fp /= file_cost + 1;

Tradução literal:
"A quantidade de pressão que aplicamos em cada LRU é inversamente proporcional ao custo de recuperação de cada lista, conforme determinado pela proporção de páginas que estão sendo redefinidas, vezes o custo relativo de E/S para trazer de volta uma página anônima trocada versus recarregar uma página do sistema de arquivos (troca).
Embora limitemos essa influência para garantir que nenhuma lista seja completamente deixada para trás: pelo menos um terço da pressão é aplicada, antes da troca.
Com a swappiness em 100, anon e file têm o mesmo custo de E/S."

Resumindo: quanto menor o valor da swappiness menos a swap será utilizada não importando a quantidade total da swap; quanto maior o valor da swappiness mais ela será utilizada não importando a quantidade total da swap.
Definir vm.swappiness como zero impedirá que o Kernel remova páginas anônimas em favor de páginas do cache de arquivos e mais restrito será o uso da swap.
Swap com HD ou com SD faz diferença também no desempenho, pois um HD é um gargalo num computador e quanto mais precisa acessar a swap no HD mais perderá em desempenho.
Em computadores com SDs, com bastante memória RAM física e swap generosa pode-se colocar a swappiness como 100 que será um bom valor.
O valor padrão em 60 ajusta-se aos HDs e SDs.
Para entender mais um pouco: usuários de laptop/desktop que usam muito a hibernação/suspensão, o arquivo de swap deve ter pelo menos o tamanho da sua RAM física e a swappiness colocada em 100 é uma boa prática.

Outro exemplo: em um cluster com máquinas antigas com HD e apesar de ser sem interface gráfica nos Nós, coloca-se a swap com 10 (dez) GB no particionamento e a vm.swappiness como 20, pois cada Nó teria, por exemplo, 4GB de RAM física, além disso, a carga de trabalho utilizada na máquina também influencia.

Valor próximo de 0: Evita ao máximo usar swap.
Valor de 100: Usa swap com frequência para liberar RAM.
Valor padrão: 60

Verificando a RAM:
$ free -m
total usada livre compart. buff/cache disponível
Mem.: 7437 2019 4097 67 1640 5418
Swap: 14304 0 14304

Nessa máquina tem 4097 MB livres de um total de ~8GB.
Deve-se levar em conta a quantidade de memória RAM e o número de processos (programas, arquivos, etc) que você usará cotidianamente.
Quanto mais RAM livre menos swappiness você precisa, porém, deve-se levar em conta o tamanho da swap (partição de troca).
Desde uns 5 anos para cá eu coloco em todo e qualquer particionamento Linux, no mínimo, 5GB de Swap não importando a quantidade de RAM física.
Como já foi dito, o valor da swappiness é bastante específico para cada máquina, porém, caso seu computador seja um desktop/laptop de uso pessoal regular, deixe no padrão.

Para saber um pouco mais sobre a necessidade de Swap leia este artigo:

Deixo uma tradução livre do resumo:

"1. Ter swap é uma parte razoavelmente importante de um sistema que funciona bem. Sem swap torna-se mais difícil alcançar um gerenciamento de memória sensato.
2. A swap geralmente não visa obter memória de emergência, mas sim tornar a recuperação de memória igualitária e eficiente. Na verdade, usá-la como "memória de emergência" geralmente é prejudicial.
3. Desabilitar a swap não impede que a E/S de disco se torne um problema em caso de contenção de memória. Em vez disso simplesmente transfere a sobrecarga de E/S de disco de páginas anônimas para páginas de arquivo. Isso não só pode ser menos eficiente já que temos um conjunto menor de páginas para selecionar para recuperação, como também pode contribuir para esse estado de alta contenção.
4. O swapper em kernels anteriores à versão 4.0 apresenta muitas armadilhas e contribuiu para a percepção negativa de muitas pessoas sobre a swap devido à sua ânsia excessiva em trocar páginas. Em kernels posteriores à versão 4.0 a situação é significativamente melhor.
5. Em SSDs a troca de páginas anônimas e a recuperação de páginas de arquivo são essencialmente equivalentes em termos de desempenho e latência. Em discos giratórios mais antigos, as leituras de troca são mais lentas devido a leituras aleatórias, portanto, uma configuração vm.swappiness mais baixa faz sentido (continue lendo para saber mais sobre vm.swappiness).
6. Desabilitar a swap não previne comportamentos patológicos em situações próximas ao fim da vida útil (OOM), embora seja verdade que tê-la pode prolongá-la. Independentemente de o eliminador global de OOM ser invocado com ou sem swap, ou ter sido invocado mais cedo ou mais tarde, o resultado é o mesmo: você fica com um sistema em um estado imprevisível. A ausência de swap não evita isso.
7. Você pode obter melhor comportamento de swap sob pressão de memória e evitar thrashing utilizando memory.low no cgroup v2.

Se você procurar descrições sobre a finalidade da swap no Linux inevitavelmente encontrará muitas pessoas falando sobre ela como se fosse apenas uma extensão da RAM física para uso em emergências. Por exemplo, aqui está uma postagem aleatória que recebi como um dos principais resultados ao pesquisar "o que é swap" no Google:

'Swap é essencialmente memória de emergência; um espaço reservado para momentos em que o sistema precisa temporariamente de mais memória do que a disponível na RAM. É considerado "ruim" no sentido de que é lenta e ineficiente e se o seu sistema precisa usar swap constantemente, obviamente não tem memória suficiente. […] Se você tem RAM suficiente para atender a todas as suas necessidades e não espera esgotá-la, então você deve estar perfeitamente seguro sem swap.'

Para deixar claro, não culpo quem postou este comentário pelo conteúdo da postagem – isso é aceito como "conhecimento comum" por muitos administradores de sistemas Linux e é uma das coisas mais prováveis que você ouvirá de alguém se pedir para falar sobre swap. Infelizmente, porém, isso também é um mal-entendido sobre o propósito e o uso do swap, especialmente em sistemas modernos.
A swap é principalmente um mecanismo para igualdade de recuperação, não para "memória extra" emergencial.
A swap não é o que torna seu aplicativo lento – entrar em disputa geral de memória é o que torna seu aplicativo lento.

A realidade é que a maioria das pessoas não tem uma noção clara do que seu hardware exige, então não é trivial ajustar o valor da swappiness apenas por instinto – isso é algo que você precisa testar usando valores diferentes. Você também pode dedicar um tempo avaliando a composição da memória do seu sistema e dos principais aplicativos e seu comportamento sob recuperação moderada de memória."

Alterando:
$ sudo vim /etc/sysctl.conf

Acrescentar no final:
vm.swappiness=XX # No lugar de XX você coloca o valor mais adequado para você (20, 50, 100, etc)

Salve e saia.

Carregando as configurações:
$ sudo sysctl -p

Reinicie o computador.

Para ver a alteração da swappiness, execute:
$ sudo sysctl vm.swappiness

Referências


sábado, 19 de abril de 2025

Instalação e Configuração do Chrony

c h r o n y


   Veremos duas maneiras de instalar o Chrony (como todo programa): instalação semi-automática e manual.
   O Chrony (NTP/NTS) é uma ferramenta que sincroniza o tempo em redes, servidores e desktops funcionando como uma implementação do Network Time Protocol (NTP). Ele pode sincronizar o relógio do sistema com servidores NTP, relógios de referência (por exemplo, receptor GPS) e entrada manual usando wristwatch e teclado. Ele também pode operar como um servidor NTPv4 (RFC 5905) e um peer para fornecer um serviço de sincronização de tempo a outros computadores na rede.
Link ao final.

   O Chrony é indicado pelo ntp.br:
"O Chrony é uma implementação moderna e versátil do NTP. É seguro e confiável e recomenda-se seu uso para as funções de cliente e servidor.
Em particular, para a função de cliente NTP, o Chrony é a principal recomendação do NTP.br . Isso por diversas razões: se configurado como aqui sugerido o chrony vai se comportar apenas como um cliente NTP, ou seja, não vai abrir um socket na porta 123 UDP e atender requisições."
Link ao final.

INSTALANDO PELO GERENCIADOR DE PACOTES

   No Debian, Ubuntu, Mint, Kali:
$ sudo apt install chrony

   No Red Hat e Fedora:
$ dnf install -y chrony

   OpenSuse:
$ zypper install chrony

   No Debian 12, os repositórios tem a versão 4.3.2 e o Chrony está na versão 4.6.1.
   Fica à sua escolha, pois as configurações depois são iguais.
   Deixarei aqui a instalação manual, mesmo passando um perrengue desgraçado porque o Chrony instalado manualmente não instala por padrão alguns arquivos necessários e, além disso, não tem "make uninstall", porém, isso não é exclusivo do Chrony. Alguns desenvolvedores optam por não colocar "make uninstall" porque não tem como saber em qual diretório o usuário instalará o programa e o diretório padrão de alguns arquivos muda de acordo com cada distribuição, e mesmo que na instalação automática o pacote já vem pronto com as configurações para cada distribuição, ainda assim pode mudar de acordo com uma nova versão.

   A instalação manual parece trabalhosa, mas depois que se "pega o jeito" ela flui naturalmente e só demora o tempo da compilação (make) porque a digitação dos comandos é simples. Como aprendizado todo mundo deveria fazer pelo menos uma vez. É trabalhoso, mas não é difícil!
   Muitos programas, basicamente, quando você vai atualizar basta executar "make uninstall" (os que trazem ele) estando dentro do diretório da instalação atual e instalar a versão mais recente estando dentro do diretório dessa nova versão.
   Os programas que não trazem "make uninstall" delete o diretório da instalação atual, faça uma busca e delete os arquivos e diretórios remanescentes, crie o diretório da nova versão, baixe a versão mais recente, descompacte, entre no diretório e execute "./configure". "make", "make install".
   Muita gente se engana ao pensar que na instalação manual depois fica um monte de arquivos como lixo no sistema, porém, quando você utiliza um gerenciador de pacotes (apt, dnf, zypper, etc) também ficam pacotes para trás na desinstalação e isso não é culpa dos gerenciadores de pacotes e/ou dos desenvolvedores porque, como já foi dito, não tem como adivinhar em qual diretório o usuário instalará o programa e o diretório padrão muda nas distribuições. E mesmo que na instalação [semi]-automática o pacote já vem pronto com as configurações para cada distribuição, ainda assim pode mudar de acordo com uma nova versão.
   Em todo e qualquer sistema sempre ficam arquivos para trás ocupando espaço, por isso é necessário fazer uma limpeza no sistema de vez em quando.


INSTALAÇÃO MANUAL

Instalação manual (Debian 12 - esta instalação serve de maneira geral para qualquer programa a ser instalado manualmente)

   Com essa instalação manual você evita erros como:
No NTS support;
Could not read valid frequency and skew from driftfile /var/lib/chrony/drift;
Could not open /var/log/chrony/tracking.log : Permission denied;
501 Not authorised; etc.

IMPORTANTE
   Na instalação manual de qualquer programa aconselho sempre primeiro a desinstalar a versão anterior, pois pode acontecer de ter mudanças profundas de uma para outra versão e isso pode dar problemas.
   Ao final tem uma lista de arquivos e diretórios para remover em caso de desinstalação.

   Instalando dependências:
$ sudo apt update
$ sudo apt install pkg-config build-essential libc6 libtomcrypt1 libtomcrypt-dev libcap-dev golang-github-seccomp-libseccomp-golang-dev gnutls-bin libgnutls28-dev openssl wget

   Criando o usuário:
$ sudo useradd chrony

   Criando o diretório em /opt (Debian 12)

Entre no diretório:
$ cd /opt

O Debian não toca nos diretórios /opt e /usr/local cujos são próprios para instalações de programas que não vem por padrão. O mais aconselhável é o /opt,

   Criando o diretório geral para downloads, descompactação, bkp, etc:
$ sudo mkdir croni

   Criando o diretório para instalação:
$ sudo mkdir chrony

$ cd croni
$ sudo wget https://chrony-project.org/releases/chrony-4.6.1.tar.gz

   ou acesse o site
   e faça o download da última versão.

$ ls
$ sudo tar -xf chrony-4.6.1.tar.gz
$ cd chrony-4.6.1

   Configurando e instalando no diretório /opt/chrony estando dentro de /opt/croni/chrony-4.6.1:

--prefix=/opt/chrony - diretório onde será instalado;
--enable-scfilter - suporte ao recurso de computação segura do Linux (seccomp);
--enable-nts - suporte a Network Time Security (NTS) para sincronização de horário segura.
$ sudo ./configure --prefix=/opt/chrony --enable-scfilter --enable-nts
$ sudo make
$ sudo make install
$ sudo apt update


CONFIGURANDO

   Criando os diretórios e arquivos necessários e setando permissões e proprietários:

$ cd /var/lib
   O diretório /var/lib/chrony é o único que essa instalação cria, mas temos que alterar o proprietário:
$ sudo chown -R chrony chrony
$ cd
$ sudo mkdir /var/log/chrony
$ cd /var/log
$ sudo chown -R chrony chrony
$ cd
$ sudo touch /etc/chrony.keys
$ sudo chown chrony /etc/chrony.keys
$ sudo chmod 400 /etc/chrony.keys

  Configurando (utilizo o vim, você utilize teu editor de texto predileto):
$ sudo vim /etc/chrony.keys
   Coloque dentro:

1 SHA256 b1gS3cr3tKey123!
2 SHA256 Ch4v&S&cr3t4ch4v3?

   Aconselho a mudar os caracteres e colocar sua própria combinação de caracteres.
   A parte "1 SHA256"e "2 SHA256" deixe assim. Pode colocar mais chaves caso queira: "3 SHA sdFJ3dftj&*cDnHHmSA!", etc. Coloque um máximo de 4 chaves. Não há um limite de chaves, mas é aconselhado não muitas chaves.
   No entanto, a chave utilizada para autenticação deve ter um ID (por exemplo, b1gS3cr3tKey123!) sem sinal no intervalo de 1 a 2^32-1 (2 elevado na 32 menos 1).
   A função hash padrão é MD5, que é sempre suportada.
   Se o chronyd foi criado com suporte habilitado para hash usando uma biblioteca de criptografia (nettle, nss ou libtomcrypt), as seguintes funções estão disponíveis: MD5, SHA1, SHA256, SHA384 e SHA512. Dependendo da biblioteca e da versão que o chronyd está usando algumas ou todas das seguintes funções e/ou criptografias também podem estar disponíveis: SHA3-224, SHA3-256, SHA3-384, SHA3-512, RMD128, RMD160, RMD256, RMD320, TIGER e WHIRLPOOL .

   Copiando o chrony.conf porque nessa instalação ele não cria por padrão:
$ sudo cp /opt/croni/chrony-4.6.1/examples/chrony.conf.example2  /etc/chrony.conf
$ sudo vim /etc/chrony.conf

   Deixe como abaixo:

# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (https://www.pool.ntp.org/join.html).
cmdallow 127.0.0.1
local stratum 2
#pool pool.ntp.org iburst
server a.st1.ntp.br iburst nts
server b.st1.ntp.br iburst nts
server c.st1.ntp.br iburst nts
server d.st1.ntp.br iburst nts

# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift

# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 0.1 3

# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
#sourcedir /run/chrony-dhcp
#sourcedir /etc/chrony/sources.d

# Enable hardware timestamping on all interfaces that support it.
#hwtimestamp *

# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2

# Allow NTP client access from local network.
#allow 192.168.0.0/16

# Serve time even if not synchronized to a time source.
#local stratum 10

# Require authentication (nts or key option) for all NTP sources.
#authselectmode require

# Specify file containing keys for NTP authentication.
keyfile /etc/chrony.keys

# Save NTS keys and cookies.
ntsdumpdir /var/lib/chrony

# Insert/delete leap seconds by slewing instead of stepping.
leapsecmode step
leapsectz right/UTC

# Set the TAI-UTC offset of the system clock.
#leapseclist /usr/share/zoneinfo/leap-seconds.list

# Specify directory for log files.
logdir /var/log/chrony

# Select which information is logged.
log measurements statistics tracking

# Erro máximo tolerado em ppm em relação aos servidores
maxupdateskew 10

   Salve e saia.

   É uma configuração própria para sincronizar a contento o relógio do sistema, caso quiser adapte para você.

   Criando o UNIT para o famigerado Systemd (utilizei o vim, você utilize teu editor preferido):
$ sudo vim /etc/systemd/system/chrony.service

[Unit]
Description=Chrony NTP/NTS
After=syslog.target ntpdate.service sntp.service ntpd.service
Conflicts=ntpd.service systemd-timesyncd.service

[Service]
Type=notify
PIDFile=/run/chrony/chronyd.pid
ExecStart=/opt/chrony/sbin/chronyd -f /etc/chrony.conf -u chrony
ExecStop=/opt/chrony/sbin/chronyd

[Install]
WantedBy=multi-user.target
Alias=chrony.service

   Salve e saia.
   Veja bem, caso você executou a instalação em outro lugar que não /opt/chrony, ajuste os caminhos no arquivo acima.


CONFIGURAÇÕES FINAIS

   Reconfigurando, habilitando e iniciando:
$ sudo systemctl daemon-reexec
$ sudo systemctl daemon-reload
$ sudo systemctl enable chrony
$ sudo systemctl start chrony
$ sudo systemctl status chrony


Caso tenha feito tudo certo estará como na imagem acima.
A mensagem em amarelo é porque foi a primeira sincronização, depois ela some.

Pode sempre verificar os servidores atuais em
   A título de verificação acesse o site e verifique se no lado direito aparece:

"HORA CERTA XX:XX:XX SUA HORA XX:XX:XX UTC-3
A hora do seu computador está correta".

   Caso não estiver, dê um refresh no site e se persistir refaça as configurações do arquivo /etc/chrony.conf com calma.
   Os servidores "a.ntp.br, b.ntp.br", etc, são IPv6, caso quiser acrescentar, mas veja que não tem o NTS (Network Time Security) que é uma extensão de segurança do protocolo NTP (Network Time Protocol).

   Criando 'aliases':
$ cd
$ vim apelidos (dê o nome que quiser)
   Coloque dentro:

alias chronyc='/opt/chrony/bin/chronyc'
alias chronyd='/opt/chrony/sbin/chronyd'
alias chronycaut='sudo /opt/chrony/bin/chronyc -N authdata'
alias chronycmks='sudo /opt/chrony/bin/chronyc makestep'

   Salve e saia.

$ vim .bashrc

   Acrescente no final:

if [ -f apelidos ]; then
. apelidos
fi

   Salve e saia.
$ source .bashrc

   Testando:
$ chronyc
$ chronyd --version
$ chronycaut
$ chronyc tracking

Para os 4 comandos é necessário criar 'aliases', pois a instalação é manual.
Os comandos 'chronyc tracking', 'chronyc sources -v', além de outros, são reconhecidos automaticamente.
Caso aparecer mais algum comando que não for reconhecido basta acrescentar no arquivo de 'aliases'.
Serve para qualquer instalação de qualquer programa no Linux.

   Na página de FAQ do Chrony:

"4.2. Continuo recebendo o erro: 501 Não Autorizado
Este erro indica que o chronyc enviou o comando para o chronyd usando um soquete UDP em vez do soquete de domínio Unix (por exemplo, /var/run/chrony/chronyd.sock), o que é necessário para alguns comandos. Por motivos de segurança apenas os usuários root e chrony têm permissão para acessar o soquete.
Também é possível que o soquete não exista. O chronyd não criará o soquete se o diretório tiver um proprietário ou permissões incorretas. Nesse caso deve haver uma mensagem de erro do chronyd no log do sistema."

   É melhor criar aliases do que mudar permissões e proprietários, nesse caso.

E assim finalizamos a instalação e configuração do Chrony.

   Para reiniciar: sudo systemctl restart chrony
   Parar: sudo systemctl stop chrony
   Status: sudo systemctl status chrony

   Para recomeçar do zero:
$ cd /opt/croni
$ sudo rm -rf chrony-4.6.1
$ sudo rm -rf /opt/chrony
$ sudo mkdir /opt/chrony
$ sudo tar -xf chrony-4.6.1.tar.gz
$ cd chrony-4.6.1
$ sudo ./configure --prefix=/opt/chrony --enable-scfilter --enable-nts
$ sudo make
$ sudo make install
e proceda com as configurações.

   Caso queira remover completamente:
/opt/croni/
/etc/chrony.conf
/etc/chrony.keys
/etc/systemd/system/chrony.service
/var/log/chrony
/var/lib/chrony
/etc/systemd/system/multi-user.target.wants/chrony.service
/etc/systemd/system/chrony.service
/run/chrony
/opt/chrony
/opt/croni
/sys/fs/cgroup/system.slice/chrony.service

   Faça uma busca:
$ sudo find / | grep chrony | less

   Para remover o usuário:
$ sudo deluser chrony

Projeto Chrony:

   Recomendações e comparações do ntp.br:

Referências


quinta-feira, 17 de abril de 2025

Debian 12 -- Errata - Correções Importantes de Segurança



Deparei-me hoje com o seguinte site:

referindo-se a algumas correções de segurança no Debian 12, algumas vindas desde julho de 2023, como podem ver no site oficial do Debian.


# Atualizações propostas para a versão 12
deb https://deb.debian.org/debian bookworm-proposed-updates main contrib non-free-firmware non-free

Resolvi colocar esse repositório no arquivo /etc/apt/sources.list e executar "sudo apt update" acreditando que nada aconteceria.

Para minha surpresa, em um computador veio:

Construindo árvore de dependências... Pronto
Lendo informação de estado... Pronto
62 packages can be upgraded. Run 'apt list --upgradable' to see them.

e em outro:

Construindo árvore de dependências... Pronto
Lendo informação de estado... Pronto
41 packages can be upgraded. Run 'apt list --upgradable' to see them.

sendo que os dois tem Debian 12 instalados esse ano e sempre atualizados.
Depois executei "sudo aptitude safe-upgrade (ou sudo apt upgrade)" e os pacotes foram atualizados.

A pergunta é: como tinham todas essas atualizações de segurança desde julho de 2023?

Aconselho a quem tem o Debian 12 que execute esse procedimento o mais breve possível.