cgroups (Português)

Artigos relacionados
Linux Containers
systemd-nspawn
Docker
limits.conf
Status de tradução:
Esse artigo é uma tradução de
Cgroups
. Data da última tradução: 2023-03-11. Você pode ajudar a sincronizar a tradução, se houver
alterações
na versão em inglês.
Grupos de Controle
, ou em inglês
Control groups
(ou também conhecido por
cgroups
) é um recurso para gerenciamento, restrição e auditoria de grupos de processos fornecido pelo kernel Linux. Comparado com outros gerenciamentos como pelo comando
nice(1)
ou por configurações em
/etc/security/limits.conf
, cgroups é mais flexível por conseguir operar em (sub)conjuntos de processos (usável com diferentes usuários de sistema).
O controle de grupos pode ser acessado por diversas ferramentas:
Usando diretivas nos arquivos unit do
systemd
para especificar limites de serviços e slices;
Acessando o sistema de arquivos
cgroup
diretamente;
Por via de
cgcreate
,
cgexec
e
cgclassify
(parte dos pacotes
libcgroup-git
AUR
e
libcgroup-git
AUR
) ou similares;
Usando o serviço de controle de grupos (rules engine daemon) para automaticamente mover certos usuários/grupos/comandos para grupos (
/etc/cgrules.conf
) e
cgconfig.service
(parte dos pacotes
libcgroup-git
AUR
e
libcgroup-git
AUR
);
E através de outros softwares de virtualização como
Linux Containers
(LXC).
Em Arch Linux systemd é o método preferível e mais fácil para chamar e configurar cgroups, pois faz parte da instalação padrão.
Instalação
Tenha certeza que você possui um desses pacotes
instalados
para automatizar o controle de grupos:
systemd
- para controle de recursos de um serviço systemd.
libcgroup
AUR
,
libcgroup-git
AUR
- conjunto de ferramentas standalone (
cgcreate
,
cgclassify
, persistência via
cgconfig.conf
).
Com systemd
Hierarquia
A atual hierarquia de cgroup pode ser vista com
systemctl status
ou pelo comando
systemd-cgls
.
$ systemctl status
● myarchlinux
    State: running
     Jobs: 0 queued
   Failed: 0 units
    Since: Wed 2019-12-04 22:16:28 UTC; 1 day 4h ago
   CGroup: /
           ├─user.slice 
           │ └─user-1000.slice 
           │   ├─user@1000.service 
           │   │ ├─gnome-shell-wayland.service 
           │   │ │ ├─ 1129 /usr/bin/gnome-shell
           │   │ ├─gnome-terminal-server.service 
           │   │ │ ├─33519 /usr/lib/gnome-terminal-server
           │   │ │ ├─37298 fish
           │   │ │ └─39239 systemctl status
           │   │ ├─init.scope 
           │   │ │ ├─1066 /usr/lib/systemd/systemd --user
           │   │ │ └─1067 (sd-pam)
           │   └─session-2.scope 
           │     ├─1053 gdm-session-worker [pam/gdm-password]
           │     ├─1078 /usr/bin/gnome-keyring-daemon --daemonize --login
           │     ├─1082 /usr/lib/gdm-wayland-session /usr/bin/gnome-session
           │     ├─1086 /usr/lib/gnome-session-binary
           │     └─3514 /usr/bin/ssh-agent -D -a /run/user/1000/keyring/.ssh
           ├─init.scope 
           │ └─1 /sbin/init
           └─system.slice 
             ├─systemd-udevd.service 
             │ └─285 /usr/lib/systemd/systemd-udevd
             ├─systemd-journald.service 
             │ └─272 /usr/lib/systemd/systemd-journald
             ├─NetworkManager.service 
             │ └─656 /usr/bin/NetworkManager --no-daemon
             ├─gdm.service 
             │ └─668 /usr/bin/gdm
             └─systemd-logind.service 
               └─654 /usr/lib/systemd/systemd-logind
