LinuxKit

Docker cresceu bastante no último ano, atendendo as demandas dos usuários que solicitavam suporte nativo para os ambientes que estavam usando. Essas demandas eram carregadas de desafios técnicos já que muitos dos ambientes não tinham um subsistema Linux, necessário para executar os containers.

Ao projetar o subsistema Linux que atenderia as demandas, o time de desenvoledores do Docker em conjunto com empresas parceiras como Intel, IBM, ARM e Microsoft, trabalharam para que o projeto fosse modular, compacto, seguro e principalmente portátil. Os frutos desse trabalho foram os projetos Docker para Mac, Windows, AWS, Azure e Google Cloud.

Na DockerCon 2017 o código fonte do kit usado na construção de todas as plataformas foi aberto e apresentado ao público como LinuxKit, um conjunto de ferramentas que possibilita a construção de sistemas operacionais especializados para containers.

Como funciona ?

No LinuxKit tudo é construído dentro de um container. Quer dizer que não é necessário instalar dependências e isso torna o uso fácil. Dependendo da plataforma escolhida para executar o Kernel, a ferramenta fornece diferentes saídas: iso-bios, iso-efi, gcp-img ou ainda kernel + initrd.

Essa imagem do kernel gerada é uma imagem do Docker com um arquivo bzImage para o kernel a ser executado de fato, e um arquivo kernel.tar que contém alguns módulos.

A ferramenta chamada moby (se você não viu nada sobre moby ainda) converte um arquivo de especificação yaml em uma ou mais imagens inicializáveis.

Esse arquivo yaml é utilizado para descrever o kernel bem como os aplicativos e serviços necessários. Veja o exemplo:

  • Kernel é a especificação de uma imagem Docker do kernel, essa imagem contém uma versão de kernel e um tarball do sistema de arquivos, ou seja, os módulos do sistema.

  • init é a base init do sistema também especificado em uma imagem Docker, que é descompactado como o sistema base, nesse caso: init, containerd, runc e outras ferramentas.

  • onboot traz os containers do sistema que são executados em ordem sequencial.

  • services são os serviços, que normalmente funcionam durante todo o tempo em que o sistema está ativo.

  • outputs formata a saída no processo de build para diferentes plataformas, são como arquivos ISOs.

Note que em quase todas as seções existe a palavra-chave image, pois tudo é aplicado em containers.

Um pouco de prática

Para esse exemplo é necessário ter uma versão recente do Golang e Docker instalados e claro o clone do projeto:

$ git clone https://github.com/linuxkit/linuxkit.git

Em seguida é preciso gerar o binário que vai fornecer o CLI da ferramenta, o moby:

$ cd linuxkit
$ make
$ cp bin/moby /usr/local/bin/
$ moby
Please specify a command.

USAGE: moby [options] COMMAND

Commands:
  build       Build a Moby image from a YAML file
  run         Run a Moby image on a local hypervisor or remote cloud
  version     Print version information
  help        Print this message

Run (moby COMMAND --help) for more information on the command

Options:
  -q    Quiet execution
  -v  Verbose execution

O projeto possui alguns exemplos prontos e neste caso utilizaremos um do Google Cloud Platform. Os exemplos ficam em examples/, antes de executar é necessário ter uma conta GCP configurada. Você pode instalar o SDK do Google seguindo essas instruções https://cloud.google.com/sdk/. Em seguida:

$ export CLOUDSDK_CORE_PROJECT=infoslack-1337
$ export CLOUDSDK_COMPUTE_ZONE=us-east1-b
$ gcloud auth login

Depois de realizar a autenticação na conta do Google podemos executar o exemplo:

$ cd examples
$ moby build gcp.yml
$ ls
6.7M -rw-r--r-- 1 root root 6.7M Apr 22 21:24 gcp-bzImage
4.0K -rw-r--r-- 1 root root   27 Apr 22 21:24 gcp-cmdline
 57M -rw-r--r-- 1 root root  57M Apr 22 21:25 gcp.img.tar.gz
 50M -rw-r--r-- 1 root root  50M Apr 22 21:24 gcp-initrd.img
4.0K -rw-r--r-- 1 root root 1.9K Apr 22 21:20 gcp.yml

O arquivo principal gerado é o gcp.img.tar.gz com 57MB, agora só precisamos realizar o upload do mesmo para o Google e iniciar o sistema, hora de chamar o moby mais uma vez:

$ moby run gcp -project infoslack-1337 gcp.img.tar.gz

Esse procedimento leva alguns minutos e no final estaremos logados dentro da instância que foi criada. Agora podemos verificar se os serviços que são containers estão em execução, neste exemplo por padrão teremos como container manager o Runc:

$ runc list
ID          PID         STATUS      BUNDLE
nginx       759         running     /containers/services/nginx
rngd        798         running     /containers/services/rngd
sshd        797         running     /containers/services/sshd

Na listagem recebemos os 3 serviços em execução: Nginx, SSHD e o rngd que é um serviço para o kernel. Agora podemos fazer um request no ip público da instância e verificar se o Nginx responde corretamente:

$ http -h 104.196.170.124
HTTP/1.1 200 OK
Accept-Ranges: bytes
Connection: keep-alive
Content-Length: 612
Content-Type: text/html
Date: Sun, 23 Apr 2017 00:55:56 GMT
ETag: "58e66cf5-264"
Last-Modified: Thu, 06 Apr 2017 16:29:41 GMT
Server: nginx/1.11.13

Touché! O container do Nginx respondeu corretamente. Ao final deste exemplo foi possível produzir um sistema operacional especializado para executar containers, enviar para o cloud do Google e ver um serviço em funcionamento. O tempo gasto entre geração de imagem e upload para cloud foi de aproximadamente 10 minutos. PS: minha conexão não estava muito estável durante os testes.

Conclusão

Apesar do projeto estar em fase inicial já da para ter uma ideia do seu potencial e perceber a forte inspiração nos Unikernels já que um dos objetivos é prover um sistema operacional imutável. Acredito que daqui em diante projetos como RancherOS farão bom uso dessa ferramenta e teremos também opções de plataformas automatizadas para construção de sistemas operacionais com foco em containers como é o caso RACKN que já está fazendo algo com LinuxKit + Kubernetes.

Happy Hacking ;)

Referências

Comentários