Introdução do Tradutor: Com a crescente adoção de diferentes tipos de contêineres em nossa vida, pode ser interessante e útil entender quais tecnologias deram início a tudo isso. Algumas delas ainda podem ser aplicadas de forma útil nos dias de hoje, mas nem todos lembram (ou sabem, se não estiveram presentes durante seu desenvolvimento acentuado). Uma dessas tecnologias é o User Mode Linux. O autor do original teve um bom trabalho investigando o que das antigas ferramentas ainda funciona e o que já não é tão útil, e compilou uma espécie de guia passo a passo sobre como criar seu próprio UML em 2019. E sim, convidamos para o site o autor do post original. , então, se tiver dúvidas — pergunte em inglês nos comentários.

User Mode no Linux é, na verdade, uma portabilidade do núcleo do Linux sobre si mesmo. Esse modo permite que um núcleo Linux completo seja executado como um processo de usuário e é geralmente utilizado por desenvolvedores para testar drivers. Mas esse modo também é útil como uma ferramenta de isolamento geral, cujo princípio é semelhante ao funcionamento de máquinas virtuais. Este modo fornece um maior isolamento do que o Docker, porém menor do que uma máquina virtual completa, como KVM ou Virtual Box.
Em geral, o User Mode pode parecer uma ferramenta estranha e complexa de usar, mas ainda assim possui suas aplicações. Afinal, é um núcleo Linux completo, operando a partir de um usuário não privilegiado. Essa característica permite executar código potencialmente não confiável sem qualquer ameaça à máquina host. E como se trata de um núcleo completo, seus processos estão isolados da máquina host, ou seja, os processos que operam dentro do User Mode não serão visíveis para o host. Isso não se assemelha ao contêiner Docker habitual, onde a máquina host sempre vê os processos dentro do armazenamento. Veja este pedaço do pstree de um dos meus servidores:
containerd─┬─containerd-shim─┬─tini─┬─dnsd───19*[{dnsd}]
│ │ └─s6-svscan───s6-supervise
│ └─10*[{containerd-shim}]
├─containerd-shim─┬─tini─┬─aerial───21*[{aerial}]
│ │ └─s6-svscan───s6-supervise
│ └─10*[{containerd-shim}]
├─containerd-shim─┬─tini─┬─s6-svscan───s6-supervise
│ │ └─surl
│ └─9*[{containerd-shim}]
├─containerd-shim─┬─tini─┬─h───13*[{h}]
│ │ └─s6-svscan───s6-supervise
│ └─10*[{containerd-shim}]
├─containerd-shim─┬─goproxy───14*[{goproxy}]
│ └─9*[{containerd-shim}]
└─32*[{containerd}]E compare isso com o pstree do núcleo Linux no Modo de Usuário:
linux─┬─5*[linux]
└─slirpAo trabalhar com contêineres Docker, posso ver a partir do host os nomes dos processos que estão em execução no sistema convidado. Com o Modo de Usuário do Linux, isso não é possível. O que isso significa? Isso significa que as ferramentas de monitoramento que operam através do subsistema de auditoria do Linux não veem os processos executados no sistema convidado. Mas em algumas situações, essa característica pode se tornar uma faca de dois gumes.
Na verdade, todo o post abaixo é uma série de pesquisas e tentativas rudimentares de alcançar o resultado desejado. Para isso, precisei usar diversas ferramentas antigas, ler o código-fonte do núcleo, fazer depuração intensiva de código escrito na época em que eu ainda estava na escola primária, além de fuçar nas compilações do Heroku com um binário específico em busca das ferramentas que precisava. Todo esse trabalho fez com que a galera no meu IRC começasse a me chamar de bruxa (magic). Espero que este post sirva como uma documentação confiável para que alguém consiga fazer o mesmo, mas já com núcleos e versões de SO mais atuais.
Configuração
A configuração do Modo de Usuário do Linux é feita em várias etapas:
- instalação de dependências no host;
- download do núcleo Linux;
- configuração da compilação do núcleo;
- compilação do núcleo;
- instalação do binário;
- configuração do sistema de arquivos convidado;
- ajuste dos parâmetros de inicialização do núcleo;
- configuração da rede convidada;
- inicialização do núcleo convidado.
Eu presumo que, se você decidir fazer isso sozinho, provavelmente estará fazendo tudo o que foi descrito em algum sistema parecido com Ubuntu ou Debian. Eu tentei implementar tudo que foi mencionado na minha distribuição favorita — Alpine, mas não consegui, aparentemente devido ao fato de que o kernel do Linux possui uma rigididade em relação ao glibc-isms para drivers em User Mode. Planejo relatar isso para o upstream assim que entender completamente o problema.
Instalação de dependências no host
O Ubuntu requer, no mínimo, os seguintes pacotes para compilar o kernel do Linux (considerando uma instalação limpa):
- 'build-essential'
- 'flex'
- 'bison'
- 'xz-utils'
- 'wget'
- 'ca-certificates'
- 'bc'
- 'linux-headers'
Você pode instalá-los usando o seguinte comando (com privilégios de root ou através do sudo):
apt-get -y install build-essential flex bison xz-utils wget ca-certificates bc
linux-headers-$(uname -r) Observe que a execução do programa de configuração do menu para o kernel do Linux exigirá a instalação de libncurses-dev. Por favor, verifique se ele está instalado usando o seguinte comando (com privilégios de root ou através do sudo):
apt-get -y install libncurses-devBaixando o kernel
Defina um local para baixar e compilar o kernel. Para esta operação, você precisará liberar cerca de 1,3 GB de espaço no disco rígido, então certifique-se de que você tem isso disponível.
Em seguida, acesse e obtenha a URL para baixar a última versão estável do kernel. No momento da redação deste post, é:
Baixe esse arquivo usando 'wget':
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.16.tar.xz E extraia-o usando 'tar':
tar xJf linux-5.1.16.tar.xzAgora vamos para o diretório criado durante a extração do tarball:
cd linux-5.1.16Configuração da compilação do kernel
O sistema de compilação do kernel é um conjunto com com uma variedade de ferramentas e scripts personalizados para automatizar o processo. Para começar, abra o programa interativo de configuração:
make ARCH=um menuconfig Ele conduzirá parcialmente a compilação e lhe mostrará uma janela de diálogo. Quando na parte inferior da janela aparecer ‘[Select]‘, você poderá fazer as configurações usando as teclas de espaço ou Enter. A navegação pela janela é como de costume, usando as teclas de seta para cima e para baixo, e a seleção de itens com para a esquerda ou direita.
Um indicador do tipo —> significa que você está em um submenu, cujo acesso se faz pela tecla Enter. A saída dele, evidentemente, é através de ‘[Exit]‘.
Ative as seguintes opções em ‘[Select]‘ e certifique-se de que há um símbolo ‘[*]’ ao lado delas:
Opções específicas do UML:
- Sistema de arquivos do host
Suporte à rede (ative isso para fazer o submenu aparecer):
- Opções de rede:
- Rede TCP/IP
Dispositivos de rede UML:
- Dispositivo de rede virtual
- Transporte SLiRP Você pode sair desta janela, selecionando '[Exit]'. Apenas certifique-se de que no final será oferecido a você salvar a configuração e escolha '[Sim]‘.
Recomendo que você brinque com as opções de compilação do kernel após ler este post. Através dessas experiências, você poderá aprender muito sobre o funcionamento das mecânicas de baixo nível do kernel e a influência dos diferentes flags em sua compilação.
Compilação do kernel
O kernel do Linux é um grande programa que gerencia muitas coisas. Mesmo com uma configuração tão mínima em hardware antigo, a compilação pode levar um bom tempo. Portanto, compile o kernel usando o seguinte comando:
make ARCH=um -j$(nproc) Por quê? Este comando dirá ao nosso compilador para usar todas as núcleos e threads disponíveis durante o processo de compilação. O comando $(nproc) no final da compilação substitui a saída do comando nproc, que é parte do coreutils na compilação padrão do Ubuntu.
Após algum tempo, nosso kernel será compilado em um arquivo executável ./linux.
Instalação do binário
Como o Modo de Usuário no Linux cria um binário padrão, você pode instalá-lo como qualquer outra utilidade. Veja como eu fiz:
mkdir -p ~/bin
cp linux ~/bin/linux Também é importante garantir que ~/bin esteja no seu $PATH:
export PATH=$PATH:$HOME/binConfiguração do sistema de arquivos do convidado
Crie um diretório para o sistema de arquivos do convidado:
mkdir -p $HOME/prefix/uml-demo
cd $HOME/prefix
Abra alpinelinux.org e na encontre o link atual para download do MINI ROOT FILESYSTEM. No momento da redação desta publicação, isso era:
http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gzBaixe este tarball usando wget:
wget -O alpine-rootfs.tgz http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.0-x86_64.tar.gzAgora entre no diretório do sistema de arquivos do convidado e extraia o arquivo:
cd uml-demo
tar xf ../alpine-rootfs.tgzAs ações descritas criarão um pequeno template do sistema de arquivos. Devido às peculiaridades do sistema, será extremamente complicado instalar pacotes através do gerenciador apk do Alpine. Mas este sistema de arquivos será suficiente para avaliar a ideia geral.
Também precisaremos de uma ferramenta para prevenir o consumo de memória do nosso kernel convidado.
wget -O tini https://github.com/krallin/tini/releases/download/v0.18.0/tini-static
chmod +x tiniCriação da linha de comando do kernel
No núcleo do Linux, assim como na maioria dos outros programas, existem argumentos de linha de comando, que podem ser consultados fornecendo a chave --help.
self —help
linux --help
User Mode Linux v5.1.16
disponível em http://user-mode-linux.sourceforge.net/
--showconfig
Imprime o arquivo de configuração do qual este binário UML foi gerado.
iomem=,
Configura como uma região de memória IO chamada .
mem=
Isso controla quanto de "memória física" o kernel aloca
para o sistema. O tamanho é especificado como um número seguido
de um dos 'k', 'K', 'm', 'M', que têm os significados óbvios.
Isso não está relacionado à quantidade de memória no host. Pode
ser mais, e o excesso, se usado, será apenas trocado.
Exemplo: mem=64M
--help
Imprime esta mensagem.
debug
essa flag não é necessária para executar gdb em UML no modo skas
root=
Isso é realmente usado pelo kernel genérico da mesma forma
que em qualquer outro kernel. Se você configurar um número de dispositivos
de bloco e quiser reiniciar a partir de algo diferente de ubd0, você
usaria algo assim:
root=/dev/ubd5
--version
Imprime o número da versão do kernel.
umid=
Isso é usado para atribuir uma identidade única a esta máquina UML e
é usado para nomear o arquivo pid e o socket do console de gerenciamento.
con[0-9]*=
Anexa um console ou linha serial a um canal host. Veja
http://user-mode-linux.sourceforge.net/old/input.html para uma descrição completa
deste comando.
eth[0-9]+=,
Configura um dispositivo de rede.
aio=2.4
Isso é usado para forçar UML a usar AIO no estilo 2.4 mesmo quando AIO 2.6 está
disponível. AIO 2.4 é uma única thread que lida com um pedido por vez,
de forma síncrona. AIO 2.6 é uma thread que usa a interface AIO 2.6
para lidar com um número arbitrário de pedidos pendentes. AIO 2.6
não está disponível no modo tt, em hosts 2.4, ou quando UML é construído com
/usr/include/linux/aio_abi.h não disponível. Muitas distribuições não incluem
aio_abi.h, portanto você precisará copiá-lo de uma árvore do kernel para
seu /usr/include/linux para poder construir um UML compatível com AIO
nosysemu
Desativa o patch de emulação de syscall para ptrace (SYSEMU).
SYSEMU é um patch de desempenho introduzido por Laurent Vivier. Isso muda
o comportamento do ptrace() e ajuda a reduzir as taxas de troca de contexto
no host. Para que funcione, você também precisará de um patch de kernel para seu host.
Veja http://perso.wanadoo.fr/laurent.vivier/UML/ para mais informações.
uml_dir=
O local para colocar os arquivos pid e umid.
quiet
Desativa mensagens de informações durante a inicialização.
hostfs=,,...
Isso é usado para definir parâmetros do hostfs. O argumento do diretório raiz
é usado para restringir todas as montagens do hostfs dentro da árvore de diretórios
especificada no host. Se isso não for especificado, um usuário dentro do UML pode
montar qualquer coisa no host que esteja acessível ao usuário que está executando.
A única flag atualmente suportada é 'append', que especifica que todos os
arquivos abertos pelo hostfs serão abertos em modo de acréscimo.Esta tela destaca os parâmetros básicos de inicialização. Vamos iniciar o núcleo com o conjunto mínimo de opções necessárias:
linux
root=/dev/root
rootfstype=hostfs
rootflags=$HOME/prefix/uml-demo
rw
mem=64M
init=/bin/shAs linhas acima dizem ao nosso núcleo o seguinte:
- Suponha que o sistema de arquivos raiz seja um pseudo-dispositivo
/dev/root. - Escolha como driver do sistema de arquivos raiz.
- Monte o sistema de arquivos do convidado que criamos no dispositivo raiz.
- E sim, no modo leitura e gravação.
- Use apenas 64 megabytes de memória RAM (você pode usar bem menos, dependendo do que planeja fazer, mas 64 MB parecem um valor ideal).
- O kernel inicia automaticamente
/bin/shcomoinit-o processo.
Execute este comando e você deve receber algo como o seguinte:
Mais uma folha
Limites de despejo de núcleo:
suave - 0
duro - NENHUM
Verificando se o ptrace pode alterar os números de chamadas do sistema...OK
Verificando patch de emulação de syscall para ptrace...OK
Verificando patch avançado de emulação de syscall para ptrace...OK
Verificando variáveis de ambiente para um tempdir...nenhum encontrado
Verificando se /dev/shm está em tmpfs...OK
Verificando PROT_EXEC mmap em /dev/shm...OK
Adicionando 32137216 bytes à memória física para compensar a lacuna do exec-shield
Versão do Linux 5.1.16 (cadey@kahless) (gcc versão 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #30 Dom Jul 7 18:57:19 UTC 2019
Listas de zonas construídas 1, agrupamento de mobilidade ativado. Total de páginas: 23898
Linha de comandos do kernel: root=/dev/root rootflags=/home/cadey/dl/uml/alpine rootfstype=hostfs rw mem=64M init=/bin/sh
Entradas da tabela de hash do cache de dentry: 16384 (ordem: 5, 131072 bytes)
Entradas da tabela de hash do cache de inode: 8192 (ordem: 4, 65536 bytes)
Memória: 59584K/96920K disponível (2692K código do kernel, 708K rwdata, 588K rodata, 104K init, 244K bss, 37336K reservado, 0K cma-reservado)
SLUB: HWalign=64, Ordem=0-3, MinObjects=0, CPUs=1, Nós=1
NR_IRQS: 15
source de relógio: timer: máscara: 0xffffffffffffffff max_cycles: 0x1cd42e205, max_idle_ns: 881590404426 ns
Calibrando loop de atraso... 7479.29 BogoMIPS (lpj=37396480)
pid_max: padrão: 32768 mínimo: 301
Entradas da tabela de hash do cache de montagem: 512 (ordem: 0, 4096 bytes)
Entradas da tabela de hash do cache de ponto de montagem: 512 (ordem: 0, 4096 bytes)
Verificando se os ptys do host suportam saída SIGIO...Sim
Verificando se os ptys do host suportam SIGIO ao fechar...Não, ativando a solução alternativa
devtmpfs: inicializado
random: get_random_bytes chamado de setup_net+0x48/0x1e0 com crng_init=0
Usando 2.6 host AIO
source de relógio: jiffies: máscara: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
Entradas da tabela de hash do futex: 256 (ordem: 0, 6144 bytes)
NET: Família de protocolo 16 registrada
source de relógio: Mudado para clocksource timer
NET: Família de protocolo 2 registrada
tcp_listen_portaddr_hash entradas da tabela de hash: 256 (ordem: 0, 4096 bytes)
Entradas da tabela de hash TCP estabelecidas: 1024 (ordem: 1, 8192 bytes)
Entradas da tabela de hash TCP bind: 1024 (ordem: 1, 8192 bytes)
TCP: Tabelas de hash configuradas (estabelecidas 1024 bind 1024)
Entradas da tabela de hash UDP: 256 (ordem: 1, 8192 bytes)
Entradas da tabela de hash UDP-Lite: 256 (ordem: 1, 8192 bytes)
NET: Família de protocolo 1 registrada
console [stderr0] desativado
mconsole (versão 2) inicializado em /home/cadey/.uml/tEwIjm/mconsole
Verificando suporte a MADV_REMOVE no host...OK
workingset: timestamp_bits=62 max_order=14 bucket_order=0
Driver SCSI genérico do bloco (bsg) versão 0.4 carregado (major 254)
agendador de I/O noop registrado (padrão)
agendador de I/O bfq registrado
loop: módulo carregado
NET: Família de protocolo 17 registrada
Driver de console stdio inicializado
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 1: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 2: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 3: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 4: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 5: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 6: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 7: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 8: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 9: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 10: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 11: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 12: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 13: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 14: Configuração falhou
Usando um tipo de canal que está configurado fora do UML
setup_one_line falhou para o dispositivo 15: Configuração falhou
Console inicializado em /dev/tty0
console [tty0] ativado
console [mc-1] ativado
Falha ao inicializar o dispositivo ubd 0: Não foi possível determinar o tamanho do arquivo do dispositivo
VFS: Sistema de arquivos root montado (sistema de arquivos hostfs) no dispositivo 0:11.
devtmpfs: montado
Esta arquitetura não possui proteção de memória do kernel.
Execute /bin/sh como processo init
/bin/sh: não pode acessar tty; controle de jobs desativado
random: inicialização rápida concluída
/ # As manipulações acima nos darão um sistema de convidado básico, sem coisas como /proc ou um nome de host atribuído. Por exemplo, tente executar os seguintes comandos:
- uname -av
- cat /proc/self/pid
- hostname
Para sair do sistema de convidado, digite sigreturn ou pressione control-d. Isso encerrará o shell com um subsequente kernel panic:
/ # exit
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
fish: “./linux root=/dev/root rootflag…” terminated by signal SIGABRT (Abort) Nós tivemos esse kernel panic porque o núcleo do Linux acredita que o processo de inicialização está sempre em execução. Sem ele, o sistema não pode mais funcionar e se desliga. Mas como esse é um processo em modo de usuário, o resultado obtido se envia para SIGABRT, o que leva ao término.
Configuração da rede de convidado
Aqui as coisas começam a sair do planejamento. A rede em User Mode Linux é o lugar onde todo o conceito de "modo de usuário" restrito começa a desmoronar. Afinal, normalmente a rede no nível do sistema é restringida por modos de execução privilegiados por razões que todos nós entendemos.
Nota do tradutor: você pode ler mais sobre as diferentes opções de trabalho com a rede em UML .
Uma jornada em slirp
No entanto, existe uma ferramenta antiga e praticamente não suportada chamada , que permite que o User Mode Linux interaja com a rede. Ela funciona mais ou menos como uma pilha TCP/IP no nível do usuário e não requer permissões do sistema para ser executada. Esta ferramenta foi lançada em 1995, com a última atualização datada de 2006.Slirp é muito antigo. Durante o tempo sem suporte e atualizações, os compiladores avançaram tanto que agora essa ferramenta só pode ser caracterizada como .
Então, vamos instalar o Slirp dos repositórios do Ubuntu e tentar executá-lo:
sudo apt-get install slirp
/usr/bin/slirp
Slirp v1.0.17 (BETA)
Copyright (c) 1995,1996 Danny Gasparovski e outros.
Todos os direitos reservados.
Este programa é protegido por direitos autorais, software livre.
Por favor, leia o arquivo COPYRIGHT que acompanha o pacote Slirp
para conhecer os termos e condições dos direitos autorais.
Endereço IP do host Slirp: 127.0.0.1
Endereço IP do seu(s) DNS(s): 1.1.1.1, 10.77.0.7
Seu endereço é 10.0.2.15
(ou qualquer outra coisa que você queira)
Digite cinco zeros (0) para sair.
[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]
SLiRP Pronto ...
fish: "/usr/bin/slirp" encerrado pelo sinal SIGSEGV (Erro de limite de endereço)Oh, meu Deus. Vamos instalar um depurador para o Slirp e ver se conseguimos entender o que está acontecendo:
sudo apt-get install gdb slirp-dbgsym
gdb /usr/bin/slirp
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /usr/bin/slirp...Reading symbols from /usr/lib/debug/.build-id/c6/2e75b69581a1ad85f72ac32c0d7af913d4861f.debug...done.
done.
(gdb) run
Starting program: /usr/bin/slirp
Slirp v1.0.17 (BETA)
Copyright (c) 1995,1996 Danny Gasparovski and others.
All rights reserved.
This program is copyrighted, free software.
Please read the file COPYRIGHT that came with the Slirp
package for the terms and conditions of the copyright.
IP address of Slirp host: 127.0.0.1
IP address of your DNS(s): 1.1.1.1, 10.77.0.7
Your address is 10.0.2.15
(or anything else you want)
Type five zeroes (0) to exit.
[autodetect SLIP/CSLIP, MTU 1500, MRU 1500, 115200 baud]
SLiRP Ready ...
Program received signal SIGSEGV, Segmentation fault.
ip_slowtimo () at ip_input.c:457
457 ip_input.c: No such file or directory.O erro ocorre na . Vamos dar uma olhada no stacktrace, talvez isso nos ajude:
(gdb) bt full
#0 ip_slowtimo () at ip_input.c:457
fp = 0x55784a40
#1 0x000055555556a57c in main_loop () at ./main.c:980
so =
so_next =
timeout = {tv_sec = 0, tv_usec = 0}
ret = 0
nfds = 0
ttyp =
ttyp2 =
best_time =
tmp_time =
#2 0x000055555555b116 in main (argc=1, argv=0x7fffffffdc58) at ./main.c:95
No locals.Aqui vemos que a falha acontece durante a execução do loop principal, quando o slirp tenta verificar os timeouts. Nesse momento, eu deveria ter desistido das tentativas de depuração. Mas vamos ver se o Slirp, construído a partir do código-fonte, funciona. Eu baixei novamente o arquivo diretamente do site , porque fazer algo a partir da linha de comando é complicado:
cd ~/dl
wget https://xena.greedo.xeserv.us/files/slirp-1.0.16.tar.gz
tar xf slirp-1.0.16.tar.gz
cd slirp-1.0.16/src
./configure --prefix=$HOME/prefix/slirp
make Aqui vemos alertas sobre funções internas indefinidas, ou seja, a impossibilidade de vincular o arquivo binário resultante. Parece que, entre 2006 e agora, o gcc parou de criar símbolos usados nas funções internas de arquivos compilados intermediariamente. Vamos tentar substituir a palavra-chave inline por um comentário vazio e ver o resultado:
vi slirp.h
:6
a
#define inline /**/
:wq
makeNão. Isso também não funciona. Ainda não consigo encontrar os símbolos dessas funções.
Neste ponto, eu desisti e comecei a procurar no Github . Minha teoria era que algum pacote de compilação do Heroku conteria os arquivos binários que eu precisava. No final, minhas buscas me levaram . Eu baixei e descompactei uml.tar.gz e encontrei o seguinte:
total 6136
-rwxr-xr-x 1 cadey cadey 79744 10 de dez. 2017 ifconfig*
-rwxr-xr-x 1 cadey cadey 373 13 de dez. 2017 init*
-rwxr-xr-x 1 cadey cadey 149688 10 de dez. 2017 insmod*
-rwxr-xr-x 1 cadey cadey 66600 10 de dez. 2017 route*
-rwxr-xr-x 1 cadey cadey 181056 26 de jun. 2015 slirp*
-rwxr-xr-x 1 cadey cadey 5786592 15 de dez. 2017 uml*
-rwxr-xr-x 1 cadey cadey 211 13 de dez. 2017 uml_run*Este é o arquivo binário slirp! E ele funciona?
./slirp
Slirp v1.0.17 (BETA) FULL_BOLT
Copyright (c) 1995,1996 Danny Gasparovski e outros.
Todos os direitos reservados.
Este programa é protegido por direitos autorais, software livre.
Por favor, leia o arquivo COPYRIGHT que veio com o pacote Slirp
para os termos e condições do copyright.
Endereço IP do host Slirp: 127.0.0.1
Endereço IP do seu(s) DNS: 1.1.1.1, 10.77.0.7
Seu endereço é 10.0.2.15
(ou qualquer outra coisa que você queira)
Digite cinco zeros (0) para sair.
[detectar automaticamente SLIP/CSLIP, MTU 1500, MRU 1500]
SLiRP Pronto ...
Não falha — então deve funcionar! Vamos colocar este binário em ~/bin/slirp:
cp slirp ~/bin/slirpCaso o criador do pacote o deletar, eu .
Configuração da rede
Agora vamos configurar a rede em nosso núcleo convidado. :
linux
root=/dev/root
rootfstype=hostfs
rootflags=$HOME/prefix/uml-demo
rw
mem=64M
eth0=slirp,,$HOME/bin/slirp
init=/bin/shAgora vamos ativar a rede:
mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2 Os primeiros dois comandos de configuração /proc e /sys são necessários para funcionar ifconfig, que configura a interface de rede para se comunicar com o Slirp. O comando rota configura a tabela de roteamento do núcleo para forçar o envio de todo o tráfego através do túnel Slirp. Vamos verificar isso com uma consulta DNS:
nslookup google.com 8.8.8.8
Servidor: 8.8.8.8
Endereço 1: 8.8.8.8 dns.google
Nome: google.com
Endereço 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Endereço 2: 2607:f8b0:4006:81b::200e lga25s63-in-x0e.1e100.netEstá funcionando!
Nota: Aparentemente, o post original foi escrito em um desktop com uma placa de rede com fio, ou alguma outra configuração que não exige drivers adicionais. No entanto, em um laptop com WiFi 8265 da Intel, ao levantar a rede, ocorre um erro
/ # ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
slirp_tramp failed - errno = 2
ifconfig: ioctl 0x8914 failed: No such file or directory
/ #Parece que o núcleo não consegue se conectar ao driver da placa de rede. A tentativa de compilar o firmware no núcleo, infelizmente, não resolveu a situação. No momento da publicação, ainda não consegui encontrar uma solução nessa configuração. Em configurações mais simples (como no Virtualbox), a interface se levanta corretamente.
Vamos automatizar o redirecionamento com o seguinte script shell:
#!/bin/sh
# init.sh
mount -t proc proc proc/
mount -t sysfs sys sys/
ifconfig eth0 10.0.2.14 netmask 255.255.255.240 broadcast 10.0.2.15
route add default gw 10.0.2.2
echo "networking set up"
exec /tini /bin/shE torná-lo executável:
chmod +x init.shE então faremos alterações na linha de comando do kernel:
linux
root=\/dev\/root
rootfstype=hostfs
rootflags=$HOME\/prefix\/uml-demo
rw
mem=64M
eth0=slirp,,$HOME\/bin\/slirp
init=\/init.sh
E repetiremos:
SLiRP Pronto ...
rede configurada
\/bin\/sh: não é possível acessar tty; controle de jobs desativado
nslookup google.com 8.8.8.8
Servidor: 8.8.8.8
Endereço 1: 8.8.8.8 dns.google
Nome: google.com
Endereço 1: 172.217.12.206 lga25s63-in-f14.1e100.net
Endereço 2: 2607:f8b0:4004:800::200e iad30s09-in-x0e.1e100.netA rede está funcionando de maneira estável!
Dockerfile
Para facilitar a verificação, compilei , que automatiza a maior parte dos passos descritos e deve fornecer uma configuração funcional. Também tenho uma , que contém tudo que foi descrito na postagem. Mas é importante entender que aqui expus apenas a configuração mínima.
Espero que esta postagem tenha ajudado você a entender como levantar um kernel convidado. Resultou em um verdadeiro monstros, mas a intenção da publicação era ser um guia abrangente sobre montagem, instalação e configuração do User Mode em Linux para as versões modernas dos sistemas operacionais dessa família. As ações subsequentes devem incluir a instalação de serviços e outros softwares já dentro do sistema convidado. Como as imagens dos containers Docker são apenas arquivos tar empacotados, você deve ser capaz de extrair a imagem através de docker export, e então determinar o caminho da sua instalação na raiz do sistema de arquivos do kernel convidado. Então, execute o script shell.
Um agradecimento especial a Rkeene com #lobsters no Freenode. Sem sua ajuda na depuração do Slirp, eu não teria chegado tão longe. Não tenho ideia de como o sistema dele Slackware funciona corretamente com slirp, mas meus sistemas Ubuntu e Alpine não aceitaram slirp e o binário proposto por Rkeene. Mas já é suficiente que eu tenha algo funcionando.
Fonte: habr.com
