Contêineres com LXC – parte 1

LXC-1_site

Voltando aos contêineres em Linux. Já escrevi alguma coisa sobre o Docker e até demonstrei como usá-lo para  rapidamente colocar uma aplicação rodando. Mas ele não é a única opção disponível para trabalhar com contêineres, outra ferramenta bastante interessante é o LXC, utilizado pelo Juju como parte da infraestrutura e originalmente pelo próprio Docker — a partir da versão 0.9 ele foi substituído pelo libcontainer.

Docker × LXC

Ambos, Docker e LXC, são ferramentas que implementam virtualização ao nível do sistema operacional (ou operating-system-level virtualization, caso tenha errado na tradução). Isto quer dizer que aquilo que será virtualizado é o sistema operacional e não a arquitetura de hardware — O que acontece nos hipervisores que, para tal, precisam emular controladoras de rede, disco, vídeo etc junto.

Por este motivo um hipervisor consegue executar diversos sistemas operacionais enquanto que o Docker e o LXC estão “restritos” somente ao Linux. Seguindo a mesma lógica pode-se afirmar que um “docker” (ou “lxc”) de OS X (ou Windows) virtualizaria apenas OS X (ou Windows).

No entanto, apesar de usarem a mesma técnica, o Docker é voltado para “encaixotar” aplicações, isto, é ele funciona muito bem para executar múltiplas instâncias de Apache, MongoDB, NGINX etc enquanto que o LXC produz “sessões” completas de um sistema operacional — o que o deixa com uma experiência bem parecida a de um hipervisor.

Uma outra diferença é que o Docker trabalha de forma bem particular os conceitos de “imagem” (o que está no disco e base para criar um contêiner) e “contêiner” (o que está em execução) enquanto que no LXC eles isto é uma coisa só.

Instalação

A primeira coisa, como sempre, é a instalação. Quem usa Debian ou Ubuntu pode usar:

$ sudo apt-get install lxc

Quem usa Red Hat — CentOS, Fedora, RHEL & cia — pode fazer:

$ sudo yum install lxc

O resto é resolução de dependências, download de pacotes e a instalação propriamente dita.

Contêineres como ‘root’

Por enquanto vou trabalhar com contêineres “privilegiados”, ou seja, rodando com direitos de administrador. Logo as ferramentas do LXC serão executadas diretamente pelo usuário root (poderia fazer via sudo mas ficaria cansativo). Mais para frente tratarei dos contêineres “não privilegiados”, ou seja, executados como usuário “comum e corrente”.

Verificando a configuração

Não custa nada verificar se o seu kernel está devidamente configurado e pronto para rodar o LXC:

$ sudo lxc-checkconfig
Kernel configuration not found at /proc/config.gz; searching...
Kernel configuration found at /boot/config-3.19.0-37-generic
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
...

Se você estiver utilizando um kernel da própria distribuição é bem capaz do suporte estar corretamente habilitado, caso contrário, será possível saber o que precisará ser habilitado antes de seguir adiante.

Criando contêineres

O LXC não possui algo como o Docker Hub para centralizar diversas imagens já prontas para o uso, logo será necessário “montar” os contêineres do zero. Isto é feito usando o comando lxc-create, que tem a seguinte sintaxe:

# lxc-create -t «modelo» -n «nome do contêiner»

A parte do “nome do contêiner” é autoexplicativo enquanto que “modelo” (ou template) é basicamente um script que será executado e que contém as instruções para a baixar e montar as imagem do contêiner em uma determinada distribuição.

Para saber quais estão disponíveis, use:

$ ls -C /usr/share/lxc/templates/ | sed 's/lxc-//g'
alpine     centos    fedora        oracle  ubuntu-cloud
altlinux   cirros    gentoo        plamo
archlinux  debian    openmandriva  sshd
busybox    download  opensuse      ubuntu

Ou apenas pressione «Tab» duas vezes depois do parâmetro “-t” do lxc-create… 🙂

Uma coisa chata é que alguns dos arquivos de modelo consideram que você esteja a usar a própria distribuição da qual criará uma imagem — no meu caso “archlinux”, “openmandriva” e “opensuse” pediram ferramentas específicas para e não funcionaram aqui.

