Como criar cgroups de usuários com systemd

14

Eu uso lxccontêineres sem privilégios no Arch Linux. Aqui estão as informações básicas do sistema:

[chb@conventiont ~]$ uname -a
Linux conventiont 3.17.4-Chb #1 SMP PREEMPT Fri Nov 28 12:39:54 UTC 2014 x86_64 GNU/Linux

É um kernel personalizado / compilado com user namespace enabled:

[chb@conventiont ~]$ lxc-checkconfig 
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled
Multiple /dev/pts instances: enabled

--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled

--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

[chb@conventiont ~]$ systemctl --version
systemd 217
+PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID -ELFUTILS +KMOD +IDN 

Infelizmente, systemdnão joga bem com lxcatualmente. Especialmente, a configuração cgroupspara um usuário não root parece não estar funcionando bem ou eu não estou familiarizado com isso. lxcsó iniciará um contêiner no modo não privilegiado quando ele puder criar os cgroups necessários /sys/fs/cgroup/XXX/*. No entanto, isso não é possível lxcporque systemdmonta a roothierarquia do cgroup /sys/fs/cgroup/*. Uma solução alternativa parece ser a seguinte:

for d in /sys/fs/cgroup/*; do
        f=$(basename $d)
        echo "looking at $f"
        if [ "$f" = "cpuset" ]; then
                echo 1 | sudo tee -a $d/cgroup.clone_children;
        elif [ "$f" = "memory" ]; then
                echo 1 | sudo tee -a $d/memory.use_hierarchy;
        fi
        sudo mkdir -p $d/$USER
        sudo chown -R $USER $d/$USER
        echo $$ > $d/$USER/tasks
done

Esse código cria os cgroupdiretórios correspondentes na cgrouphierarquia para um usuário não privilegiado. No entanto, algo que eu não entendo acontece. Antes de executar o mencionado acima, verei o seguinte:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope

Depois de executar o código mencionado acima, vejo no shell que o executei:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/chb
7:net_cls:/chb
6:freezer:/chb
5:devices:/chb
4:memory:/chb
3:cpu,cpuacct:/chb
2:cpuset:/chb
1:name=systemd:/chb

Mas em qualquer outro shell ainda vejo:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope

Portanto, posso iniciar meu lxccontêiner sem privilégios no shell, executei o código mencionado acima, mas não em nenhum outro.

  1. Alguém pode explicar esse comportamento?

  2. Alguém encontrou uma maneira melhor de configurar o necessário cgroupscom uma versão atual de systemd( >= 217)?

lord.garbage
fonte

Respostas:

13

Uma solução melhor e mais segura é instalá cgmanager-lo e executá-lo com systemctl start cgmanager(em uma systemddistribuição baseada em). Você pode ter seu rootusuário ou se você tiver sudodireitos no host cgroupspara criar para seu usuário não privilegiado em todos os controladores com:

sudo cgm create all $USER
sudo cgm chown all $USER $(id -u $USER) $(id -g $USER)

Uma vez criados para o seu usuário não privilegiado, ele / ela pode mover processos aos quais ele tem acesso cgrouppara cada controlador usando:

cgm movepid all $USER $PPID

Mais seguro, mais rápido, mais confiável do que o script de shell que publiquei.

Solução manual:

Para responder 1.

for d in /sys/fs/cgroup/*; do
        f=$(basename $d)
        echo "looking at $f"
        if [ "$f" = "cpuset" ]; then
                echo 1 | sudo tee -a $d/cgroup.clone_children;
        elif [ "$f" = "memory" ]; then
                echo 1 | sudo tee -a $d/memory.use_hierarchy;
        fi
        sudo mkdir -p $d/$USER
        sudo chown -R $USER $d/$USER
        echo $$ > $d/$USER/tasks
done

Eu era ignorante sobre o que estava acontecendo exatamente quando escrevi esse script, mas lendo este e experimentar um pouco me ajudou a entender o que está acontecendo. O que estou basicamente fazendo neste script é criar uma nova cgroupsessão para a atual, userque é o que eu já afirmei acima. Quando executo esses comandos no atual shellou em um script e o faço para que sejam avaliados no atual shelle não em um subshell(via . scriptO .é importante para que isso funcione!) É que eu não apenas abro uma nova sessão para usermas adicione o shell atual como um processo que é executado neste novo cgroup. Posso obter o mesmo efeito executando o script em uma subshell e, em seguida, descendo para a cgrouphierarquia no chb subcgroupe useecho $$ > taskspara adicionar o shell atual a todos os membros do chb cgroup hierarchy.

Portanto, quando eu executo lxcesse shell atual, meu contêiner também se tornará membro de todos os chb subcgroups dos quais a corrente shellé membro. Isto é, meu containerherda o cgroupstatus de meu shell. Isso também explica por que não funciona em nenhum outro shell que não faça parte dos chb subcgroups atuais .

Eu ainda passo em 2.. Provavelmente precisaremos esperar uma systemdatualização ou Kerneldesenvolvimentos adicionais para systemdadotar um comportamento consistente, mas prefiro a configuração manual de qualquer maneira, pois isso força você a entender o que está fazendo.

lord.garbage
fonte
você não pode simplesmente montar o cgroups dir em outro lugar (pergunta honesta) ? houve muita controvérsia sobre o linux cgroups e systemd no ano passado, quando o mantenedor do cgroups aparentemente decidiu atribuir systemd pelo nome e outras aplicações similares sem nome sobre o manuseio do cgroups no espaço do usuário. Não tenho certeza de como tudo acabou, mas eu sei que estava muito claro se um usuário poderia fazer isso há um ano.
mikeserv
Provavelmente eu poderia fazer isso, mas teria que impedir que o systemd monte o diretório raiz do cgroup em primeiro lugar. Sempre que eu fizer login na minha máquina, o systemd montará a hierarquia raiz do cgroup raiz em / sys / fs / cgroup e adicionará um usuário cgroup somente na parte systemd do root cgroup (você pode ver isso acima). A diferença entre as distribuições baseadas em sistema e as não antes de mudarem é que, por exemplo, no Ubuntu, o cgroup management não está nas mãos do daemon init.
Lord.garbage 4/14
Em vez disso, é tratado por um programa como, por exemplo, cgmanager. Ou você pode fazê-lo manualmente, como sugerido no link para kernel.org que publiquei acima. Atualmente, não tenho um entendimento suficientemente profundo do gerenciamento de grupos de sistemas para mexer com isso mais profundamente do que agora. Mas espero que isso mude em breve.
precisa saber é o seguinte
1
É verdade que lembro que você afirmou que em um comentário a uma resposta que dei há muito tempo. Eu vou perguntar ...
lord.garbage
1
O truque é basicamente: sudo systemctl start cgmanager && sudo cgm create all $USER && sudo cgm chown all $USER $(id -u) $(id -g) && sudo cgm movepid all $USER $PPID. O último comando precisa ser executado no shell atual para adicioná-lo ao novo cgroup for $USER.
Lr.garbage
0

Na verdade, no archlinux, isso não funcionará, por exemplo, com um usuário sem privilégios (recomendado ao usar contêineres sem lxc). ou seja, esse usuário não tem sudo :)

Em vez disso, defina o grupo no /etc/cgconfig.conf, ative o cgconfig, o cgrules (libcgroup no AUR), adicione também o cgrules, pronto. O usuário também terá os mesmos direitos.

No systemd 218 (não sei quando, mas parece que é preciso adicionar mais duas condições, pois elas não são definidas quando criadas da maneira cgconfig):

cat /etc/cgconfig.conf

group lxcadmin {
perm {
    task {
        uid = lxcadmin;
        gid = lxcadmin;
    }
    admin {
        uid = lxcadmin;
        gid = lxcadmin;
    }
}
cpu { }
memory { memory.use_hierarchy = 1; }  
blkio { }
cpuacct { }
cpuset { 
    cgroup.clone_children = 1;
    cpuset.mems = 0;
    cpuset.cpus = 0-3; 
}
devices { }
freezer { }
hugetlb { }
net_cls { }
}

cat /etc/cgrules.conf
lxcadmin        *       lxcadmin/

Supondo que o espaço para nome seja compilado no kernel.

Este é um modelo, o cpus pode estar de acordo com quantos núcleos você possui, mem pode ser definido com algum valor real, etc.

EDIÇÃO 2: Finalmente, no systemd, se você deseja usar o início automático com um usuário tão privilegiado, pode:

cp /usr/lib/systemd/system/lxc{,admin}\@.service e adicione User = lxcadmin

e habilite-o para o contêiner do lxcadmin chamado lolz systemctl enable lxcadmin @ lolz.

Malina Salina
fonte
Obrigado @Anthon, eu nunca pode obter o código de formatação direita nestes sites, x
Malina Salina
Obrigado. Desculpe pelo atraso na resposta. O seu primeiro ponto, "Na verdade, em archlinux, isso não vai funcionar com por exemplo, um usuário sem privilégios (recomendado ao usar unpriv. Recipientes LXC). Ou seja, que o usuário não tem sudo :)" não se destacam como você só precisa de seu rootadministrador criar e chownvocê em todos os cgroupcontroladores. Isso é perfeitamente fino e seguro. movepidpode ser feito sem rootdireitos e, portanto, sem privações. O usuário não precisa de nenhum sudodireito. (Btw, libcgroupnão é suposto ser mais utilizado RHEL e outros têm depreciado-lo..)
lord.garbage
@Brauner. Como você inicia automaticamente na inicialização, os contêineres de usuários sem privilégios? Na verdade, suas soluções listadas funcionavam apenas (e implícitas) para um usuário sudo. O meu não. Você perguntou como consertar. De qualquer forma, há apenas uma atualização e o cgconfig agora falha ao iniciar, pois as user.slices são adicionadas automaticamente, à frente das configurações do cgconfig que parecem. Faltam permissões de usuário (possivelmente um erro de regressão, estou analisando agora). Eu não disse que era a melhor solução. Foi a / a solução para sua pergunta. :) Mas meus contêineres não estão inicializando agora, grrr.
Malina Salina
O motivo pelo qual eu listei systemctl enable lxcadmin @ container foi para que o root decidisse executar um contêiner privado na inicialização. Se o próprio usuário o usar em --user (land), ele será inicializado apenas quando ele efetuar login, o que não é muito útil para um servidor. E uma nota no seu comentário. colocar um usuário em todos os controladores, permite que ele comece a mover os IDs para o espaço do host, acredito, o que é um risco à segurança.
Malina Salina
Acho que isso é o que você estava fazendo com o seu método listado inicialmente, mas veja isso, mesmo que seja um pacote do ubuntu systemd bugs.launchpad.net/ubuntu/+source/systemd/+bug/1413927 Mas algo foi atualizado em dias passados ​​mudando a lógica .. Estou tentando rastreá-la.
Malina Salina
0

Por isso, tive o mesmo problema ao tentar fazer com que contêineres sem privilégios LXC funcionassem no CentOS 7. Não queria usar cgmanagerporque não gosto de introduzir nenhum serviço adicional, se não for absolutamente necessário. O que acabei fazendo foi corrigir o systemd usando alguns patches do pacote ubuntu e um patch personalizado para expandir a lista de controladores cgroup. Eu tenho as fontes necessárias para criar um RPM na minha conta do GitHub em https://github.com/CtrlC-Root/rpmdist . Também tenho versões corrigidas do shadow-utils (para subuids e subgids) e pam (para loginuid). Depois de instalar esses RPMs e configurar um usuário para executar contêineres sem privilégios (atribuir subuids e subgids, alocar pares veth no lxc-usernet, criar .config / lxc / default.conf, etc), posso executar contêineres sem privilégios LXC.

EDIT: Outra razão pela qual eu não queria usar o cgmanager é porque eu não queria que meus usuários comuns tivessem que usar o sudo. Usuários regulares devem poder fazer login e tudo deve "funcionar" imediatamente.

ctrlc-root
fonte