Não sou um usuário forte de Linux, mas quero entender melhor o material neste post aqui que fala sobre namespaces Linux
https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory
Acho que minha incapacidade de compreensão pode estar relacionada à compreensão insuficiente de "comando", "processo" e talvez algumas outras coisas.
Primeiro, deixe-me explicar um experimento simples que estou usando para minha educação. Abri duas janelas de terminal PUTTY. Em cada janela, fiz um ssh root@[ip of machine]
. Agora que tenho 2 sessões SSH para minha máquina Linux, começo meus experimentos.
Na primeira janela, fiz isso:
root@localhost:~# unshare --pid /bin/bash
bash: fork: Cannot allocate memory
Na segunda janela, fiz isso:
root@localhost:~# ps -aux | grep unshare
root 58188 0.0 0.0 6480 2284 pts/3 R+ 21:49 0:00 grep --color=auto unshare
Aqui estão minhas perguntas:
A segunda janela não mostra nenhuma indicação de
unshare --pid /bin/bash
. Isso ocorre porque o/bin/bash
comando ou o/bin/bash
processo já havia terminado? É por isso que muitos usuários de Linux na internet recomendam usar o--fork
para que o/bin/bash
seja executado no namespace recém-criado?A resposta aceita declarou isto: "Depois que o bash começar a rodar, o bash irá bifurcar vários novos subprocessos para fazer algumas coisas." Não entendi o significado desta frase. Então, na segunda janela do terminal, eu rodei isto:
root@localhost:~# unshare -pf /bin/bash
root@localhost:~# ps -a
PID TTY TIME CMD
58278 pts/2 00:00:00 sudo
58279 pts/2 00:00:00 su
58280 pts/2 00:00:00 bash
58291 pts/2 00:00:00 unshare
58292 pts/2 00:00:00 bash
58299 pts/2 00:00:00 ps
PID 58278 a PID58299 é o que o autor quis dizer com "o bash bifurcará vários novos subprocessos para fazer algumas coisas"?
Fundo
Começarei com um histórico simplificado sobre como os processos são criados no Linux. Não cobrirei todas as opções ou todos os detalhes, mas, em vez disso, focarei nas ideias principais.
Geralmente, novos processos são criados usando a
fork()
chamada do sistema. Em caso de sucesso,fork()
resultará em um novo processo que está executando o mesmo programa que o original (efetivamente, é um clone do programa que foi invocadofork()
no ponto em que chamoufork()
). Afork()
função retorna tanto no processo "pai" quanto no processo "filho" (o recém-criado). Cada processo pode examinar o valor de retorno defork()
para determinar se é o "pai" ou o "filho", e pode usar isso para decidir o que fazer em seguida.Muitas vezes, criar um novo processo significa que queremos executar um programa diferente, e até agora só temos uma maneira de criar cópias do mesmo programa. Felizmente, há uma chamada de sistema separada,
exec()
, que substitui o programa em execução no momento por um novo programa.Considere o caso em que você tem um shell (vou assumir
bash
aqui) e você digitals
para listar o conteúdo do diretório atual:O Problema
Você começa com:
Observe o erro
bash: fork: Cannot allocate memory
– isso não é um bom sinal.Neste caso, o
unshare
programa (1) cria um novo namespace PID e (2)exec
s/bin/bash
. Lembre-se da seção Background queexec
substitui o processo em execução atual (unshare
) por um novo programa (/bin/bash
) – ele não cria um novo processo.Até agora, nenhum processo está sendo executado no namespace PID recém-criado. O namespace existe, mas o processo que o criou ainda não fez
fork()
-ed em nada.À medida que
bash
começa a ser executado, ele normalmente executa algum conjunto de programas. Aquirun
está a combinaçãofork
/exec
descrita na seção Background. O kernel coloca o primeiro processo quebash
fork()
s no novo namespace PID e esse processo se torna oinit
processo para esse namespace (o processo nesse namespace com pid = 1). O programa quebash
é executado provavelmente tem vida curta, então ele é executado, termina e o namespace PID é destruído.Em seguida,
bash
tenta executar algum outro comando. Ele quer colocar esses comandos no novo namespace PID, mas esse namespace PID não existe mais. Como resultado, elefork()
falha resultando na mensagem de erro que você vê. Você verá isso novamente se tentar executar qualquer outro comando:A solução
Como você observou em sua pergunta, o
unshare
programa tem outra opção que é útil neste cenário. Deman unshare
:Você pode substituir seu primeiro comando por:
Observe que neste caso não há erro.
Esta opção faz com
unshare
que seu comportamento seja alterado. Em vez de usar imediatamenteexec()
para substituir a si mesmo por/bin/bash
, ele usa o comportamentofork()
/exec()
descrito na seção Background acima:Você pode confirmar que neste caso
/bin/bash
é oinit
processo (ou seja, processo com pid 1) imprimindo seu id de processo:Respostas para suas perguntas
A segunda janela não mostra nenhuma indicação de
unshare
que não está mais em execução – ela costumavaexec()
ser substituída por/bin/bash
.A
--fork
opção altera o comportamento deunshare
para que elefork()
primeiro crie um novo processo — um processo no namespace PID recém-criado — e então esse processo o usaexec()
para se substituir por/bin/bash
.Os novos subprocessos provavelmente terão vida curta, então eles não estarão mais em execução quando você executar o
ps
.