Tag Archives: lxd

LXD o virtualizador ubuntu

Este post é sobre o LXD, uma forma de criar “máquinas virtuais” que residem em directorias na nossa máquina, sem mais intermediários (hypervisors). Para quem usa docker podem ver mais info sobre o projecto e como se comparam os 2: https://www.ubuntu.com/containers/lxd.

Fica já a nota que o docker e o lxd são concorrentes, mas talvez sejam mais complementares. O docker isola componentes, o lxd isola sistemas operativos. Terão por isso vantagens e desvantagens muitas vezes simétricas. E ambos são similares na tecnologia de base que usam (lxc e chroot + cgroups). Basicamente, usam capacidades do kernel linux para isolar componentes (é por isso que só podemos “virtualizar” componentes linux e não windows ou mac). Na verdade, e para ser tecnicamente menos incorrecto, não se criam máquinas virtuais, mas sim containers. Mas para simplicidade, no resto do texto quando falo de containers ou VM’s é tudo o mesmo… containers.

Aquilo que me entusiasma no LXD é a simplicidade de uso, com muito poucos  comandos, e a facilidade de gerir sistemas que integram vários componentes, como geralmente acontece numa plataforma SIG (qgis, postgresql, geoserver, etc.). Como o LXD virtualiza um SO inteiro, é natural e fácil usá-lo para conter sistemas aplicacionais inteiros.

As máquinas LXD podem ser criadas em directorias no nosso servidor Ubuntu, e podem conter diversos sistemas operativos. E é muito fácil clonar, fazer snapshots, parar e iniciar estes contentores de SO. Já cópias de segurança obrigam a alguma ginástica, mas estão a trabalhar num método simplificado.

Também é fácil limitar os recursos usados por cada VM, quer na memória máxima, quer no processador (cores, % de tempo, etc.), e vários outros recursos. Podem ver info completa aqui: https://stgraber.org/2016/03/26/lxd-2-0-resource-control-412/.

A existência do LXD vem baixar a complexidade da virtualização baseada em containers, deixando de usar hypervisors como o KVM, OpenVZ, VMWare, VirtualBox, e HyperV.

Podemos instalar o Ubuntu directamente na máquina física, e criar VM’s usando comandos LXD. Os seus defensores indicam ganhos de desempenho, ou mais correctamente menos perda de desempenho, e por isso potencial maior densidade de VM’s. Não posso confirmar nem desmentir porque não testei nada disto. Mas parece-me algo lógico.

Só mais um detalhe – o LXD suporta nested virtualization, ou seja, dentro de uma VM Ubuntu podemos usá-lo para criar VM’s, que estão dentro da nossa VM inicial… confuso? Cuidado, que o OpenVZ não suporta lxd… portanto ao comprarem uma VPS assegurem-se que é baseada em KVM.

Nested Virtualization… whaaat?

Instalar o LXD

Instalar o LXD é muito simples – já vem incluído no Ubuntu.

É preciso no entanto iniciá-lo uma primeira vez e definir a sua configuração, que principalmente define o tipo storage usado pelas máquinas a criar (baseadas em directorias ou pools zfs), e a configuração da rede que dirá se as VM’s são acessíveis do exterior, e se poderão comunicar entre si.

O tutorial que usei como base foi este da Digital Ocean: https://www.digitalocean.com/community/tutorials/how-to-set-up-and-use-lxd-on-ubuntu-16-04.

A diferença é que escolhi usar directorias para mais simplicidade, em vez de ZFS. Embora ZFS seja a opção recomendada pela Canonical, fabricante do Ubuntu, envolve uma complexidade que seria contraproducente para mim – o objectivo é ter simplicidade máxima e o menor número de pontos de falha. Mais info aqui: https://insights.ubuntu.com/2016/02/16/zfs-is-the-fs-for-containers-in-ubuntu-16-04/.

Então, a sessão de configuração do lxd foi assim (o meu user é dncpax e as respostas estão a negrito):

$ sudo usermod --append --groups lxd dncpax
$ sudo lxd init
Do you want to configure a new storage pool (yes/no) [default=yes]? y
Name of the storage backend to use (dir or zfs) [default=dir]: dir
Would you like LXD to be available over the network (yes/no) [default=no]? no
Do you want to configure the LXD bridge (yes/no) [default=yes]? yes

