Containers & Deployment

Docker & Deployment

O Docker empacota sua aplicação e seu ambiente em uma imagem que roda da mesma forma em qualquer lugar. Multi-stage builds, caching e CI/CD transformam o deployment em uma etapa repetível.

intermediate14 min readUpdated 15 de set. de 2026
Dockerfile
dockerfile
// Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Image
Um template somente leitura
Container
Uma imagem em execução
Build file
Dockerfile
Layers
Cacheadas e reutilizadas
Compose
Apps de múltiplos serviços
Registry
Onde as imagens são armazenadas

Por que importa

Por que os containers venceram a história do deployment

Consistente em qualquer lugar

A imagem inclui o SO, o runtime e as dependências, portanto, roda da mesma forma no seu laptop, no CI e em produção.

Isolado por padrão

Containers compartilham o kernel do host, mas isolam processos, sistemas de arquivos e redes, o que limita o raio de impacto de falhas.

Portátil e escalável

A mesma imagem roda em qualquer host de container, o que torna a escalabilidade e a migração entre nuvens algo simples.

O panorama completo

As três ideias por trás do Docker

Uma imagem é o build, um container é a execução, e um registry é como as imagens viajam entre máquinas.

A imagem

Build

Um template de camadas, somente leitura, construído a partir de um Dockerfile.

O container

Run

Uma instância em execução de uma imagem, com seu próprio processo e sistema de arquivos.

O registry

Distribute

Um repositório de imagens de onde o CI e a produção fazem o download.

Docker em resumo

O núcleo do Docker

Dockerfile

Instruções que constroem uma imagem camada por camada.

Layers e cache

Cada instrução é uma camada cacheada, portanto, etapas inalteradas são reutilizadas.

Multi-stage builds

Construa em uma etapa e envie apenas o resultado final em uma imagem menor.

Compose

Defina e execute apps de múltiplos containers, como uma aplicação mais um banco de dados.

Registry

Faça push e pull de imagens do Docker Hub, GHCR ou de um registry privado.

CI/CD

Construa, teste e faça o deploy automaticamente a cada alteração.

Uma breve historia

De VMs para containers e CI/CD

  1. 2013

    Lançamento do Docker

    Containers tornam-se acessíveis para desenvolvedores comuns.

    13
  2. 2015

    Compose e orquestração

    Compose e Kubernetes tornam deploys de múltiplos serviços viáveis.

    15
  3. 2017

    Multi-stage builds

    Imagens de produção menores tornam-se a prática padrão.

    17
  4. 2020

    Containers em todo lugar

    CI/CD baseado em containers e plataformas de containers serverless tornam-se comuns.

    20
  5. Hoje

    A base do deployment

    A maioria dos sistemas de produção é entregue como imagens de container.

    Hoje

O guia completo

Docker & Deployment: Tudo que voce precisa saber

Por que os containers venceram

Antes dos containers, fazer o deploy significava reproduzir um ambiente: a versão correta do runtime, as bibliotecas de sistema adequadas, a configuração certa. “Na minha máquina funciona” era um problema real, e os servidores divergiam do ambiente de desenvolvimento com o passar do tempo.

O Docker resolveu isso empacotando a aplicação e seu ambiente em uma única imagem. A imagem roda de forma idêntica em um laptop, no CI e em produção, porque ela carrega tudo o que precisa. Essa consistência é o motivo pelo qual os containers se tornaram a base para o deployment, e por que aprender Docker é uma das habilidades de maior valor para entregar software.

Imagens e containers

Uma imagem é um template de apenas leitura construído a partir de um Dockerfile, composto por camadas em cache. Um container é uma instância em execução de uma imagem, com sua própria camada de escrita, processo e rede. Você constrói uma vez e executa várias.

docker build -t my-app:1.0 .
docker run -p 3000:3000 my-app:1.0
docker ps
docker logs <container>

A flag -p mapeia uma porta do host para uma porta do container. Containers são efêmeros por design: você pode pará-los, removê-los e recriá-los livremente, pois a imagem é a fonte da verdade.

O Dockerfile

O Dockerfile é a receita de build. Cada instrução cria uma camada.

# Dockerfile
FROM node:22-alpine
WORKDIR /app

# install dependencies first for better caching
COPY package*.json ./
RUN npm ci --omit=dev

# then copy source
COPY . .

ENV NODE_ENV=production
EXPOSE 3000
USER node
CMD ["node", "server.js"]

A ordem é fundamental. Copiar os manifestos de dependências e instalá-los antes de copiar o código-fonte significa que uma alteração no código invalida apenas a camada de source (que é leve), e não a de instalação (que é pesada). npm ci garante uma instalação reprodutível, e USER node executa o processo como um usuário não-root.

Cache de camadas

O Docker faz o cache de cada camada e a reutiliza quando as entradas não são alteradas. É por isso que a ordem acima é deliberada: coloque as coisas que mudam raramente no topo e as que mudam com frequência na parte inferior.