Encontre o cgroup de um processo
O nome de um processo do cgroup pode ser encontrado em
/proc/
PID
/cgroup
.
Por exemplo, o cgroup do shell:
$ cat /proc/self/cgroup
0::/user.slice/user-1000.slice/session-3.scope
Uso de recursos do cgroup
O comando
systemd-cgtop
pode ser usado para visualizar o uso de recursos:
$ systemd-cgtop
Control Group                            Tasks   %CPU   Memory  Input/s Output/s
user.slice                                 540  152,8     3.3G        -        -
user.slice/user-1000.slice                 540  152,8     3.3G        -        -
user.slice/u…000.slice/session-1.scope     425  149,5     3.1G        -        -
system.slice                                37      -   215.6M        -        -
Customização de cgroups
Um arquivo unit
systemd.slice(5)
pode ser usado para definir uma configuração de cgroup personalizada, do qual deve ser colocado em um diretório do systemd como
/etc/systemd/system/
. As opções de controle de recursos que podem ser atribuídas estão documentadas em
systemd.resource-control(5)
.
Este é um exemplo de um
slice unit
que pode somente permitir 30% da CPU em uso:
/etc/systemd/system/meu.slice
[Slice]
CPUQuota=30%
Lembre-se de fazer systemd
daemon-reload
para selecionar qualquer arquivo novo ou modificado em
.slice
.
Nota
Como mostrado acima, um slice permite agrupar e gerenciar recursos e processos de uma unidade (unit) do systemd.
Como serviços
Arquivo unit de serviço
Recursos podem ser especificamente direcionados em uma definição de serviço ou como
arquivo drop-in
:
[Service]
MemoryMax=1G
Neste exemplo os limites do serviço foram definidos para 1 gigabyte.
Agrupando unit em um slice
Um serviço pode ser direcionado para uma execução de slice específica em:
[Service]
Slice=
meu.slice
Como root
systemd-run
pode ser usado para executar um comando em um slice específico.
# systemd-run --slice=
meu.slice
comando
--uid=
nomedousuario
é uma opção usada para gerar o comando como um usuário específico.
# systemd-run --uid=
nomedousuario
--slice=
meu.slice
comando
A opção
--shell
é usada para gerar um comando em shell de dentro do slice.
Como usuário sem privilégios
Usuários sem privilégios podem dividir os recursos disponibilizados em novos cgroups, se claro algumas condições forem atendidas.
É importante que cgroups v2 seja utilizado para que um usuário sem privilégios consiga as permissões de gerenciamento de recursos cgroup.
Tipos de controladores
Nem todos os recursos podem ser controlados pelo usuário.
Controlador
Controlado pelo usuário
Opções
cpu
Precisa de delegação
CPUAccounting, CPUWeight, CPUQuota, AllowedCPUs, AllowedMemoryNodes
io
Precisa de delegação
IOWeight, IOReadBandwidthMax, IOWriteBandwidthMax, IODeviceLatencyTargetSec
memory
Sim
MemoryLow, MemoryHigh, MemoryMax, MemorySwapMax
pids
Sim
TasksMax
rdma
Não
Não definido ou desconhecido.
eBPF
Não
IPAddressDeny, DeviceAllow, DevicePolicy
Nota
eBPF tecnicamente não é considerado um controlador, mas sim as opções implementadas pelo systemd que as usa e somente o usuário root possui permissão de mudá-las.
Delegações de usuário
Para o usuário controlar CPU e recursos de I/O os mesmos precisam ser delegados ao usuário em questão. Isso pode ser feito com um
arquivo drop-in
.
Por exemplo, se o seu id de usuário for 1000:
/etc/systemd/system/user@1000.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io
Reinicie o sistema e verifique a utilização dos controladores
cpu
e
io
na sessão de usuário:
$ cat /sys/fs/cgroup/user.slice/user-1000.slice/cgroup.controllers
cpuset cpu io
memory pids
Slices definidos pelo usuário
Os arquivos slice de usuário podem ser colocados em
~/.config/systemd/user/
.
Para executar comandos em um certo slice:
$ systemd-run --user --slice=
meu.slice
comando
Você pode também executar seu login shell de dentro do slice:
$ systemd-run --user --slice=
meu.slice
--shell
Ajuste durante runtime - Tempo de execução
Recursos definidos pelo cgroups podem ser ajustados durante o tempo de execução usando o comando
systemctl set-property
. A sintaxe é idêntica às opções de
systemd.resource-control(5)
.
Por exemplo, para cortar o acesso à internet de todas as sessões de usuário:
$ systemctl set-property user.slice IPAddressDeny=any
Atenção
Os ajustes serão
permanentes
a não ser que a opção
--runtime
seja passada. As alterações são salvas em
/etc/systend/system.control/
e, portanto, gerenciam as opções gerais do sistema, enquanto as opções de usuário são salvas em
.config/systemd/user.control/
.
Nota
Nem todos os recursos tem efeito imediato após alteração. Por exemplo, gerar alterações com TaskMax terá efeito somente depois de criado novos processos.
Com libcgroup
É possível
habilitar
o serviço
chconfig
com systemd. Isto permite facilmente o rastreio de quaisquer erros gerados pelo
cgconfig.conf
.
Grupos ad-hoc
Um dos poderes de cgroups é a criação de grupos "ad-hoc" em tempo real. Uma das vantagens é adicionar privilégios ao usuário regular ativo para criação de grupos customizados. No exemplo abaixo
nomedogrupo
é o nome do cgroup:
# cgcreate -a
usuario
-t
usuario
-g memory,cpu:
nomedogrupo
Agora todos os comportamentos ajustados no grupo
nomedogrupo
podem ser escritos pelo usuário ativo.
$ ls -l /sys/fs/cgroup/memory/
nomedogrupo
total 0
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cgroup.event_control
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cgroup.procs
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cpu.rt_period_us
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cpu.rt_runtime_us
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cpu.shares
-rwxrwxr-x 1 user root 0 Sep 25 00:39 notify_on_release
-rwxrwxr-x 1 user root 0 Sep 25 00:39 tasks
Cgroups são hierárquicos, ou seja, um usuário pode criar quantos subgrupos forem desejados. Se por exemplo um usuário regular quiser executar o shell
bash
de dentro de um novo subgrupo chamado
foo
:
$ cgcreate -g memory,cpu:
nomedogrupo/foo
$
cgexec
-g memory,cpu:nomedogrupo/foo
bash
Por garantia verifique (somente necessário ao usar cgroups legacy (v1)):
$ cat /proc/self/cgroup
11:memory:/nomedogrupo/foo
6:cpu:/nomedogrupo/foo
Desta forma um novo subdiretório foi criado para este grupo. Para limitar o uso da memória de todos os processos envolvidos no grupo em 10MB, execute o comando abaixo:
$ echo 10000000 > /sys/fs/cgroup/memory/groupname/foo/memory.limit_in_bytes
Note que o limite de memória se aplica apenas ao uso de RAM. A partir do momento que as tarefas alcançarem o máximo estabelecido, a memória é convertida em swap. Entretanto a troca não afetará a performance de forma significativa.
De maneira similar, você pode mudar a prioridade ("shares", ou compartilhamentos) de CPU em grupo. Por padrão todos os grupos tem 1024 shares. Um grupo com 100 shares deterá aproximadamente 10% do tempo de CPU.
$ echo 100 > /sys/fs/cgroup/cpu/groupname/foo/cpu.shares
Mais ajustes de comportamento ou estatísticas podem ser encontrados ao listar o diretório do cgroup.
Se for preferível um processo já em execução pode ter seu cgroup alterado. Como mostrado no exemplo abaixo, para mover todos os comandos dos processos em shell 'bash' com destino ao
nomedogrupo/foo
:
$ pidof bash
13244 13266
$
cgclassify
-g memory,cpu:nomedogrupo/foo `pidof bash`
$ cat /proc/13244/cgroup
11:memory:/nomedogrupo/foo
6:cpu:/nomedogrupo/foo
Configuração persistente de grupo
Nota
Quando usada uma versão de
Systemd
≥ 205 (maior ou igual a 205) ao gerenciar cgroups, você pode ignorar totalmente este arquivo.
Se você quiser que cgroups sejam criados durante o boot, defina no arquivo de configuração em
/etc/cgconfig.conf
. Por exemplo, o "nomedogrupo" garante permissão para o
$USER
e
usuários
do grupo
$GROUP
para gerenciar limites e adicionar tarefas. Portanto as definições de grupo do
subgrupo
"nomedogrupo/foo" seriam semelhantes a configuração abaixo:
/etc/cgconfig.conf
group
nomedogrupo
{
  perm {
# who can manage limits
    admin {
      uid =
$USER
;
      gid =
$GROUP
;
    }
# who can add tasks to this group
    task {
      uid =
$USER
;
      gid =
$GROUP
;
    }
  }
# create this group in cpu and memory controllers
  cpu { }
  memory { }
}

