← tópicos

Específicos · Infraestrutura em TI

Docker: imagem × contêiner, Dockerfile (CMD × ENTRYPOINT), camadas, volumes, multi-stage

Imagem é molde imutável, contêiner é instância descartável — quase todo item se decide perguntando se a frase fala do tempo de construção ou do tempo de execução.

Altíssima28 itens no tópico

A ideia que organiza o assunto

O problema que o contêiner resolve tem nome antigo: na minha máquina funciona. A aplicação depende de uma versão de biblioteca, de uma variável de ambiente, de um caminho no disco — e nada disso viaja junto com o código. A máquina virtual resolvia empacotando um sistema operacional inteiro por aplicação, o que é caro demais para se repetir dezenas de vezes em um servidor.

O Docker empacota a aplicação com o seu ambiente de execução — bibliotecas, binários, arquivos da distribuição — e deixa o núcleo de fora, porque o núcleo é o do hospedeiro, compartilhado por todos os contêineres. Daí virem juntas as duas propriedades que o tópico inteiro explora: portabilidade (o pacote é o mesmo em qualquer lugar) e leveza (não há sistema convidado a manter).

E há uma segunda ideia, que decide mais itens que a primeira: existem duas linhas do tempo, e a banca vive na fronteira entre elas.

tempo de construçãotempo de execução
artefatoDockerfile → imagemcontêiner
comandodocker builddocker run, start, exec
camadassomente leitura, imutáveisuma camada gravável por contêiner
o que sobra depoistudo, na imagemnada, salvo em volume

Quem guarda essa tabela responde sozinho por que não se edita imagem pronta, por que o dado escrito dentro do contêiner some, por que a ordem das instruções do Dockerfile importa para o cache e por que EXPOSE não abre porta nenhuma.

Por que se usa (e o que custa)

Ganha-se portabilidade e densidade. O mesmo artefato sobe em desenvolvimento, homologação e produção sem readaptação de código, e, como não há hipervisor nem sistema convidado por instância, a partida é de segundos e o consumo de memória é uma fração do de uma máquina virtual equivalente.

Paga-se em três lugares. O isolamento é mais fraco: o núcleo é um só, e uma falha de núcleo alcança todos os contêineres da máquina — é por isso que a máquina virtual continua ganhando em isolamento. O estado passa a ser problema seu: a camada gravável morre com o contêiner, e persistência exige volume declarado. E surge uma cadeia de suprimento nova — imagens vindas de registries, com camadas herdadas de terceiros, que precisam ser autenticadas, verificadas e atualizadas.

A formulação honesta para a prova: o contêiner troca isolamento por eficiência e padronização. Ele não é uma máquina virtual mais leve; é outra coisa, com outro compromisso.

Como funciona

Do arquivo à imagem. O Dockerfile é texto escrito por uma pessoa, e o docker build o lê para produzir a imagem — nunca o contrário. Cada instrução gera uma camada somente leitura, e o resultado é empilhado por um sistema de arquivos em união (o driver overlay2, hoje o padrão). Como o cache é por instrução e cai a partir da primeira que mudou, a ordem manda: o que muda pouco — imagem base, instalação de dependências — vem antes; o código da aplicação, que muda a cada commit, vem por último.

Da imagem ao contêiner. docker run é create mais start: cria a camada gravável, fixa a configuração (nome, variáveis de ambiente, portas, volumes) e dispara o processo principal. Quando um arquivo da imagem é alterado dentro do contêiner, ele é primeiro copiado para a camada gravável — é a cópia na escrita — e a alteração existe apenas ali; outros contêineres da mesma imagem continuam vendo o original. Removido o contêiner, a camada vai junto.

O isolamento tem duas peças. Os namespaces isolam a visão: PID, rede, montagens, usuários. Processos no mesmo namespace se enxergam; processos em namespaces distintos, não. Os cgroups limitam o consumo: CPU, memória, E/S. Confundir as duas é o caminho mais curto para errar um item.

Persistência e rede. Sem volume, dado não sobrevive. O volume é gerenciado pelo Docker e montado no contêiner; o bind mount liga um diretório do hospedeiro. Em rede, cada contêiner tem sua própria pilha — por isso dois contêineres podem escutar na mesma porta interna —, e o acesso a partir do hospedeiro só existe com -p HOST:CONTÊINER (ou -P).

Distribuição. O registry armazena e entrega imagens: pull traz, push envia, e a conversa é por TLS, o que significa certificado e chaves. No Docker Desktop, o Registry Access Management permite à organização autorizar quais registries os desenvolvedores podem usar, filtrando por nome de domínio.

