Entendendo Docker — Parte I

Pedro Santiago
nibotech
Published in
5 min readSep 6, 2019

Introdução

Este artigo é parte de uma série onde irei explicar o funcionamento do ecossistema do Docker, desde os conceitos elementares de um contêiner, passando por cada um de seus componentes básicos, até a parte de orquestração e gerenciamento. Nessa primeira parte, darei uma breve introdução do surgimento do conceito de conteinerização e explicarei o que significa submeter uma aplicação a esse processo.

Surgimento da conteinerização

Conteinerização é um conceito que surgiu há mais de 10 anos no mundo da computação. O bloco principal que formou as bases para as tecnologias posteriores de conteinerização foi o LXC, adicionado ao kernel do Linux em 2008. Ao combinar o uso de grupos de controle (cgroups) para isolar e rastrear a utilização de recursos, e namespaces para permitir que os grupos sejam separados uns dos outros, foi possível implementar o isolamento de processos de forma lightweight.

Mais tarde, em 2013, o Docker surgiu como uma forma de simplificar as ferramentas necessárias para criar e gerenciar contêineres. Inicialmente, ele usava o LXC como seu driver de execução padrão, tendo posteriormente desenvolvido a biblioteca runc para esse propósito. Embora não introduza muitas novas ideias, o Docker tornou-as mais acessíveis aos desenvolvedores e administradores de sistema, simplificando processos ao trazer uma interface padronizada.

O que é um contêiner?

Se você pensar em contêineres de transporte de carga, eles são unidades auto-contidas de alguma coisa, empilhados em embarcações, possuindo paredes que isolam o meio interno do externo e fazendo com que o único meio de comunicação seja através de suas portas. Um contêiner por si só provavelmente não flutuaria e definitivamente não seria capaz de se mover pela água. Assim, a embarcação compartilha alguns de seus recursos com o contêiner — como seu motor e sua capacidade de flutuar, por exemplo.

É assim que os contêineres funcionam com o sistema operacional do host. Os namespaces são responsáveis por isolar a execução do seu programa e suas portas são o meio de comunicação (via protocolo TCP/IP), onde o sistema host (Ubuntu, por exemplo) compartilha alguns recursos com o contêiner, como o seu kernel e sistema de arquivos.

O contêiner então consegue fazer seu próprio trabalho, em seu sistema independente. Este contêiner não se importa com o tipo de “embarcação” em que está — ele sempre conterá a mesma coisa, incluindo todas as dependências necessárias para que a aplicação funcione, independentemente de estar em um navio de guerra ou em um bote. Os recursos aos quais ele tem acesso, porém, podem mudar.

Nesta imagem, é possível ver de forma simplificada como os contêineres se relacionam com o sistema host. Os contêineres isolam aplicações individuais e usam recursos do sistema operacional que foram abstraídos pelo Docker. Na visão expandida à direita, podemos ver que os contêineres podem ser construídos por “camadas”, com vários contêineres compartilhando camadas subjacentes, diminuindo o uso de recursos repetidos.

O Docker cria contêineres com base em imagens. Uma imagem é como uma receita, definindo o que deve estar dentro do container quando ele for criado. A maneira usual de definir uma imagem é através de um Dockerfile. Um Dockerfile contém instruções sobre como construir uma imagem passo a passo.

FROM ubuntu:16.04RUN apt-get update \
&& apt-get install -y --no-install-recommends \
Python3=3.5.3-1 \
Python3-pip=9.0.1-2+deb9u1 \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt requirements.txt
RUN pip3 install --upgrade -r requirements.txt

Comparando Contêineres e Máquinas Virtuais

Os contêineres e as máquinas virtuais têm benefícios semelhantes de isolamento e alocação de recursos, mas funcionam de maneira diferente porque os contêineres virtualizam o sistema operacional em vez do hardware, tornando os contêineres mais portáteis e eficientes.

Contêineres

Os contêineres são uma abstração na camada de aplicativo que agrupa código e dependências. Vários contêineres podem ser executados na mesma máquina e compartilhar o kernel do sistema operacional com outros contêineres, cada um sendo executado como processos isolados no espaço do usuário. Os contêineres ocupam menos espaço que as VMs (as imagens de contêiner geralmente têm dezenas de MBs), podem lidar com mais aplicativos e exigem menos VMs e sistemas operacionais.

Máquinas virtuais

Máquinas virtuais (VMs) são uma abstração de hardware físico, transformando um servidor em vários servidores. O hypervisor permite que várias VMs sejam executadas em uma única máquina. Cada VM inclui uma cópia completa de um sistema operacional, o aplicativo, binários necessários e bibliotecas — ocupando dezenas de GBs. As VMs também podem ser lentas para inicializar.

Quais são as vantagens?

A utilização de contêineres implica numa série de vantagens, sendo as principais:

Modularidade

  • A abordagem do Docker para a containerização se concentra na habilidade de desativar uma parte de uma aplicação, seja para reparo ou atualização, sem interrompê-la totalmente. Além dessa abordagem baseada em microsserviços, é possível compartilhar processos entre várias aplicações da mesma maneira como na arquitetura orientada a serviço (SOA).

Camadas e controle de versão de imagens

  • Cada arquivo de imagem Docker é composto por uma série de camadas. Elas são combinadas em uma única imagem. Uma nova camada é criada quando há alteração na imagem. Toda vez que um usuário especifica um comando, como executar ou copiar, uma nova camada é criada. O Docker reutiliza essas camadas para a construção de novos contêineres, o que torna o processo de criação muito mais rápido. As alterações intermediárias são compartilhadas entre imagens, o que melhora ainda mais a velocidade, o tamanho e a eficiência. O controle de versões é inerente ao uso de camadas. Sempre que é realizada uma nova alteração, é gerado um changelog integrado, o que fornece controle total sobre as imagens do contêiner.

Reversão

  • Talvez a melhor vantagem da criação de camadas seja a habilidade de reverter quando necessário. Toda imagem possui camadas. Não gostou da iteração atual de uma imagem? Simples, basta reverter para a versão anterior. Esse processo é compatível com uma abordagem de desenvolvimento ágil e possibilita as práticas de integração e implantação contínuas (CI/CD) em relação às ferramentas.

Implantação rápida

  • Antigamente, colocar novo hardware em funcionamento, provisionado e disponível, levava dias. E as despesas e esforço necessários para mantê-lo eram onerosos. Os contêineres baseados em Docker podem reduzir o tempo de implantação de horas para segundos. Ao criar um contêiner para cada processo, é possível compartilhar rapidamente esses processos similares com novos aplicativos. Como não é necessário inicializar um sistema operacional para adicionar ou mover um contêiner, o tempo de implantação é substancialmente menor. Além disso, com a velocidade de implantação, é possível criar dados e destruir os criados pelos contêineres sem nenhuma preocupação e com facilidade e economia.

Conclusão

Por hoje, fizemos uma breve introdução a história dos contêineres e explicamos o conceito de conteinerização, mostrando uma comparação entre a utilização de máquinas virtuais. Nos próximos artigos, abordaremos mais a fundo a estrutura de um contêiner Docker, explicando sobre seus principais componentes. Até a próxima!

--

--