O primeiro contêiner

Criando algo familiar, um contêiner de Debian:

# lxc-create -t debian -n debian-01
debootstrap é /usr/sbin/debootstrap
Checking cache download in /var/cache/lxc/debian/rootfs-
jessie-amd64 ... 
Downloading debian minimal ...
W: Cannot check Release signature; keyring file not
available /usr/share/keyrings/debian-archive-keyring.gpg
I: Retrieving Release 
I: Retrieving Packages
...
Generation complete.

Quando executado da primeira vez, será criado via debootstrap o esqueleto (ou rootfs) de uma instalação da Jessie que ficará guardada como cache. Então, da próxima vez, ele simplesmente copiará esta estrutura para o diretório do novo contêiner. E isto será feito com qualquer distribuição.

Com o contêiner criado, por padrão eles ficarão em “/var/lib/lxc”, é hora de mexer um pouco:

# lxc-start --name debian-01
# lxc-console --name debian-01
Connected to tty 1
Type <Ctrl+a q> to exit the console, <Ctrl+a Ctrl+a> to enter
Ctrl+a itself

Debian GNU/Linux 8 debian-01 pts/0

debian-01 login: _

Opa, qual é o usuário e senha desse cara? A resposta é simples: nenhum usuário foi criado e o root está sem senha.

Em um ambiente com múltiplas instalações você pode até ficar tentado a padronizar  direto no próprio cache, fazendo um chroot em “/var/cache/lxc/debian/rootfs-jessie-amd64” para criar usuários e trocar as senhas por lá, mas…

…é possível utilizar o comando lxc-clone para criar uma cópia do contêiner, logo é muito mais elegante fazer as coisas do jeito certo:

# lxc-attach --name debian-01
root@debian-01:~# adduser giovanni
Adicionando usuário 'giovanni' ...
Adicionando novo grupo 'giovanni' (1000) ...
Adicionando novo usuário 'giovanni' (1000) com grupo 'giovanni' ...
Criando diretório pessoal '/home/giovanni' ...
Copiando arquivos de '/etc/skel' ...
...

Como já estou aqui, “bora” fazer o serviço completo instalando logo sudo e colocando meu usuário no grupo “sudo”:

root@debian-01:~# apt-get install sudo
...
root@debian-01:~# usermod --append --groups sudo giovanni

Agora é possível testar o lxc-console:

