Como usar o cgroups para limitar todos os processos, exceto a lista de permissões a uma única CPU?

26

Existe um guia para cgroups da Red Hat que talvez seja meio que útil (mas não responde a essa pergunta).

Eu sei como limitar um processo específico a uma CPU específica, durante o comando para iniciar esse processo, por:

Primeiro, coloque o seguinte * em /etc/cgconfig.conf:

mount {
  cpuset =  /cgroup/cpuset;
  cpu =     /cgroup/cpu;
  cpuacct = /cgroup/cpuacct;
  memory =  /cgroup/memory;
  devices = /cgroup/devices;
  freezer = /cgroup/freezer;
  net_cls = /cgroup/net_cls;
  blkio =   /cgroup/blkio;
}

group cpu0only {
  cpuset {
    cpuset.cpus = 0;
    cpuset.mems = 0;
  }
}

E, em seguida, inicie um processo e atribua-o especificamente a esse cgroup usando:

cgexec -g cpuset:cpu0only myprocessname

Posso limitar automaticamente todas as instâncias de um nome de processo específico ( acho que isso está correto) colocando o seguinte em /etc/cgrules.conf:

# user:process  controller  destination
*:myprocessname cpuset      cpu0only

Minha pergunta é: Como posso fazer o inverso ?

Em outras palavras, como posso atribuir todos os processos, exceto um conjunto específico de processos na lista de permissões e seus filhos, a um cgroup restrito?


Com base no que estudei, mas não testei, acredito que uma solução parcial seria:

Adicione um cgroup "irrestrito":

group anycpu {
  cpuset {
    cpuset.cpus = 0-31;
    cpuset.mems = 0;  # Not sure about this param but it seems to be required
  }
}

Atribua meu processo explicitamente ao grupo irrestrito e tudo mais ao grupo restrito:

# user:process  controller  destination
*:myprocessname cpuset      anycpu
*               cpuset      cpu0only

No entanto, a advertência sobre isso parece ser (da leitura dos documentos, e não do teste, portanto, grão de sal) que os filhos de myprocessnameserão transferidos para o cpu0onlycgroup restrito .

Uma abordagem alternativa possível seria criar um usuário para executar myprocessnamee ter todos os processos desse usuário irrestritos e tudo mais restrito. No entanto, no meu caso de uso real, o processo precisa ser executado pela raiz e há outros processos que também devem ser executados pela raiz que devem ser restritos.

Como posso fazer isso com o cgroups?


Se isso não for possível com o cgroups (que agora suspeito ser o caso), minhas idéias de soluções parciais estão corretas e elas funcionarão como eu penso?

* Isenção de responsabilidade: este provavelmente não é um exemplo de código mínimo; eu não entendo todas as partes, portanto não sei quais não são necessárias.

Curinga
fonte

Respostas:

30

UPDATE: Observe que a resposta abaixo se aplica ao RHEL 6. No RHEL 7, a maioria dos cgroups é gerenciada pelo systemd e o libcgroup está obsoleto.


Desde a publicação desta pergunta, estudei o guia inteiro ao qual vinculei acima, bem como a maioria da documentação cgroups.txt e cpusets.txt . Agora eu sei mais do que eu esperava aprender sobre cgroups, então vou responder minha própria pergunta aqui.

Existem várias abordagens que você pode adotar. O contato de nossa empresa na Red Hat (arquiteto técnico) recomendou uma restrição geral de todos os processos, de preferência a uma abordagem mais declarativa - restringindo apenas os processos que queríamos especificamente restritos. A razão para isso, de acordo com suas declarações sobre o assunto, é que é possível que as chamadas do sistema dependam do código do espaço do usuário (como processos LVM) que, se restringido, poderia diminuir a velocidade do sistema - o oposto do efeito pretendido. Então acabei restringindo vários processos nomeados especificamente e deixando tudo o resto.

Além disso, quero mencionar alguns dados básicos do cgroup que estavam faltando quando postei minha pergunta.


Os Cgroups não dependem da libcgroupinstalação. No entanto, esse é um conjunto de ferramentas para lidar automaticamente com a configuração do cgroup e as atribuições de processo ao cgroups e pode ser muito útil.

Eu descobri que as ferramentas libcgroup também podem ser enganosas, porque o pacote libcgroup é construído em seu próprio conjunto de abstrações e suposições sobre o uso do cgroups, que são ligeiramente diferentes da implementação real do cgroups no nível do kernel. (Eu posso colocar exemplos, mas isso levaria algum trabalho; comente se você estiver interessado.)

