Um Guia para Iniciantes sobre Imagens e Contêineres Docker
Você acabou de entrar em uma equipe de frontend, e todos estão falando sobre “subir contêineres” e “baixar imagens”. Sua aplicação React funciona perfeitamente na sua máquina, mas fazer o deploy parece um mistério. Docker resolve exatamente esse problema—e entender os fundamentos de imagens Docker é mais simples do que você imagina.
Este guia aborda o que são imagens e contêineres Docker, como eles se relacionam entre si, e como usá-los no seu fluxo de trabalho frontend para desenvolvimento local, testes e deploys simples.
Pontos-Chave
- Imagens Docker são blueprints somente leitura, enquanto contêineres são instâncias em execução dessas imagens.
- Use tags explícitas como
node:20-alpineem vez delatestpara builds previsíveis e reproduzíveis. - Builds multi-estágio mantêm suas imagens de produção pequenas e seguras.
- Nunca armazene dados persistentes dentro de contêineres—use volumes.
- Execute contêineres como usuários não-root e escaneie imagens regularmente em busca de vulnerabilidades.
O Que São Imagens e Contêineres Docker?
Uma imagem Docker é um pacote somente leitura contendo tudo o que é necessário para executar uma aplicação: código, runtime, bibliotecas e configuração. Pense nela como uma classe em programação orientada a objetos—um blueprint que define a estrutura mas não executa nada por si só.
Um contêiner é uma instância em execução dessa imagem. Quando você executa docker run, o Docker cria um ambiente isolado a partir da imagem onde sua aplicação realmente roda. Você pode criar múltiplos contêineres a partir da mesma imagem, cada um operando independentemente.
Essa distinção entre imagem Docker vs contêiner é importante: imagens são templates estáticos armazenados em disco, enquanto contêineres são processos ativos com seu próprio sistema de arquivos e rede.
Imagens Docker seguem a especificação OCI (Open Container Initiative), o que significa que funcionam em diferentes runtimes de contêiner—não apenas Docker. Essa padronização garante que suas imagens permaneçam portáveis.
Entendendo Registries e Tags
Imagens ficam armazenadas em registries—sendo o Docker Hub o público mais comum. Quando você referencia uma imagem como node:20-alpine, você está especificando um repositório (node) e uma tag (20-alpine).
Aqui está algo que confunde iniciantes: a tag latest não é mágica. Ela não aponta automaticamente para a versão mais recente. É simplesmente uma tag padrão que os mantenedores da imagem podem ou não atualizar. Sempre use tags explícitas como node:20-alpine para builds previsíveis.
Executando Seu Primeiro Contêiner
Vamos executar um contêiner simples usando a imagem oficial do Node.js:
docker run -it --rm node:20-alpine node -e "console.log('Hello from Docker!')"
As flags -it habilitam o modo interativo com um terminal. A flag --rm remove automaticamente o contêiner quando ele encerra.
Para um exemplo mais prático, você pode executar um servidor de desenvolvimento. Primeiro, crie um diretório de projeto com seu código frontend, depois:
docker run -d -p 3000:3000 -v $(pwd):/app -w /app node:20-alpine sh -c "npm install && npm run dev"
A flag -d executa o contêiner em segundo plano. O -p 3000:3000 mapeia a porta 3000 dentro do contêiner para a porta 3000 na sua máquina. A flag -v monta seu diretório atual no contêiner, e -w define o diretório de trabalho.
Construindo Imagens Personalizadas com Dockerfiles
Para projetos reais, você criará imagens personalizadas. Aqui está um Dockerfile para uma aplicação React:
FROM node:20-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
Isso demonstra um build multi-estágio—uma prática essencial do Docker. O primeiro estágio constrói sua aplicação; o segundo estágio copia apenas os arquivos de produção para uma imagem nginx mínima. Sua imagem final permanece pequena e segura.
Construa e execute:
docker build -t my-frontend-app .
docker run -d -p 8080:80 my-frontend-app
Discover how at OpenReplay.com.
Volumes Docker e Persistência
Contêineres são efêmeros—quando eles param, quaisquer dados escritos dentro deles desaparecem. Para desenvolvimento local, use bind mounts para sincronizar seu código-fonte:
docker run -v $(pwd)/src:/app/src -p 3000:3000 my-frontend-app
Para dados que precisam persistir (como arquivos de banco de dados), use volumes nomeados:
docker volume create app-data
docker run -v app-data:/data my-app
Entender volumes Docker e persistência é essencial: nunca armazene dados importantes apenas dentro do sistema de arquivos de um contêiner.
Fundamentos de Segurança Docker
Algumas práticas mantêm seus contêineres mais seguros:
Execute como não-root. Adicione um usuário no seu Dockerfile:
RUN adduser -D appuser
USER appuser
Use imagens base mínimas. Imagens baseadas em Alpine têm menos vulnerabilidades do que distribuições completas.
Escaneie imagens regularmente. Ferramentas como Docker Scout ou Trivy identificam vulnerabilidades conhecidas.
Nunca incorpore secrets nas imagens. Variáveis de ambiente ou ferramentas de gerenciamento de secrets lidam com credenciais—codificá-las diretamente cria riscos de segurança que persistem nas camadas da imagem.
Simplificando Configurações Multi-Contêiner com Compose
Quando seu frontend precisa de uma API backend e banco de dados localmente, o Docker Compose orquestra tudo:
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
api:
build: ./api
ports:
- "4000:4000"
Execute docker compose up e ambos os serviços iniciam juntos. Use docker compose down para parar e remover todos os contêineres.
Conclusão
Imagens Docker são blueprints; contêineres são instâncias em execução. Mantenha imagens pequenas com builds multi-estágio, use tags explícitas em vez de latest, separe estado dos contêineres usando volumes, e reconstrua imagens regularmente para capturar atualizações de segurança. Esses fundamentos servirão você tanto ao executar um ambiente de desenvolvimento quanto ao fazer deploy de uma aplicação frontend simples.
Perguntas Frequentes
Uma imagem Docker é um template somente leitura contendo o código da sua aplicação, dependências e configuração. Um contêiner é uma instância em execução dessa imagem. Você pode criar múltiplos contêineres a partir da mesma imagem, cada um executando independentemente com seu próprio sistema de arquivos e rede isolados.
A tag latest não atualiza automaticamente para a versão mais recente. É apenas uma tag padrão que os mantenedores podem ou não manter atualizada. Usar tags de versão explícitas como node:20-alpine garante builds reproduzíveis e previne mudanças inesperadas que quebram a aplicação quando as imagens são atualizadas.
Use volumes Docker para persistir dados fora do sistema de arquivos do contêiner. Volumes nomeados armazenam dados em um local gerenciado pelo Docker, enquanto bind mounts vinculam a diretórios específicos na sua máquina host. Nunca confie no sistema de arquivos interno de um contêiner para dados importantes.
Builds multi-estágio permitem que você use uma imagem para construir sua aplicação e uma imagem diferente e menor para executá-la. Isso mantém suas imagens de produção leves ao excluir ferramentas de build e dependências, reduzindo tanto o tamanho da imagem quanto potenciais vulnerabilidades de segurança.
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.