Docker um novo conceito de virtualização - Parte 1

Em desenvolvimento, podemos optar por usar máquinas virtuais para facilitar o gerenciamento e provisionamento de serviços. Neste caso entra em cena a ferramenta Vagrant que facilita a criação dessas máquinas virtuais e o provisionamento de recursos de forma programática através de ferramentas como Puppet, Salt, Chef ou Ansible.

A criação e manutenção de uma máquina virtual (Virtual Box, Hyper-V ou VMWare) demanda grande quantidade de tempo, além do fato dessas máquinas virtuais consumirem uma quantidade imensa de espaço em disco.

Devido ao crescimento da demanda por máquinas virtuais e grande dificuldade na operação desse ambiente surgiu a necessidade de melhorar esse modelo. Empresas que buscam melhores soluções para administradores de sistemas, e desenvolvedores tanto do meio corporativo quanto da própria comunidade open source, perceberam que não havia a necessidade de recriar um sistema complexo bastando apenas reutilizar alguns recursos da própria arquitetura e engenharia do kernel Linux. Lançando mão de uma funcionalidade nativa do Kernel Linux, para facilitar a criação e gestão destes ambientes virtuais leves, eles conseguiram ótimos resultados. Assim surgiu o LXC.

O Linux Container ou LXC como é mais conhecido, foi lançado em 2008 e é uma tecnologia que permite a criação de múltiplas instâncias isoladas de um determinado Sistema Operacional dentro de um único hospedeiro ou em outras palavras, é uma maneira de virtualizar aplicações dentro de um servidor GNU/Linux.

O conceito é simples e antigo, sendo o comando chroot seu precursor mais famoso que foi lançado em 1979 pelo Unix V7 com o intuito de segregar acessos de diretórios e evitar que o usuário possa ter acesso à estrutura raiz (“/” ou root). Esse conceito evoluiu alguns anos mais tarde com o lançamento do comando jail, no sistema operacional FreeBSD 4.

Essa implementação já introduzia a ideia de segregação de rede e limitação dos acessos de superusuários aos processos, que passou a ser adotada, com maiores funcionalidades, pelas distribuições GNU/Linux. Posteriormente foi melhor definido em alguns sistemas como o AIX WPAR e o Solaris Containers. Nesses dois sistemas já havia o conceito de virtualização de sistema operacional, mas não o conceito de contêineres.

Nas distribuições GNU/Linux o chroot era uma maneira fácil de criar uma jail para as conexões dos servidores FTP, mas acabou ficando mais conhecido pela sua vulnerabilidade do que propriamente pela segurança que seu nome indicava implicitamente, mas acabou ajudando a cunhar um termo jailbreak.

A grande diferença entre o chroot e o LXC é o nível de segurança que se pode alcançar. Com relação à virtualização, a diferença está no fato do LXC não necessitar de uma camada de sistema operacional para cada aplicação, como pode ser visto na figura a seguir:
Ao comparar com a virtualização tradicional, fica mais claro que uma aplicação sendo executada em um LXC demanda muito menos recursos, consumindo menos espaço em disco e com um nível de portabilidade difícil de ser alcançado por outras plataformas.

Tais características tornaram o LXC uma ferramenta poderosa para criação e teste de aplicações por desenvolvedores, conquistando também os administradores GNU/Linux pela facilidade de implementar as aplicações “empacotadas” nesse modelo de virtualização.

Mas não foi só a adoção de desenvolvedores e administradores que tornou essa tecnologia recentemente tão popular. A consolidação da virtualização no mercado e a crescente demanda por computação em nuvem criaram o ambiente perfeito para o LXC se espalhar rapidamente. Aplicações podem ser portadas direto do notebook do desenvolvedor para o servidor de produção, ou ainda para uma instância virtual em uma nuvem pública.

Suas facilidades de uso ficaram evidentes ao mercado com a rápida adoção dos principais competidores de computação em nuvem, que perceberam o valor do LXC e adequaram seu catálogo para suportar essa implementação.


Hoje um dos mais conhecidos LXC's do mercado é o Docker, escrito em GO, que nasceu como um projeto open source da DotCloud, uma empresa de PaaS (Platform as a Service) que apesar de estar mais interessada em utilizar LXC apenas em suas aplicações, acabou desenvolvendo um produto que foi muito bem aceito pelo mercado.

O Docker foi ganhando espaço como uma maneira de gerenciar contêineres no ambiente GNU/Linux e, depois de um ano de sua primeira versão, surpreendeu novamente lançando sua própria biblioteca deixando de lado as bibliotecas nativas que eram utilizadas para gerenciar o LXC e assumindo o controle dos drivers diretamente com o kernel.

O Docker tira proveito do recurso de Namespaces para prover um espaço de trabalho isolado para os contêineres. Sendo assim, quando um contêiner é criado, automaticamente um conjunto de namespaces também é criado para ele como mostra a imagem a cima. O namespace cria uma camada de isolamento para grupos de processos. Por exemplo:

  • PID – Isolamento de processos.
  • NET – Controle de interfaces de rede.
  • IPC - Controle dos recursos de IPC (InterProcess Communication).
  • MNT - Gestão de pontos de montagem.