Vários contêineres. O Compose descreve serviços em um único YAML e os sobe juntos; com vários -f, o primeiro arquivo é a base e os seguintes sobrepõem. Acima disso entra o orquestrador — Kubernetes —, e boa parte dos itens deste tópico atravessa essa fronteira sem avisar.

O que decide os itens

Imagem × contêiner — a distinção de base, e a origem de metade dos erros:

imagemcontêiner
naturezamolde estático, somente leiturainstância em execução
mutabilidadeimutável; muda-se o Dockerfile e reconstrói-secamada gravável própria, descartável
identidadenome e etiqueta (tag), digestnome, PID, IP
cardinalidadeuma imagem → N contêineresum contêiner → uma imagem

O verbo do comando — leia-o antes do resto da frase:

comandofaznão faz
docker buildconstrói imagem a partir do Dockerfile (contexto local, URL de Git ou tarball)não executa
docker runcria e inicia contêiner de imagem existentenão constrói
docker createcria e configura, incluindo variáveis de ambientenão inicia
docker startinicia contêiner já criadonão recria
docker exec / attachexecuta outro processo dentro / conecta-se ao principalnão criam contêiner
docker commitgera imagem a partir do estado de um contêinernão lê Dockerfile
docker push / pullenvia / traz imagem do registrynão constrói

A instrução do Dockerfile e o seu tempoFROM, WORKDIR, COPY, ADD, RUN e USER agem na construção; CMD e ENTRYPOINT só significam alguma coisa quando o contêiner inicia; EXPOSE não age em tempo algum — é metadado.

CMD × ENTRYPOINT — em uma frase: o argumento passado no docker run substitui o CMD e é anexado ao ENTRYPOINT. O ENTRYPOINT fixa o executável; o CMD dá o comando ou os argumentos padrão.

EXPOSE × -p — o primeiro documenta em que porta o contêiner escuta (EXPOSE 80/tcp); o segundo publica a porta no hospedeiro. Só o segundo torna o serviço alcançável de fora.

Contêiner × máquina virtual — contêiner: virtualização em nível de sistema operacional, núcleo compartilhado, sem sistema convidado, isolamento por namespaces e cgroups, partida em segundos. Máquina virtual: hipervisor, sistema convidado completo com núcleo próprio, hardware virtualizado, isolamento maior e custo maior.

Namespace × cgroup — visão × consumo. Mesmo namespace significa enxergar; namespaces distintos significam isolamento.

Quem é quem no ecossistema — registry armazena e distribui imagens; Compose define e executa uma aplicação de vários contêineres a partir de um YAML; Kubernetes orquestra contêineres em um cluster; o union file system e o driver de armazenamento sustentam as camadas.

Como a CEBRASPE derruba você aqui

Os 28 itens do tópico estão explicados. Sobre os 14 de gabarito Errado, a contagem é esta: inversão 43% (6 itens), troca de termo 36% (5), e atribuição errada, generalização e relação causal com 7% cada. Os outros 14 itens são Certo — metade exata do tópico.

Docker é um dos poucos tópicos em que inversão supera troca de termo, e isso não é acidente: o assunto inteiro é feito de cadeias com direção (Dockerfile → imagem → contêiner; cluster → nó → pod → contêiner) e de ordens que importam (camadas, arquivos -f). Onde há seta, a banca a vira. A frase que resume o tópico: em Docker o erro quase nunca é uma definição — é uma seta apontando para o lado errado.

Um aviso sobre o recorte: 6 dos 28 itens (21%) mencionam Kubernetes, pod ou cluster, e o título não avisa. Dois deles são errados justamente por atribuir ao Kubernetes o que é do Docker, ou vice-versa. E 12 dos 28 (43%) trazem comando ou Dockerfile literaldocker run, docker build, docker create, docker compose -f, EXPOSE, ENTRYPOINT, RUN pip install. Este é um tópico de linha de comando tanto quanto de conceito.

