O que são namespaces do Linux e para que são usados?
Os namespaces do Linux são a tecnologia subjacente por trás das tecnologias de contêiner, como o Docker. Eles são um recurso do kernel do Linux que permite que o sistema restrinja os recursos que os processos em contêineres veem e garante que nenhum deles possa interferir no outro.
O que são espaços de nomes?
Quando você está executando muitos processos e aplicativos diferentes em um único servidor, como é o caso de ferramentas de implantação como o Kubernetes, é importante ter cada processo isolado, principalmente por segurança.
Um contêiner não deve ser capaz de obter controle sobre os recursos de outro, porque se esse contêiner for comprometido, poderá comprometer todo o sistema. Esse método de ataque é semelhante ao funcionamento do bug Meltdown da CPU; threads diferentes de um processador devem ser isoladas umas das outras. Da mesma forma, os processos executados em diferentes sistemas virtuais (contêineres) devem ser isolados de outros contêineres.
Os namespaces atingem esse isolamento no nível do kernel. Semelhante ao funcionamento do aplicativo chroot, que prende um processo em um diretório raiz diferente, os namespaces separam outros aspectos do sistema. Há sete namespaces disponíveis:
- Montar ou
mnt
. Muito semelhante aochroot
, o namespace Mount particiona virtualmente o sistema de arquivos. Os processos executados em namespaces de montagem separados não podem acessar arquivos fora de seu ponto de montagem. Como isso é feito no nível do kernel, é muito mais seguro do que alterar o diretório raiz comchroot
. - Processo ou
pid
. No Linux, os primeiros processos são gerados como filhos do PID 1, que forma a raiz da árvore de processos. O namespace do processo corta uma ramificação da árvore PID e não permite acesso mais acima na ramificação. Os processos em namespaces filhos terão, na verdade, vários PIDs — o primeiro representando o PID global usado pelo sistema principal e o segundo PID representando o PID dentro da árvore do processo filho, que será reiniciado a partir de 1. - Comunicação entre processos ou
ipc
. Este namespace controla se os processos podem ou não se comunicar diretamente entre si. - Rede ou
net
. Este namespace gerencia quais dispositivos de rede um processo pode ver. No entanto, isso não configura nada automaticamente para você - você ainda precisará criar dispositivos de rede virtual e gerenciar a conexão entre as interfaces de rede global e as interfaces de rede filhas. O software de conteinerização como o Docker já descobriu isso e pode gerenciar a rede para você. - Usuário. Este namespace permite que o processo tenha “raiz virtual” dentro de seu próprio namespace, sem ter acesso root real ao sistema pai. Ele também particiona as informações de UID e GID, para que os namespaces filhos possam ter suas próprias configurações de usuário.
- UTS. Esse namespace controla o nome do host e as informações de domínio e permite que os processos pensem que estão sendo executados em servidores com nomes diferentes.
- Cgroup é outro recurso do kernel muito semelhante aos namespaces. Cgroups permitem que o sistema defina limites de recursos (CPU, memória, espaço em disco, tráfego de rede, etc.) para um grupo de processos. Esse é um recurso útil para aplicativos conteinerizados, mas não faz nenhum tipo de “isolamento de informações” como os namespaces fariam. O espaço de nome do cgroup é uma coisa separada e controla apenas quais cgroups um processo pode ver e não o atribui a um cgroup específico.
Por padrão, qualquer processo executado usa os namespaces globais e a maioria dos processos em seu sistema também, a menos que especificado de outra forma.
Trabalhando com Namespaces
Você pode usar o comando lsns
(ls-namespaces) para visualizar os namespaces atuais que seu sistema ativou. Este comando precisa ser executado como root, caso contrário a lista pode estar incompleta.
Acima está a saída lsns
de uma nova instalação do Ubuntu. Cada namespace é listado ao lado do ID do processo, usuário e comando que o criou. Os sete namespaces gerados de /sbin/init
com PID 1 são os sete namespaces globais. Os únicos outros namespaces são mnt
para daemons do sistema, juntamente com o serviço Livepatch da Canonical.
Se você estivesse trabalhando com contêineres, essa lista seria muito maior. Você pode gerar essa lista no formato JSON com o sinalizador -J
, que pode ser usado com muito mais facilidade com uma linguagem de script.
Você pode alterar seu namespace atual com o utilitário nsenter
. Este comando permite “entrar” no namespace de outro processo, geralmente para fins de depuração. Na verdade, ele pode executar qualquer comando nesse namespace, mas, por padrão, apenas tenta carregar um shell (/bin/bash
geralmente).
Você especifica um ID de processo e, em seguida, cada namespace que deseja inserir:
sudo nsenter -t PID --mount --net --pid //etc.
Por exemplo, tentar inserir o namespace de montagem para kdevtmpfs
carregará você nesse namespace, mas posteriormente falhará porque não pode encontrar /bin/bash
, o que na verdade significa que funcionou, porque o diretório raiz aparente foi alterado.
Se o namespace mnt
filho incluir /bin/bash
, você poderá inseri-lo e carregar um shell. Isso pode ser feito manualmente, mas deve ser feito por meio de montagens vinculadas, que podem manipular a árvore de diretórios e vincular arquivos nos namespaces mnt
. Isso pode levar a alguns casos de uso interessantes, como fazer dois processos lerem conteúdos diferentes do mesmo arquivo.
Para criar novos namespaces, você precisa bifurcar um existente (geralmente global) e especificar quais namespaces deseja alterar. Isso é feito com o comando unshare
, que executa um comando com um novo namespace “unshared” do mestre.
Para descompartilhar o namespace do nome do host, use:
sudo unshare -u command
Se o comando for deixado em branco, descompartilhar
executará o bash por padrão. Isso cria um novo namespace que aparecerá na saída de lsns
:
A tela
do multiplexador de terminal é usada aqui para manter o bash rodando em segundo plano, caso contrário, o namespace desapareceria quando o processo fosse encerrado.
A menos que você esteja fazendo programação de nível muito baixo, provavelmente não terá que tocar em namespaces. Programas de conteinerização como o Docker gerenciarão os detalhes para você e, na maioria dos casos em que for necessário isolar o processo, você deve usar apenas uma ferramenta existente. No entanto, é importante entender como os namespaces funcionam no contexto da conteinerização, especialmente se você estiver fazendo qualquer configuração de baixo nível de seus contêineres Docker ou precisar fazer qualquer depuração manual.