Além destes, existe também o UTC - Unix Timesharing System, que provém todo o isolamento de recursos do kernel (justamente a camada de abstração como mostra a imagem).

O que para muitos especialistas seria um erro, curiosamente para o mercado foi a criação de um padrão. Essa opção agradou aos principais mantenedores do GNU/Linux e Containers, como por exemplo a Red Hat, Canonical, a Parallels, IBM e outras empresas que passaram inclusive a contribuir com o código do Docker.

Muitos desenvolvedores fazem uso de hypervisors, como VirtualBox, para executar máquinas virtuais (VMs) que virtualizam hardware físico como parte de um desenvolvimento multi-plataforma, testes e implementação de fluxo de trabalho.

No entanto, virtualização baseada em contêiner é muito mais leve. Cada contêiner é executado como uma instância isolada de espaço do usuário de um kernel de sistema operacional de hospedagem compartilhada. Embora o sistema operacional seja compartilhado, contêineres individuais têm interfaces de rede virtuais independentes, espaços de processo independentes e sistemas de arquivos separados.

Docker torna a manipulação e administração de contêineres, um mais processo rápido e fácil do que em qualquer outro lugar. Por exemplo, em uma nuvem pública ou privada, dentro de uma VM local ou em um hardware físico.

Estes contêineres podem ser alocados com os recursos do sistema, como memória RAM, usando grupos de controle que implementam isolamento de recursos. Comparado à virtualização baseada em hipervisor, onde cada VM é executada em seu próprio sistema operacional, que só aumenta a sua utilização de recursos do sistema, os contêineres usam muito menos recursos de disco e memória.


Principais Funcionalidades do Docker

  • Contêineres facilmente portáveis: Você pode criar uma imagem de toda a configuração e aplicativos instalados em seu contêiner, transferir e instalar em um outro host desde que tenha um Docker previamente instalado.

  • Versionamento: Docker permite que você versione as alterações de um contêiner de uma forma muito semelhante ao feito pelo GIT ou SVN. Isto permite portanto verificar as diferenças entre versões, fazer commit de novas versões e fazer rollback de uma dada versão.

  • Reutilização de componentes: As imagens criadas podem ser reutilizadas, como por exemplo, se diversas de suas aplicações utilizam um stack com Java 8, Tomcat 8 e Oracle 12 você poderá criar uma uma imagem base contendo estes itens com sua instalação e configuração. Desta maneira esta imagem poderá ser reutilizada em diversos Contêineres diferentes. Podemos construir imagens Docker usando um arquivo Dockerfile e o comando de montagem docker build.

  • Compartilhamento: O Docker Hub já possui milhares de contêineres com as mais diversas aplicações instaladas e configuradas, desta maneira você pode rapidamente criar sua aplicação com uma base desenvolvida por outra pessoa, ou ainda criar sua base e compartilhá-la.

  • CLI - Command Line Interface e API - Application Program Interface: Permite criação de Programas e Scripts que interagem com o Docker para provisionar serviços nos Contêineres.

  • Automatização de Implantação dentro dos Contêineres: Usando os provisionadores que por sua vez usam a API do Docker, podemos automatizar a implantação dos ambientes de software.

  • Licença Open Source: Licenciado como Apache License, Version 2.0 mantém os códigos fonte disponíveis para facilitar o desenvolvimento colaborativo.

  • Evita Dependency Hell: Um dos maiores problemas em múltiplos ambientes com os quais os desenvolvedores de software convivem diariamente é o gerenciamento de dependências. O Docker evita problemas neste gerenciamento.

  • Demanda Poucos Recursos de Hardware: Exige poucos recursos de processos, memória e espaço em disco.

  • Performance inigualável: Por exemplo, é possível baixar uma imagem do Fedora ou Debian do repositório público na Internet em menos de um minuto e executar um comando simples num contêiner criado com esta imagem, à partir do computador Host, em menos de um segundo.

  • Ligação entre Contêineres: Conectar contêineres via mapeamentos de porta TCP/IP não é a única forma de disponibilizar recursos entre eles. Um contêiner Docker pode se conectar a um outro via um sistema de ligação e enviar informações de um para o outro de forma eficiente e segura. Quando os contêineres estão ligados, a informação sobre o contêiner origem pode ser enviada para um contêiner destino.

Ainda é cedo para se dizer que é o fim da virtualização de servidores como a conhecemos hoje. Acredito que muitas aplicações serão reescritas para suportar o uso de contêineres de forma adequada. Alguns sistemas operacionais ainda serão repensados para suportar o LXC nativamente visto que esta tecnologia pode vir a ameaçar tudo o que conhecemos em termos de inovação em ambiente virtual hoje.

E também alguns paradigmas deverão ser quebrados para que essa tecnologia seja amplamente utilizada pelo mercado, exatamente como aconteceu há alguns anos com a virtualização de servidores.

Aqui no LEMAF, por exemplo, já estamos usando um servidor com o Docker. Estamos rodando serviços como o Rocket.Chat, o p2p/reepio, o servidor do próprio blog, uma versão do nginx e outros serviços como Mongodb etc... O objetivo é tornar todo o ambiente de desenvolvimento interno em servidores docker.

Até um próximo post, e espero que tenham gostado da abordagem dada a este material.


Sugestão para estudo: