Como funcionam os contêineres do Docker

Concluído

Anteriormente, você descobriu que o contêiner se torna a unidade que você usará para distribuir seus aplicativos. Você também aprendeu que o contêiner está em um formato padronizado utilizado pelas equipes de desenvolvimento e operação.

Em seu exemplo, você está desenvolvendo um portal de acompanhamento de pedidos para uso pelos diversos outlets da sua empresa. Com a imagem do Docker criada, sua equipe de operações agora é responsável por implantar, distribuir atualizações e gerenciar o portal de rastreamento de pedidos.

Na unidade anterior, você viu como é criada uma imagem do Docker. Aqui, você examinará brevemente o ciclo de vida de um contêiner do Docker e como gerenciar contêineres. Você também aprenderá a pensar em configurar o armazenamento de dados e as opções de rede para os seus contêineres.

Como gerenciar contêineres do Docker

Um contêiner do Docker tem um ciclo de vida que você pode utilizar para gerenciar e rastrear o estado do contêiner.

Um diagrama que mostra o ciclo de vida de um contêiner e a transição entre as fases do ciclo de vida.

Para colocar um contêiner em estado de execução, utilize o comando run. Também é possível reiniciar um contêiner que já esteja em execução. Ao reiniciar um contêiner, ele recebe um sinal de encerramento para habilitar qualquer processo em execução a ser desligado suavemente antes do encerramento do kernel do contêiner.

Um contêiner será considerado em estado de execução até que seja pausado, interrompido ou encerrado. Um contêiner, no entanto, também pode sair do estado em execução sozinho. Um contêiner pode ser encerrado de modo automático quando o processo em execução for concluído ou caso ele entre em um estado de falha.

Para pausar um contêiner em execução, use o comando pause. Esse comando suspende todos os processos no contêiner.

Para interromper um contêiner em execução, use o comando stop. O comando stop permite que o processo de trabalho seja desligado normalmente enviando-lhe um sinal de terminação. O kernel do contêiner será encerrado após o desligamento do processo.

Se você precisar encerrar o contêiner, use o comando kill para enviar um sinal de encerramento. O kernel do contêiner captura o sinal de encerramento, mas o processo em execução não. Esse comando encerra de maneira forçada o processo de trabalho no contêiner.

Por fim, para remover contêineres que estejam em um estado parado, use o comando remove. Após remover um contêiner, todos os dados armazenados nele serão destruídos.

Como exibir os contêineres disponíveis

Execute o comando docker ps para listar contêineres em execução. Passe o argumento -a para conferir contêineres em todos os estados.

Aqui está um exemplo:

docker ps -a

Aqui está a saída desse comando:

CONTAINER ID    IMAGE        COMMAND         CREATED       STATUS           PORTS        NAMES
d93d40cc1ce9    tmp-ubuntu:latest  "dotnet website.dll …"  6 seconds ago    Up 5 seconds        8080/tcp      happy_wilbur
33a6cf71f7c1    tmp-ubuntu:latest  "dotnet website.dll …"  2 hours ago     Exited (0) 9 seconds ago            adoring_borg

Existem três itens que devem ser analisados na saída anterior:

  • O nome da imagem listado na coluna IMAGEM; neste exemplo, tmp-ubuntu: latest. Observe como é permitido criar mais de um contêiner da mesma imagem. Esse é um poderoso recurso de gerenciamento que você pode utilizar para habilitar a colocação em escala em suas soluções.

  • O status do contêiner listado na coluna STATUS. Neste exemplo, você tem um contêiner em execução e um contêiner encerrado. O status do contêiner é geralmente o primeiro indicador da integridade do contêiner.

  • O nome do contêiner listado na coluna NOMES. Além da ID do contêiner na primeira coluna, os contêineres também recebem um nome. Neste exemplo, você não forneceu de modo explícito um nome para cada contêiner. Como resultado, o Docker deu um nome aleatório para o contêiner. Para dar um nome explícito a um contêiner usando o sinalizador --name, utilize o comando run.

Por que os contêineres recebem um nome?

Este recurso permite que você execute várias instâncias de contêiner da mesma imagem. Os nomes dos contêineres são exclusivos, o que significa que, se você especificar um nome, não poderá reutilizá-lo para criar um novo contêiner. A única maneira de reutilizar um nome específico é remover o contêiner anterior.

Como executar um contêiner

Para iniciar um contêiner, utilize o comando docker run. Somente será necessário especificar a imagem a ser executada usando seus respectivos nomes ou IDs para iniciar o contêiner por meio dela. Um contêiner iniciado desse modo fornecerá uma experiência interativa.

Nesse momento, adicione o sinalizador -d para executar o contêiner com nosso site em segundo plano.

docker run -d tmp-ubuntu

O comando, nesse caso, retorna apenas a ID do novo contêiner.

Após você especificar uma imagem a ser executada, o Docker encontra a imagem, carrega o contêiner a partir da imagem e executa o comando especificado como ponto de entrada. É nesse ponto que o contêiner fica disponível para gerenciamento.

Como pausar um contêiner

Execute o comando docker pause a fim de pausar um contêiner. Aqui está um exemplo:

docker pause happy_wilbur

A pausa de um contêiner suspende todos os processos. Esse comando permitirá que o contêiner continue executando os processos em uma fase posterior. O comando docker unpause cancela a suspensão de todos os processos nos contêineres especificados.

Como reiniciar um contêiner

Execute o comando docker restart para reiniciar contêineres. Aqui está um exemplo:

docker restart happy_wilbur

O contêiner recebe um comando parar seguido de um comando iniciar. Se o contêiner não responder ao comando stop, um sinal de encerramento será enviado.

Como interromper um contêiner

Execute o comando docker stop para interromper um contêiner em execução. Aqui está um exemplo:

docker stop happy_wilbur

O comando parar envia um sinal de encerramento para o contêiner e para os processos em execução no contêiner.

Como remover um contêiner

Execute o comando docker rm para remover um contêiner. Aqui está um exemplo:

docker rm happy_wilbur

Depois de remover o contêiner, todos os dados presentes nele serão destruídos. É essencial sempre considerar os contêineres como temporários ao pensar no armazenamento de dados.

Configuração de armazenamento de contêiner do Docker

Como descrevemos anteriormente, sempre considere os contêineres como temporários quando o aplicativo em um contêiner precisar armazenar dados.

Vamos supor que o seu portal de rastreamento crie um arquivo de log em uma subpasta na raiz do aplicativo, ou seja, diretamente no sistema de arquivos do contêiner. Quando o aplicativo gravar dados no arquivo de log, o sistema os gravará na camada de contêiner gravável.

Embora essa abordagem funcione, infelizmente ela tem várias desvantagens.

  • O armazenamento do contêiner é temporário.

    O arquivo de log não persistirá entre instâncias de contêiner. Por exemplo, vamos supor que você interrompa e remova o contêiner. Ao iniciar uma nova instância de contêiner, a nova instância se baseia na imagem especificada, e todos os dados anteriores estarão ausentes. Lembre-se de que todos os dados de um contêiner serão destruídos com ele durante a remoção.

  • O armazenamento em contêiner está acoplado ao computador host subjacente.

    É difícil acessar ou mover o arquivo de log do contêiner, pois o contêiner está acoplado ao computador host subjacente. Você tem que se conectar à instância do contêiner para acessar o arquivo.

  • As unidades de armazenamento do contêiner são menos eficientes.

    Os contêineres implementam um driver de armazenamento para permitir que seus aplicativos gravem dados. Esse driver apresenta uma abstração extra para se comunicar com o kernel do SO do host e tem desempenho menor que a gravação direta em um sistema de arquivos do host.

Os contêineres podem fazer uso de duas opções para persistir os dados. A primeira opção é fazer uso de volumes e a segunda são montagens de associação.

O que é um volume?

Um volume é armazenado no sistema de arquivos do host em uma localização de pasta específica. Escolha uma pasta em que você saiba que os dados não serão modificados por processos que não sejam do Docker.

O Docker criará e gerenciará o novo volume executando o comando docker volume create. Esse comando pode fazer parte da definição do nosso Dockerfile, o que significa que você pode criar volumes como parte do processo de criação do contêiner. O Docker criará o volume se ele não existir quando você tentar montar o volume em um contêiner na primeira vez.

Os volumes são armazenados em diretórios no sistema de arquivos do host. O Docker monta e gerencia os volumes no contêiner. Após a montagem, esses volumes serão isolados do computador host.

Vários contêineres podem usar simultaneamente os mesmos volumes. Os volumes também não são removidos automaticamente quando um contêiner para de usar o volume.

Neste exemplo, você pode criar um diretório em nosso host de contêiner e montar esse volume no contêiner ao criar o contêiner do portal de acompanhamento. Quando o portal de acompanhamento registrar dados, será possível acessar essas informações por meio do sistema de arquivos do host de contêiner. Você terá acesso a esse arquivo de log, mesmo se o contêiner for removido.

O Docker também fornece uma forma para empresas de terceiros criarem complementos para que sejam usados como volumes. Por exemplo, o Armazenamento do Azure fornece um plug-in para montar o Armazenamento do Azure como volumes em contêineres do Docker.

O que é uma montagem de associação?

Uma montagem de associação é conceitualmente igual a um volume; entretanto, em vez de utilizar uma pasta específica, você pode montar qualquer arquivo ou pasta no host. Você também espera que o host possa alterar o conteúdo dessas montagens. Assim como os volumes, a montagem de associação será criada se você a montar e ela ainda não existir no host.

As montagens de associação têm funcionalidade limitada comparado aos volumes e, embora tenham um melhor desempenho, elas dependem do host ter uma estrutura de pastas específica em vigor.

Os volumes são considerados a estratégia preferida de armazenamento de dados a ser utilizada com contêineres.

Para contêineres do Windows, outra opção está disponível: você pode montar um caminho SMB como um volume e apresentá-lo a contêineres. Isso permite que contêineres em hosts diferentes usem o mesmo armazenamento persistente.

Configuração de rede de contêiner do Docker

A configuração de rede padrão do Docker permite isolar os contêineres no host do Docker. Este recurso permite que você crie e configure aplicativos que possam se comunicar com segurança uns com os outros.

O Docker fornece configurações de rede diferentes para o Linux e o Windows.

No Linux, existem seis opções de rede pré-configuradas:

  • Ponte
  • Host
  • Sobreposição
  • IPvLan
  • MACvLan
  • Nenhum

No Windows, existem seis opções de rede pré-configuradas:

  • NAT (conversão de endereços de rede)
  • Transparente
  • Sobreposição
  • L2Bridge
  • L2Tunnel
  • Nenhum

Você pode escolher qual dessas configurações de rede aplicar ao seu contêiner, dependendo dos requisitos de rede dele.

O que é a rede de ponte?

A rede de ponte é a configuração padrão aplicada aos contêineres quando iniciada sem especificar nenhuma outra configuração de rede. Essa rede é uma rede interna e privada utilizada pelo contêiner e isola a rede do contêiner da rede do host do Docker.

Cada contêiner na ponte de rede é atribuído a um endereço IP e a uma máscara de sub-rede, com o nome do host padrão para o nome do contêiner. Os contêineres conectados à ponte de rede padrão têm permissão para acessar outros contêineres conectados à ponte pelo endereço IP. A rede de ponte não permite a comunicação entre contêineres usando nomes do host.

Por padrão, o Docker não publica nenhuma porta de contêiner. Use o sinalizador --publish da porta do Docker para habilitar o mapeamento de portas entre as portas do contêiner e as portas host do Docker.

O sinalizador de publicação configura efetivamente uma regra de firewall que mapeia as portas.

Neste exemplo, o portal de acompanhamento estará acessível para clientes que navegam usando a porta 80. Será necessário mapear a porta 80 do contêiner para obter uma porta disponível no host. Você tem a porta 8080 aberta no host, o que permite definir o sinalizador da seguinte maneira:

--publish 8080:80

Qualquer cliente que navega até o IP do host do Docker e a porta 8080 pode acessar o portal de acompanhamento.

Além das configurações específicas do Linux, a rede NAT nos hosts do Windows tem a mesma função de uma ponte de rede. Além disso, a NAT é a rede padrão no Windows, e todos os contêineres se conectarão a ela, a menos que seja especificado de outra forma.

O que é a rede do host?

A rede do host permite executar o contêiner diretamente nela. Essa configuração remove efetivamente o isolamento entre o host e o contêiner em um nível de rede.

Neste exemplo, vamos supor que você decida alterar a configuração de rede para a opção de rede do host. O portal de acompanhamento ainda poderá ser acessado usando o IP do host. Agora você pode utilizar a conhecida porta 80 em vez de uma porta mapeada.

Lembre-se de que o contêiner pode utilizar apenas portas que o host ainda não esteja usando.

No Windows, a rede do host não está disponível. Nos hosts Windows, não existe a opção de compartilhar o mesmo endereço IP (pilha de rede) entre o host e o contêiner. A rede NAT funciona como uma ponte de rede, e a opção Sobreposição fornece um endereço IP ao contêiner da mesma rede que o host, mas não o mesmo endereço IP.

Sobreposição e outras opções de rede

Para cenários mais avançados, o Linux e o Windows fornecem outras opções de rede. Por exemplo, a opção de sobreposição cria uma alternância virtual da rede do host, de modo que os contêineres nessa rede podem obter endereços IP de servidores DHCP ou operar com endereços IP desse segmento de rede. Além disso, o Docker permite que fornecedores de terceiros criem plug-ins de rede.

O que é a rede nenhuma?

Para desabilitar a rede para contêineres, utilize a opção de rede none. Isso pode ser útil se você tiver um aplicativo que não utiliza a rede ou se desejar apenas validar se um aplicativo é executado conforme esperado em um contêiner.

Considerações sobre o sistema operacional

Lembre-se de que existem diferenças entre os sistemas operacionais de desktop para as opções de configuração de rede do Docker. Por exemplo, a interface de rede Docker0 não está disponível no macOS quando se usa a rede em ponte, e o uso da configuração de rede de host não tem suporte para desktops Windows e macOS.

Essas diferenças podem afetar a maneira como os desenvolvedores configuram o fluxo de trabalho para gerenciar o desenvolvimento de contêineres. Além disso, os orquestradores de contêineres também podem fornecer outras configurações de rede além da configuração do Docker.

Verifique seu conhecimento

1.

Um contêiner é iniciado com o sinalizador --publish 8080:80. Qual das opções a seguir é a configuração de rede mais provavelmente usada para o contêiner?

2.

Qual opção de armazenamento é a melhor opção que permite que o host e o contêiner compartilhem um arquivo para gerenciar a resolução do servidor de nomes; por exemplo, o arquivo resolve.conf no Linux?