# cached unless package files change
COPY package*.json ./
RUN npm ci

# invalidated on every source change
COPY . .

Um arquivo .dockerignore também é importante. Sem ele, node_modules, .git e a saída do build são copiados para o contexto de build, o que torna o processo mais lento e pode vazar arquivos para a imagem.

node_modules
.git
dist
.env

Builds de múltiplos estágios (Multi-stage builds)

Um build de múltiplos estágios compila em uma imagem e entrega apenas o resultado final em outra.

# Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

A imagem final contém apenas os arquivos estáticos compilados e um servidor web, e não o runtime do Node, o código-fonte ou as ferramentas de build. O resultado é menor, mais rápido para fazer o pull e possui uma superfície de ataque muito menor. Para um app de servidor, o estágio final seria uma imagem slim do Node apenas com as dependências de produção.

Compose para apps de múltiplos serviços

Aplicações reais geralmente precisam de mais de um processo. O Compose define todos eles juntos.

# docker-compose.yml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://db:5432/app
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - data:/var/lib/postgresql/data

volumes:
  data:

O depends_on controla a ordem de inicialização, o volumes persiste os dados entre reinicializações de containers, e os serviços se comunicam entre si pelo nome na rede compartilhada. O Compose é ideal para desenvolvimento local e deploys simples em um único host.

Registries e CI/CD

As imagens trafegam por um registry, como Docker Hub, GitHub Container Registry ou um registry privado. Um pipeline típico segue estes passos:

  1. Instala as dependências e executa os testes.
  2. Faz o build da imagem e a tagueia com o SHA do commit.
  3. Faz o push para o registry.
  4. Faz o deploy da nova tag para o ambiente de destino.
docker build -t ghcr.io/me/app:$GIT_SHA .
docker push ghcr.io/me/app:$GIT_SHA

Como a imagem é imutável e tagueada por commit, os rollbacks consistem apenas em fazer o deploy de uma tag anterior. Este é o núcleo de um processo de deployment confiável: faça o build uma única vez, promova o mesmo artefato entre os ambientes e nunca refaça o build para produção.

Práticas de produção

  • Health checks. Exponha um endpoint que a plataforma possa monitorar para saber se o container está pronto.
  • Usuário não-root. Execute a aplicação com um usuário que possua apenas os privilégios mínimos necessários.
  • Sistema de arquivos somente leitura sempre que possível, com volumes de escrita explícitos.
  • Graceful shutdown. Trate o sinal SIGTERM para finalizar as requisições em andamento.
  • Limites de recursos. Defina limites de CPU e memória para que um container não consuma todos os recursos dos demais.
  • Fixe as versões da imagem base para garantir builds reproduzíveis.
  • Secrets em tempo de execução, nunca embutidos na imagem.
  • Imagens base pequenas, como Alpine ou distroless, para reduzir vulnerabilidades.

Melhores práticas

  • Ordene as instruções do Dockerfile da que muda com menos frequência para a que muda mais.
  • Use multi-stage builds e envie apenas o que for necessário.
  • Adicione um .dockerignore para node_modules, .git, dist e .env.
  • Execute como um usuário não-root.
  • Faça o tag das imagens pelo SHA do commit, não apenas latest.
  • Construa a imagem uma única vez e a promova entre os ambientes.
  • Trate SIGTERM para um desligamento seguro (graceful shutdown).

Erros comuns

  • Copiar node_modules para dentro da imagem.
  • Executar como root.
  • Embutir secrets na imagem ou commitar .env.
  • Usar latest como a única tag e perder a reprodutibilidade.
  • Reconstruir a imagem de forma diferente para cada ambiente.
  • Ignorar .dockerignore e criar builds enormes e lentos.

Próximos passos

Containers tornam o deployment previsível, e as mesmas habilidades se aplicam independentemente de você publicar em uma VM, Kubernetes ou em uma plataforma de containers serverless. Consolide o runtime com o guia de Node.js, gerencie as dependências com npm, sirva a aplicação via HTTP e reforce a proteção com Web Security. Depois, transforme um app pequeno em um container e faça o deploy de ponta a ponta.

Construindo a imagem

Um multi-stage build mantém as ferramentas de build fora da imagem final, tornando-a menor e reduzindo a superfície de ataque.

Preferir
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
Evitar
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/server.js"]
# ships dev deps, source
# and build tools

Executando como usuário

Execute o container como um usuário não-root para que uma invasão não consiga escalar privilégios facilmente no host.

Preferir
FROM node:22-alpine
WORKDIR /app
COPY --chown=node:node . .
USER node
CMD ["node", "server.js"]
Evitar
FROM node:22-alpine
WORKDIR /app
COPY . .
# runs as root by default
CMD ["node", "server.js"]

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Docker & Deployment?

Nosso tutorial interativo te guia por Docker & Deployment passo a passo — com quizzes e codigo real que voce pode executar no navegador.