Como se vê escolhi sempre os defaults.

Neste ponto, o lxd lança um wizard de configuração da rede em modo texto (podemos usar num terminal). Se respondermos sempre com defaults, vamos ter no final uma rede interna gerida pelo LXD, do tipo 10.0.0.X.

Desta forma, as VM’s poderão contactar a máquina “mãe” e outras VM’s, e também a Internet. Mas não receberão tráfego exterior, ou seja, ninguém conseguirá aceder às nossas VM’s.

(Para permitir o acesso do “exterior” às nossas VM’s LXD vamos ter de usar algum tipo de router/firewall (IPTables) ou reverse proxy (NGinx ou HAProxy). Eu escolhi usar o HAProxy, que veremos noutro artigo.)

Durante o wizard, vai ser configurada uma rede IPv4, e opcionalmente uma rede IPv6. Eu usei sempre os defaults, mas não configurei a rede IPv6:

wizard do lxd para configurar a rede
wizard do lxd para configurar a rede IPv6

A minha rede foi configurada como 10.70.99.X, e assim todas as VM’s terão um IP deste tipo.

Utilizar LXD

A partir daqui temos os comandos do lxd ao dispor. Parte são baseados em lxc e outros em lxd. (lxc é o componente de base do lxd.)

Por exemplo, ver as VM’s criadas (não há ainda) – lxc list:

$ lxc list
+------+--------+------+------+------+-----------+
| NOME | ESTADO | IPV4 | IPV6 | TIPO | SNAPSHOTS |
+------+--------+------+------+------+-----------

Nota: se tiverem um erro de permissão negada, é porque o vosso novo grupo lxd não está ainda “activo”. Podem fechar a sessão e abrir uma nova com o mesmo login e continuar o trabalho, ou executarem “newgrp lxd”.

Ver a configuração do lxd – lxc info:

$ lxc info
config: {}
api_extensions:
- id_map
- id_map_base
- resource_limits
api_status: stable
api_version: "1.0"
auth: trusted
auth_methods: []
public: false
environment:
  addresses: []
  architectures:
  - x86_64
  - i686
  certificate: |
    -----BEGIN CERTIFICATE-----
    MIIFWzCCA0OgAwIVK3ESSSDQAIgte5p8cNcFQHJo0byAjiQD2YkT/sXr+3mf5U
    bla bla bla bla
    hTuelEv1+SWzBsN2nDbF7ZUDhw4cioBS59fkWidNrg==
    -----END CERTIFICATE-----
  certificate_fingerprint: 85ab3c61 bla 6d2bae
  driver: lxc
  driver_version: 2.0.8
  kernel: Linux
  kernel_architecture: x86_64
  kernel_version: 4.4.0-109-generic
  server: lxd
  server_pid: 3276
  server_version: 2.0.11
  storage: dir
  storage_version: ""

Então o que temos por agora? Um deamon lxd que coordenará a existência e o isolamento das VM’s a criar. Podemos ver o seu estado actual com systemctl (notem a memória ocupada):

