Jump to content

# cgroups (Português)

3 languages

- English
- 日本語
- 中文（简体）

From ArchWiki

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-gitAUR e libcgroup-gitAUR) 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-gitAUR e libcgroup-gitAUR);
- 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.
- libcgroupAUR, libcgroup-gitAUR - 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

Categories:

- Kernel (Português)
- Virtualization (Português)