Portanto, antes de usar ferramentas libcgroup (tais como /etc/cgconfig.conf, /etc/cgrules.conf, cgexec, cgcreate, cgclassify, etc.) I altamente recomendável ficar muito familiarizado com o /cgrouppróprio sistema de arquivos virtual, e criando manualmente cgroups, hierarquias cgroup (incluindo hierarquias com vários subsistemas anexados, que libcgroup sneakily e resumos leakily ), reatribuindo processos a diferentes cgroups executando echo $the_pid > /cgroup/some_cgroup_hierarchy/a_cgroup_within_that_hierarchy/tasks, e outras tarefas aparentemente mágicas que são libcgroupexecutadas sob o capô.


Outro conceito básico que eu estava perdendo era que, se o /cgroupsistema de arquivos virtual estiver montado no seu sistema (ou mais precisamente, se algum dos subsistemas cgroup, conhecido como "controladores", estiver montado)), todos os processos do sistema inteiro estarão em um cgroup. Não existe algo como "alguns processos estão em um cgroup e outros não".

Existe o que é chamado de cgroup raiz para uma determinada hierarquia, que possui todos os recursos do sistema para os subsistemas conectados. Por exemplo, uma hierarquia cgroup que possui os subsistemas cpuset e blkio conectados, teria um cgroup raiz que possuiria todos os cpus no sistema e todo o blkio no sistema e poderia compartilhar alguns desses recursos com os cgroups filhos . Você não pode restringir o cgroup raiz porque ele possui todos os recursos do seu sistema, portanto, restringi-lo nem faria sentido.


Alguns outros dados simples que estavam faltando sobre o libcgroup:

Se você usar /etc/cgconfig.conf, verifique se o chkconfig --list cgconfigprograma cgconfigestá configurado para ser executado na inicialização do sistema.

Se você alterar /etc/cgconfig.conf, precisará executar service cgconfig restartpara carregar as alterações. (E problemas com a interrupção do serviço ou a execução cgclearsão muito comuns quando se faz testes. Para depuração, recomendo, por exemplo lsof /cgroup/cpuset, se cpuseté o nome da hierarquia do cgroup que você está usando.)

Se você deseja usar /etc/cgrules.conf, é necessário garantir que o "daemon do mecanismo de regras do cgroup" ( cgrulesengd) esteja em execução: service cgred starte chkconfig cgred on. (E você deve estar ciente de uma condição de corrida possível, mas improvável, referente a este serviço, conforme descrito no Guia de Gerenciamento de Recursos Red Hat na seção 2.8.1 na parte inferior da página.)

Se você quiser brincar manualmente e configurar seus cgroups usando o sistema de arquivos virtual (que eu recomendo para o primeiro uso), você pode fazer isso e criar um cgconfig.confarquivo para espelhar sua configuração usando cgsnapshotas várias opções.


E, finalmente, a principal informação que eu estava perdendo quando escrevi o seguinte:

No entanto, a advertência sobre isso parece ser ... que os filhos de myprocessname serão transferidos para o cgroup restrito de cpu0only.

Eu estava correto, mas há uma opção que eu desconhecia.

cgexec é o comando para iniciar um processo / executar um comando e atribuí-lo a um cgroup.

cgclassify é o comando para atribuir um processo já em execução a um cgroup.

Ambos também impedirão cgred( cgrulesengd) de reatribuir o processo especificado para um cgroup diferente com base em /etc/cgrules.conf.

Ambos cgexece cgclassifyapoiar a --stickybandeira, que além disso impede cgredde reatribuição criança processos com base em /etc/cgrules.conf.


Portanto, a resposta para a pergunta que eu escrevi (embora não seja a configuração que acabei implementando, devido aos conselhos do nosso Red Hat Technical Architect mencionado acima) é:

Faça o cpu0onlye anycpucgroup conforme descrito na minha pergunta. (Verifique se cgconfigestá definido para ser executado na inicialização.)

Faça a * cpuset cpu0onlyregra como descrito na minha pergunta. (E verifique se cgredestá configurado para ser executado na inicialização.)

Iniciar qualquer processo que eu quero sem restrições com: cgexec -g cpuset:anycpu --sticky myprocessname.

Esses processos serão irrestritos e todos os seus processos filhos também serão irrestritos. Todo o resto do sistema será restrito à CPU 0 (uma vez que você reinicia, pois cgrednão aplica o cgrules a processos já em execução, a menos que eles alterem seu EUID). Isso não é totalmente aconselhável, mas foi o que solicitei inicialmente e isso pode ser feito com os cgroups.

Curinga
fonte
Uau. legal. como isso teve 0 votos?
mikeserv
@mikeserv, obrigado. :) Responda à sua pergunta: verifique as datas; Acabei de escrever esta resposta ontem.
Wildcard
1
eu vi isso. mas foi 24 horas atrás. provavelmente sua causa é longa. as coisas boas às vezes podem ser esquecidas assim. e, de qualquer forma, as respostas com muitos votos muito em breve raramente são boas - as informações não podem ser úteis se tantas pessoas já souberem. este é um dos bons, no entanto. Os cgroups são misteriosos.
mikeserv