group
nomedogrupo/foo
{
  cpu {
cpu.shares
= 100;
  }
  memory {
memory.limit_in_bytes
= 10000000;
  }
}
Nota
Comentários
devem
começar na primeira linha! Ou seja, o carácter
#
usado em comentários deve aparecer como o primeiro carácter da linha. Caso não seja, o
cgconfigparser
irá ter problemas de
parsing
e será reportado o erro:
cgroup change of grupo failed
, ou de forma traduzida:
mudança de grupo falhou para cgroup
. O erro também é evitável se
cgconfig
for executado por uma unit do
systemd
.
A seção de permissões é opcional.
A hierarquia do diretório
/sys/fs/cgroup/
que contém todos os
controladores
já possui os subdiretórios criados e montados durante o boot como um sistema de arquivos virtual. Isto fornece a habilidade de criar uma nova entrada de grupo com o comando
$CONTROLLER-NAME { }
. Se por alguma razão você quiser criar e montar hierarquias em outro lugar, será necessário escrever uma segunda entrada em
/etc/cgconfig.conf
da seguinte forma:
mount {    
   cpuset = /local/do/
nomedogrupo
;
 }
Isto é equivalente a esses comandos em shell:
# mkdir /local/do/
nomedogrupo
# mount -t /local/do -o cpuset
nomedogrupo
/local/do/
nomedogrupo
Com o sistema de arquivos virtual cgroup
A partir do systemd versão 232, ao invés do método
cgm
descrito na próxima seção abaixo, esta seção aborda uma alternativa manual para configurar a limitação de memória em uso.
Crie um novo nome de cgroup chamado
nomedogrupo
:
# mkdir /sys/fs/cgroup/memory/
nomedogrupo
Exemplo: defina o valor limite de memória para 100MB:
# echo 100000000 > /sys/fs/cgroup/memory/
nomedogrupo
/memory.limit_in_bytes
Mova um único processo para o cgroup por vez:
# echo
pid
> /sys/fs/cgroup/memory/
groupname
/cgroup.procs
Nota
Neste último comando, somente um PID pode ser escrito por vez. Portanto, repita esse passo para cada processo que precise ser movido.
Exemplos
Restrição de uso da memória ou CPU de um comando
O exemplo a seguir demonstra um
cgroup
que restringe um determinado comando para 2GB de memória.
$ systemd-run --scope -p MemoryMax=2G --user
comando
E o exemplo a seguir demonstra um comando restringido para 20% do uso de um core de CPU.
$ systemd-run --scope -p CPUQuota="20%" --user
comando
Matlab
Fazer cálculos extensos com
MATLAB
pode resultar em
crash
do seu sistema. Devido ao fato que Matlab não possui nenhuma proteção contra o consumo de memória ou CPU da máquina. O exemplo a seguir mostra um
cgroup
que restringe o uso do Matlab para o limite dos primeiros 6 cores de CPU e 5GB de memória.
Com systemd
~/.config/systemd/user/matlab.slice
[Slice]
AllowedCPUs=0-5
MemoryHigh=6G
Inicie Matlab desta maneira (tenha certeza que o caminho está correto):
$ systemd-run --user --slice=matlab.slice /opt/MATLAB/2012b/bin/matlab -desktop
Com libcgroup
/etc/cgconfig.conf
group matlab {
    perm {
        admin {
            uid =
nomedousuario
;
        }
        task {
            uid =
nomedousuario
;
        }
    }

    cpuset {
        cpuset.mems="0";
        cpuset.cpus="0-5";
    }
    memory {
        memory.limit_in_bytes = 5000000000;
    }
}
Mude
nomedousuario
para o nome de usuário que estiver executando Matlab.
Você também pode restringir o compartilhamento de CPU (share) ao delimitar com
cpu
.
Inicie Matlab desta maneira (tenha certeza que o caminho está correto):
$ cgexec -g memory,cpuset:matlab /opt/MATLAB/2012b/bin/matlab -desktop
Documentação
Para informações de controladores e o que certos switches ou ajustes de comportamento (tunables) significam, consulte a documentação do kernel:
v1
ou
v2
(ou instale
linux-docs
e veja
/usr/src/linux/Documentation/cgroup
)
Página do manual do Linux:
cgroups(7)
.
Um detalhado e completo guia sobre gerenciamento de recursos pode ser encontrado na
documentação do Red Hat Enterprise Linux
.
Para comandos e configurações de arquivos, veja as páginas man relevantes, por exemplo:
cgcreate(1)
ou
cgrules.conf(5)
Dicas e truques
Habilitar cgroup v1
Cgroup v2 é agora habilitado por padrão. Se você quiser trocar para cgroup v1, defina o seguinte
parâmetro de kernel
:
systemd.unified_cgroup_hierarchy=0
Veja também
systemd cgroups hacker guide
cgroupv2: Linux's new unified control group system