Vamos falar de Docker

19/03/2021 às 11:16 Bruno Couty

Gostamos de falar da evolução por aqui... Neste post, vamos conversar um pouco mais sobre o Docker, um dos mais popupares gerenciadores de contâineres do cenário de desenvolvimento atual.

Iniciamos com a seguinte questão: O que são containers?

Segundo o próprio site oficial do Docker:

*> Um contêiner é uma unidade padrão de software que empacota o código e todas as suas dependências para que o aplicativo seja executado de maneira rápida e confiável de um ambiente de computação para outro. Uma imagem de contêiner do Docker é um pacote de software leve, independente e executável que inclui tudo o necessário para executar um aplicativo: código, tempo de execução, ferramentas do sistema, bibliotecas e configurações do sistema.

Todavia, esta é uma definição bastante genérica. Antes de seguir com uma explicação melhor sobre containers, precisamos garantir que você entende como funciona um Sistema Operacional.

Bem, salvo as diferenças, em geral, os sistemas operacionais possuem inúmeros processos sendo executados o tempo todo. Praticamente um por tarefa. Com a evolução tecnológica, o modo como estes processos são desenvolvidos também evoluiu. Entre os itens de evolução, cito a implementação de namespaces. Estes namespaces permitem que os processos possam ser "agrupados". Entenda:

Há um processo "XPTO" que é o processo "pai" e ele está sob o namespace ABC. Todos os processos decorrentes deste processo "pai" também estarão sob o namespace ABC. Deste modo, sabemos que aquele conjunto de processos fazem parte de um mesmo namespace. Isto forma um container, ou seja, Um container é composto de um processo principal e vários processos "filhos". Ainda seguindo este racioncínio, se o processo pai é "morto", os filhos são, automaticamente, encerrados também.

Em um sistema operacional, os namespaces cobrem e isolam Pid, Users, Redes, Arquivos... Assim, os containers são processos com subprocessos rodando que "emulam" um SO interno, de modo que um processo não sabe do outro.

Dito isso, vamos falar agora sobre uma ferramenta, mantida pelo Google, de muita importância aos containers: os Cgroups. O Cgroups controla os recursos computacionais do container, ou seja, pensando que os containers isolam processos, vamos imaginar um cenário onde um determinado processo utilize uma carga de memória muito maior, neste caso a máquina precisará servir muito mais memória para estes processos. A função do Cgroups é gerenciar a quantidade de recursos empregados. Por exemplo, para o processo "X" pode ser usado até 250 MB de memória e 512 de CPU.

Um terceiro ponto muito importante sobre containers é o File System. Existem alguns File Systems em containers mas nos manteremos no relecionado ao Docker, que é o OFS - Overlay File System.

Este sistema de arquivos trabalha, como sugere o nome, com camadas. Basicamente, imagine que você irá escalar sua aplicação trabalhando com virtualização. Ao escalar, você gera uma máquina virtual COMPLETA, certo? Bem como quando atualizamos a aplicação é subida uma cópia fiel, completa. No OFS o que ocorre é que as atualizações somente são aplicadas onde de fato houveram mudanças, ou seja, se você tem uma aplicação que utiliza 8 dependências, somente é alterada / escalada sua aplicação (que sofreu alteração). Assim, as depêndencias não são duplicadas. Deste modo, nós não temos um overload de volume de dados duplicados desnecessáriamente.

Interessante, não?!

Bem, seguindo, já que falamos sobre virtualização, vamos falar um pouco sobre "Imagem". Neste âmbito, quando falamos em Imagem, logo pensamos em "Snapshots", "Cópias de Estado fiéis"... No entanto, no caso de containers, Imagens não são cópias dos sistemas operacionais, mas sim das camadas. Imagine que temos uma imagem inicial, vazia (aqui, chamaremos de scratch. Digamos que você deseje adicionar um SO, o Ubuntu, talvez (lembre-se que aqui só serão baixadas as partes do SO que nós não temos). O Ubuntu terá o bash e o ssh.d instalados (leia: são camadas sob o Ubuntu). Nossa aplicação é uma camada sob o ssh.d.

Assim, quando trabalhamos com containers, as imagens trabalham com camadas de dependências.

Caso tenhamos uma nova aplicação que precise utilizar o bash, por exemplo, não haverá a necessidade de uma nova imagem replicar tudo novamente pois a mesma imagem servirá, uma vez que contém a dependência necessária.

Agora, digamos que temos um problema com o SO, no caso o Ubunto. Eventualmente, este problema impactará em toda a estrutura que está sob ele. Trabalhando com containers, podemos corrigir a camada de SO sem a necessidade de alterar o restante, fazendo o build e atualizando a camada do SO.

As imagens, então, são um conjunto de dependências encadeadas organizas em um organograma de árvore que podem possuir um nome e uma versão.

Para criar estas imagens, o Docker possui um arquivo que "descreve" / declara como será a imagem construída. Podemos criar a partir de uma imagem do zero ou baixar uma imagem pré definida e alterá-la, configurando comandos, acesso a portas e muitas outras coisas.

Se você chegou até aqui (ufa!) deve se perguntar: mas qual a vantagem disso? A resposta é simples: velocidade, organização e controle.

A utilização do Docker, além de aumentar demais a velocidade de execução e escalabilidade de suas aplicações também organiza de modo excelente suas dependências. Certamente, se você é um desenvolvedor, sabe o quanto utilizamos, diariamente, dependências associadas à nossas aplicações e, certamente, vê o valor da solução provida pelo Docker.

Bacana, não?! E ai, vamos trabalhar com Docker?