# lxc-console --name debian-01
Connected to tty 1
...
Login incorrect
debian-01 login: giovanni
Senha:Password: 
Linux debian-01 3.19.0-37-generic
...
-bash: cannot set terminal process group (399): ioctl
inapropriado para dispositivo
-bash: nenhum controle de trabalho nesta `shell'
giovanni@debian-01:~$ 
Login timed out after 60 seconds.
Debian GNU/Linux 8 debian-01 tty1
...

Confesso que tentei usar o lxc-console mas ele se mostrou um tanto arisco comigo.  :-/

Mas não vou me preocupar com isto agora pois o LXC, tal qual o Docker, cria uma interface de rede virtual:

# ifconfig lxcbr0
lxcbr0  Link encap:Ethernet  Endereço de HW fe:a3:58:29:83:ea  
        inet end.: 10.0.3.1  Bcast:0.0.0.0  Masc:255.255.255.0
        endereço inet6: fe80::ccc7:e5ff:fe28:9916/64 Escopo:Link
        UP BROADCAST RUNNING MULTICAST  MTU:1500  Métrica:1
        pacotes RX:7468 erros:0 descartados:0 excesso:0 quadro:0
        Pacotes TX:11951 erros:0 descartados:0 excesso:0 portadora:0
        colisões:0 txqueuelen:0 
        RX bytes:469771 (469.7 KB) TX bytes:16931402 (16.9 MB)

Então o meu notebook é o 10.0.3.1, agora é só descobrir qual é o endereço IP que está sendo utilizado pelo contêiner para acessá-lo via SSH:

# lxc-info --name debian-01
Name:           debian-01
State:          RUNNING
PID:            12874
IP:             10.0.3.171
CPU use:        2.76 seconds
BlkIO use:      88.95 MiB
Memory use:     65.14 MiB
KMem use:       0 bytes
Link:           vethGKYBC2
 TX bytes:      53.49 KiB
 RX bytes:      1.23 MiB
 Total bytes:   1.28 MiB

Assim:

# ssh giovanni@10.0.3.171
giovanni@10.0.3.171's password: 
...
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the
extent permitted by applicable law.
Last login: Sat Dec  5 09:58:54 2015
...

Pronto! A partir daqui é como se fosse um host qualquer, sem diferença com uma máquina física ou virtual via hipervisor.

Hora de interromper a execução deste contêiner:

# lxc-stop debian-01

Poderia tê-lo deixado rodando, ou até mesmo utilizado o lxc-freeze para suspendê-lo por um momento mas sinto que precisarei de recursos… 😈

O segundo contêiner

Agora é vez de fazer algo diferente do (meu) habitual. Que tal Gentoo?

# lxc-create -t gentoo -n gentoo-01
### set_default_arch: default arch/variant autodetect...
 => Got: arch=amd64 variant=amd64
...
You could now use you container with: lxc-start -n gentoo-01
little things you should know about your container:
=> rootfs of container is : /var/lib/lxc/gentoo-01/rootfs
=> config of container is : /var/lib/lxc/gentoo-01/config
=> timezone was staticly copyed from host
=> container has its own portage tree at /usr/portage
=> Connection user is root
=> root has the default password 'toor', please change it ASAP

Duzentos e vinte e um megabytes depois, a instalação está concluída, e “pronta” para uso pois, tal qual na Debian, precisarei criar um usuário para acessá-lo:

# lxc-attach -n gentoo-01
gentoo-01 ~ # useradd giovanni --uid 100 \
--user-group --home-dir /home/giovanni \
--create-home --shell /bin/bash
gentoo-01 ~ # passwd giovanni
New password: 
Retype new password: 
passwd: password updated successfully

Também é bom aproveitar para instalar compilar o sudo:

gento-01 ~ # emerge sudo
 * IMPORTANT: 15 news items need reading for repository 'gentoo'.
 * Use eselect news read to view new items.
Calculating dependencies... done!
>>> Verifying ebuild manifests
>>> Emerging (1 of 11) net-dns/libidn-1.30::gentoo
 * Fetching files in the background. To view fetch progress, run
 * `tail -f /var/log/emerge-fetch.log` in another terminal.
...

Pelo visto, hora de um café também:

LXC-1_compilando-o-sudo

Depois é usar visudo para acrescentar o usuário como um dos “sudoers” e assim deixar os dois contêineres funcionalmente iguais:

giovanni@gentoo-01 ~ $ sudo su -
We trust you have received the usual lecture from the local
System Administrator. It usually boils down to these three
things:

 #1) Respect the privacy of others.
 #2) Think before you type.
 #3) With great power comes great responsibility.

Password: 
gentoo-01 ~ #

Como não precisarei dele agora, hora de desligar também o Gentoo:

gentoo-01 ~ # poweroff

Sim, também funciona desta maneira.

Dica de configuração de rede

Obviamente que o acesso aos contêineres fica restrito ao host em que eles estão executando (no caso o meu notebook), então aqui vale a mesma dica usada para acessar os hosts dentro do Juju:

# route add -net 10.0.3.0 netmask 255.255.255.0 gw «host do LXC»

Sendo possível pode-se colocar esta regra no gateway padrão da rede para todos saberem como acessar os contêineres, senão, o jeito é colocar manualmente nos hosts da rede.

Fim da primeira parte

Por enquanto é suficiente, creio que tenha conseguido mostrar que Docker e LXC, apesar de usarem a mesma técnica de virtualização, funcional de forma bem diferente como também demonstrar o quando a operação do LXC é próxima a hipervisores como KVM e VirtualBox –porém sem  a necessidade daquela carga extra da emulação de hardware.

E na segunda parte irei detalhar um pouco mais a operação e os recursos disponíveis.

Anúncios

3 comentários sobre “Contêineres com LXC – parte 1

  1. Pingback: Contêineres com LXC – parte 1 - Peguei do

  2. Pingback: Contêineres com LXC – parte 3 | giovannireisnunes

  3. Pingback: Contêineres com LXC – parte 4 | giovannireisnunes

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s