systemctl status lxd
● lxd.service - LXD - main daemon
   Loaded: loaded (/lib/systemd/system/lxd.service; indirect; vendor preset: ena
   Active: active (running) since Qui 2018-01-18 21:35:36 WET; 14min ago
     Docs: man:lxd(1)
  Process: 3315 ExecStartPost=/usr/bin/lxd waitready --timeout=600 (code=exited,
  Process: 3277 ExecStartPost=/usr/lib/lxd/profile-config (code=exited, status=0
  Process: 3265 ExecStartPre=/usr/lib/x86_64-linux-gnu/lxc/lxc-apparmor-load (co
 Main PID: 3276 (lxd)
    Tasks: 9
   Memory: 7.5M
      CPU: 438ms
   CGroup: /system.slice/lxd.service
           └─3276 /usr/bin/lxd --group lxd --logfile=/var/log/lxd/lxd.log

Jan 18 21:35:35 ubuntumin systemd[1]: Starting LXD - main daemon...
Jan 18 21:35:36 ubuntumin lxd[3276]: lvl=warn msg="CGroup memory swap accounting
Jan 18 21:35:36 ubuntumin systemd[1]: Started LXD - main daemon.

Criar e gerir VM’s

Trabalhar com VM’s ou containers LXD é muito fácil, e basicamente limita-se a estes passos:

  1. Criar o container com o OS escolhido
  2. Aceder ao container na nossa shell ou por ssh
  3. Configurar alguns limites se quisermos (de memória p.e.)
  4. Parar ou reiniciar um container
  5. Ver os detalhes de um container, incluindo memória ocupada

A melhor página que conheço sobre gestão de containers LXD é esta: https://insights.ubuntu.com/2016/03/22/lxd-2-0-your-first-lxd-container/

Então para criar uma VM de Ubuntu dentro do nosso Ubuntu ;) usamos o comando lxc launch. O sistema operativo que queremos usar pode ser escolhido de uma lista já extensa que pode ser consultada aqui: https://us.images.linuxcontainers.org/.

Antes de instalar uma máquina novinha vamos antes ver como temos a memória:

$ free -m
              total        used        free      shared  buff/cache   available
Mem:           2000          47        1501           3         451        1795

Como se vê, estamos só com 47MB usados e 451MB em cache.

Para instalar a nova vm chamada “wordpress1″ (como é a 1ª vez, a imagem é descarregada do repositório online):

$ lxc launch ubuntu:16.04 wordpress1
A criar wordpress1
A iniciar wordpress1

E pronto. Temos um novo ubuntu fresquinho. Podemos ver na lista de containers com lxc list:

$ lxc list
+------------+---------+---------------------+------+-------------+-----------+
|    NOME    | ESTADO  |        IPV4         | IPV6 |    TIPO     | SNAPSHOTS |
+------------+---------+---------------------+------+-------------+-----------+
| wordpress1 | RUNNING | 10.70.99.165 (eth0) |      | PERSISTENTE | 0         |
+------------+---------+---------------------+------+-------------+-----------+

Podemos ver a lista dos containers, se estão iniciados, e os endereços IP internos.

Para vermos a configuração de um container, incluíndo a memória usada:

$ lxc info wordpress1
Nome: wordpress1
Remote: unix://
Arquitetura: x86_64
Criado: 2018/01/18 22:20 UTC
Estado: Running
Tipo: persistente
Perfis: default
Pid: 4426
Ips:
  eth0: inet    10.70.99.165    vethWJS19I
  eth0: inet6   fe80::216:3eff:fef3:793c        vethWJS19I
  lo:   inet    127.0.0.1
  lo:   inet6   ::1
Recursos:
  Processos: 27
  Memory usage:
    Memória (atual): 31.77MB
    Memória (máxima): 152.54MB
  Network usage:
    lo:
      Bytes recebidos: 0B
      Bytes enviados: 0B
      Pacotes recebidos: 0
      Pacotes enviados: 0
    eth0:
      Bytes recebidos: 195.18kB
      Bytes enviados: 7.45kB
      Pacotes recebidos: 138
      Pacotes enviados: 90

Até agora a memória ocupada variou entre 31 e 157 MB…

Para aceder podemos usar ssh ou um comando do lxc (exec):

$ lxc exec wordpress1 -- sudo --login --user ubuntu
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@wordpress1:~

Estamos agora “dentro” da nova máquina wordpress1, com o login ubuntu… podemos ver os seus processos de forma isolada, sem acesso à máquina mãe:

$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.2  37596  5616 ?        Ss   22:20   0:00 /sbin/init
root        55  0.0  0.1  41724  3284 ?        Ss   22:20   0:00 /lib/systemd/sy
root        57  0.0  0.1  35280  3228 ?        Ss   22:20   0:00 /lib/systemd/sy
root       232  0.0  0.0  16000   856 ?        Ss   22:20   0:00 /sbin/dhclient
daemon     318  0.0  0.1  26048  2164 ?        Ss   22:20   0:00 /usr/sbin/atd -
syslog     324  0.0  0.1 186904  3288 ?        Ssl  22:20   0:00 /usr/sbin/rsysl
root       326  0.0  0.0  20104  1208 ?        Ss   22:20   0:00 /lib/systemd/sy
root       327  0.0  0.2 272872  5960 ?        Ssl  22:20   0:00 /usr/lib/accoun
root       328  0.0  0.2  65524  5476 ?        Ss   22:20   0:00 /usr/sbin/sshd
message+   329  0.0  0.1  42896  3828 ?        Ss   22:20   0:00 /usr/bin/dbus-d
root       341  0.0  0.1  26072  2528 ?        Ss   22:20   0:00 /usr/sbin/cron
root       342  0.0  1.2 158844 26576 ?        Ssl  22:20   0:00 /usr/lib/snapd/
root       350  0.0  0.4 277184  8260 ?        Ssl  22:20   0:00 /usr/lib/policy
root       378  0.0  0.0  12848  1784 ?        Ss+  22:20   0:00 /sbin/agetty --
root       441  0.0  0.1  59508  4032 ?        Ss   22:25   0:00 sudo --login --
ubuntu     442  0.0  0.2  23012  5064 ?        S    22:25   0:00 -bash
ubuntu     459  0.0  0.1  37764  3276 ?        R+   22:26   0:00 ps aux

A partir daqui podemos instalar o que quisermos da forma habitual. Podemos aceder ao exterior, mas não o inverso – do exterior aceder ao nosso container. E isso será para resolver noutro post.

Por agora, deixem-me terminar com um pequeno teste de desempenho. Uso sempre o 7zip para testes rápidos de cpu. Portanto vamos instalar o 7zip no container testar o cpu com só 1 thread, e depois fazer o mesmo na máquina mãe, para vermos neste caso a quebra de rendimento.

$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu xenial InRelease
bla bla
Fetched 24.6 MB in 10s (2276 kB/s)
Reading package lists... Done
$ sudo apt-get install 7zip-full
bla bla
Setting up p7zip-full (9.20.1~dfsg.1-4.2) ...
$ 7z b -mmt1

7-Zip [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=C.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)

RAM size:    2000 MB,  # CPU hardware threads:   2
RAM usage:    419 MB,  # Benchmark threads:      1

Dict        Compressing          |        Decompressing
      Speed Usage    R/U Rating  |    Speed Usage    R/U Rating
       KB/s     %   MIPS   MIPS  |     KB/s     %   MIPS   MIPS

22:    3917   100   3811   3810  |    41983   100   3791   3790
23:    3735   100   3806   3806  |    39076   100   3578   3577
24:    3337   100   3589   3588  |    39359   100   3652   3652
25:    3339   100   3812   3812  |    39856   100   3748   3748
----------------------------------------------------------------
Avr:          100   3755   3754               100   3692   3692
Tot:          100   3723   3723

Portanto, dentro do container temos um total de 3723 MIPS de compressão. Vamos sair do container e fazer o mesmo exercício:

ubuntu@wordpress1:~$ exit
logout
dncpax@ubuntumin:~$
dncpax@ubuntumin:~$ 7z b -mmt1

7-Zip [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18
p7zip Version 9.20 (locale=pt_PT.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)

RAM size:    2000 MB,  # CPU hardware threads:   2
RAM usage:    419 MB,  # Benchmark threads:      1

Dict        Compressing          |        Decompressing
      Speed Usage    R/U Rating  |    Speed Usage    R/U Rating
       KB/s     %   MIPS   MIPS  |     KB/s     %   MIPS   MIPS

22:    3815   100   3712   3711  |    41670   100   3762   3762
23:    3696   100   3767   3766  |    41115   100   3765   3764
24:    3557   100   3825   3825  |    40444   100   3753   3753
25:    3408   100   3891   3891  |    40016   100   3764   3763
----------------------------------------------------------------
Avr:          100   3799   3798               100   3761   3761
Tot:          100   3780   3779

Temos então na máquina LXD 3780 MIPS de compressão.

Ou seja, 3723/3780 = 98% de desempenho no container! Sim, é um teste simplista, e não representa uma avaliação real, mas é óptimo indicador.

E pronto, acabo por aqui. O próximo post da série será dedicado a coisas mais sérias, como ter várias máquinas LXD a comunicar com o exterior, e ver como limitar os recursos usados por uma delas. Até breve.