A seta ou a ordem virada — 43%, a família dominante. Seis itens, e cada um é uma cadeia lida ao contrário. A cadeia de construção: “é correto criar um arquivo Dockerfile por meio do comando docker build” — o build consome o Dockerfile e produz imagem; jamais o cria. A hierarquia do cluster: “Um nó master do Kubernetes, composto por um ou mais workloads, é responsável por executar os contêineres em estruturas de pods” — o master decide, quem executa é o nó de trabalho, e é o nó que hospeda o pod, não o contrário. A ordem das camadas: “suas camadas são ordenadas da mais provável de ser alterada para a menos provável de ser alterada” — é o inverso, porque o cache é invalidado a partir da primeira instrução alterada e derruba todas as seguintes. A ordem dos arquivos do Compose: “o arquivo compose.yml especifica as configurações ou personalizações adicionais” num docker compose -f compose.yml -f compose.admin.yml — o primeiro -f é a base e quem sobrepõe é o seguinte. A condição do isolamento: “processos executados em containers nos mesmos namespaces são invisíveis entre si” — mesmo namespace é exatamente onde se enxergam; invisíveis são os de namespaces distintos, e é por compartilharem namespace que contêineres de um mesmo pod conversam por localhost. E a direção da escrita: “as alterações […] são vistas pelos múltiplos containers do mesmo sistema de arquivos” — a camada gravável é privada de cada contêiner, por cópia na escrita. Defesa, em uma regra por cadeia: monte a cadeia antes de ler o item; quem vem depois, no -f e nas camadas, vence; e compartilhado é o que é somente leitura, privado é o que é gravável.

O termo trocado, com o resto da frase intacto — 36%. Cinco itens, e eles se dividem em dois moldes. Dois trocam o verbo do comando: “O comando a seguir é capaz de fazer o build e iniciar a execução do container” seguido de um docker run (run cria e inicia a partir de imagem pronta; não constrói); e “Para construir uma imagem […] docker commit -f example-java-df” (commit fotografa o estado de um contêiner; construir de Dockerfile é docker build -f). Dois trocam o nome da tecnologia, deixando o predicado correto palavra por palavra: “Registry Docker é uma ferramenta que favorece a definição e a execução de aplicativos […] utiliza um único arquivo de configuração YAML” — isso é Docker Compose, e o registry só guarda e distribui imagens; e “O Docker utiliza sistemas de arquivos chamados de build” — o nome é union file system, com drivers como o overlay2, e “build” não é nome de sistema de arquivos nenhum. O quinto troca o tempo: “modificar diretamente a imagem Docker já criada” para acrescentar uma dependência — imagem é artefato imutável; altera-se o Dockerfile e reconstrói-se. Defesa: leia o verbo antes do efeito (build constrói, run cria e inicia, start religa, exec entra, commit fotografa, push envia); e, quando a descrição estiver perfeita, desconfie do sujeito.

O contêiner vestido de máquina virtual — 7%. “Quando se executa um container de aplicação .NET, o sistema operacional (SO) contido no convidado, ou seja, sob o SO host, com acesso ao hardware subjacente”: três marcas de máquina virtual numa linha só. Defesa: convidado, hipervisor e acesso ao hardware são vocabulário de VM; o contêiner responde por núcleo compartilhado, namespaces, cgroups e virtualização em nível de sistema operacional.

A metade verdadeira com fecho falso — 7%. “O Registry Access Management permite controlar quais registries os desenvolvedores podem acessar […]; esse recurso opera no nível de DNS e garante suporte a registries somente locais.” A primeira metade é exata; o fecho inverte o propósito do recurso, que existe para autorizar registries remotos, locais e espelhos por nome de domínio — e que, por filtrar por hostname, nem alcança registry acessado por IP. Defesa: frase ligada por ponto e vírgula ou por “e” se julga em duas partes, e basta uma falsa.

O efeito anunciado sem a opção que o produziria — 7%. Um RUN pip install -r requirements.txt apresentado como instalação “sem o armazenamento de caches, o que ajuda a reduzir o tamanho final da imagem” — sem --no-cache-dir, ou sem apagar o cache no mesmo RUN, ele fica gravado dentro da camada e aumenta a imagem. Defesa: em item com código, procure na linha a opção que sustentaria o efeito anunciado; se ela não está escrita, o efeito é inventado, e o próprio Dockerfile exibido é a prova.

Erros clássicos

Achar que se edita uma imagem pronta. Precisou de uma dependência nova? Altera-se o Dockerfile e reconstrói-se, gerando nova etiqueta. Imagem não se remenda.

Confundir EXPOSE com publicação de porta. EXPOSE documenta; -p publica. Um contêiner com EXPOSE 80 e sem -p está inacessível a partir do hospedeiro.

Trocar CMD por ENTRYPOINT. O que o usuário digita no docker run substitui o CMD e vira argumento do ENTRYPOINT.

Esperar que o dado sobreviva sem volume. A camada gravável é parte do contêiner; removido ele, o que foi escrito ali desaparece.

Tratar a porta interna como recurso escasso. Dez contêineres podem escutar na 5432 ao mesmo tempo. O que não pode repetir é a porta publicada no hospedeiro.

Confundir os papéis do ecossistema. Registry guarda imagem, Compose sobe um conjunto de serviços em uma máquina, Kubernetes orquestra em um cluster. Nenhum dos três faz o trabalho dos outros.

Praticar28 itens