O caso

Funcionava na minha máquina. No servidor, não.

O Isaac desenvolveu o sistema de pedidos com uma versão de Python no notebook. No servidor, havia outra versão, e uma biblioteca faltava. Ele passou a tarde instalando dependências à mão, e cada servidor novo repetia o problema.

Uma VM por aplicação resolveria, mas cada uma carregaria um sistema operacional inteiro só para rodar um programa.

Este post parte de Kernel, de Processos e Threads e de Máquinas Virtuais.

O problema

O programa depende do ambiente

Um programa não roda sozinho: ele depende de uma versão de linguagem, de bibliotecas, de configurações do sistema. Quando o ambiente de desenvolvimento e o de produção são diferentes, o mesmo código se comporta de formas diferentes.

A VM resolve a separação, mas com um custo: cada aplicação traz o próprio kernel e o próprio sistema operacional, com memória, disco e tempo de inicialização próprios.

A solução

Container: um processo isolado

Um container é um processo comum, rodando no kernel do próprio servidor, com duas coisas que o isolam: o que ele enxerga e o que ele pode usar. Não há um segundo kernel. Por isso, um container inicia em segundos e ocupa pouca memória extra.

Namespaces (o que ele vê)

Cada container tem a sua visão de processos, rede, pontos de montagem e usuários. Dentro dele, o programa acredita que está sozinho.

Na loja: o sistema de pedidos enxerga apenas os próprios processos e a própria porta de rede.

cgroups (o que ele pode usar)

O kernel limita quanto de CPU e de memória o grupo de processos pode consumir.

Na loja: o relatório não consegue tomar a memória que o sistema de pedidos precisa.

Imagem (o pacote)

Um pacote com o sistema de arquivos e as dependências da aplicação, que roda igual em qualquer servidor.

Na loja: o mesmo pacote roda no notebook do Isaac e no servidor.

Não confunda

Container × VM

Container

“Preciso de outro kernel, ou só de um processo isolado?”

Exemplo
Dez instâncias do sistema de pedidos no mesmo servidor, compartilhando o kernel.
Foco
Inicia em segundos, ocupa pouca memória extra, mas o kernel é compartilhado.

Máquina virtual

“Preciso de um sistema operacional diferente, ou de isolamento mais forte?”

Exemplo
Um sistema Windows rodando num servidor Linux, ou clientes que não podem dividir o kernel.
Foco
Cada VM tem o seu kernel. Isolamento mais forte, com mais custo de memória e de inicialização.

Por dentro

Namespaces e cgroups

Os namespaces e os cgroups são recursos do kernel Linux. Um container é, na prática, um processo que o kernel colocou dentro de um conjunto de namespaces e de um cgroup.

  • Namespace de processos: o container enxerga só os próprios processos, e o processo principal dele aparece com um número próprio, como o PID 1.
  • Namespace de rede: cada container tem as suas interfaces e as suas portas.
  • Namespace de montagens: o container vê o próprio sistema de arquivos, montado a partir da imagem.
  • cgroup: define limites de CPU e de memória, e conta o que o grupo consome.

Como tudo isso acontece no kernel, um container que estoura a memória é encerrado pelo kernel, do mesmo jeito que um processo comum, e não derruba o servidor.

Empacotar

Imagem e registro

Uma imagem é um pacote imutável: as camadas do sistema de arquivos e a configuração de como iniciar o programa. Cada camada é reaproveitada: duas imagens que partem da mesma base dividem essa base no disco.

Um container é uma instância de uma imagem em execução. Ele recebe uma camada gravável por cima, e tudo o que ele escreve nessa camada some quando o container é removido.

As imagens ficam num registro (registry), de onde os servidores as baixam. Quem quer dados que sobrevivam ao container usa um volume, que é uma área de armazenamento montada nele.

Na prática

Limitar e rodar

Com o Docker, uma das ferramentas mais conhecidas, um comando inicia um container com limites de memória e de CPU:

bash
docker run --memory 512m --cpus 1 nginx

O comando baixa a imagem do nginx, cria os namespaces, aplica o cgroup e inicia o processo. Quem consome mais de 512 MB é encerrado, e os outros containers do servidor continuam rodando.

SituaçãoEscolha
Vários serviços Python com versões diferentes, no mesmo servidorContainers
Um sistema Windows e um Linux no mesmo hardwareVM
Dados de um banco que precisam sobreviver ao containerVolume, ou um serviço gerenciado de banco
Atualizar a aplicação sem mexer no servidorTrocar a imagem e reiniciar o container

Termos-chave

Seis termos para recordar

Toque no cartão para ver a definição.

Teste rápido

Três perguntas, estilo prova

01

Dois containers rodam no mesmo servidor. O que eles compartilham?

02

Um time quer que um banco de dados mantenha os arquivos mesmo depois que o container é removido. O que deve usar?

03

Qual recurso do kernel limita quanta memória um container pode usar?


Container resolve o problema de empacotar e de isolar a aplicação, sem pagar um sistema operacional inteiro por ela. Entender os namespaces e os cgroups mostra o que é isolado e o que não é, e por isso a escolha entre container e VM depende do risco que você aceita e do sistema operacional de que precisa. O próximo passo é ver como essas peças rodam na nuvem.