Docker para Iniciantes: ContĂȘineres Simplificados

· 12 min de leitura

Índice

O Que É Docker?

Docker Ă© uma plataforma que permite empacotar aplicaçÔes e suas dependĂȘncias em contĂȘineres leves e portĂĄteis. Pense em um contĂȘiner como uma pequena caixa autossuficiente que contĂ©m tudo o que sua aplicação precisa para executar: cĂłdigo, runtime, bibliotecas e ferramentas do sistema. Chega de problemas do tipo "funciona na minha mĂĄquina".

Antes do Docker, implantar software significava instalar dependĂȘncias manualmente, configurar servidores e torcer para que nada entrasse em conflito. VocĂȘ gastaria horas configurando versĂ”es do Python, pacotes do Node.js, drivers de banco de dados e bibliotecas do sistema. Depois faria tudo de novo nos servidores de staging e produção, rezando para que as configuraçÔes correspondessem.

O Docker elimina esse caos garantindo que sua aplicação execute de forma idĂȘntica em qualquer lugar — seu laptop, a mĂĄquina de um colega, servidores de staging ou produção. O contĂȘiner se torna a unidade de implantação, nĂŁo apenas o cĂłdigo da aplicação.

O Docker se tornou a ferramenta padrĂŁo para desenvolvimento de software moderno. Seja construindo microsserviços, configurando pipelines de CI/CD ou apenas querendo um ambiente de desenvolvimento consistente, o Docker torna isso possĂ­vel com sobrecarga mĂ­nima. Empresas como Netflix, Spotify e PayPal executam milhĂ”es de contĂȘineres em produção todos os dias.

Dica rĂĄpida: Docker nĂŁo Ă© apenas para implantaçÔes em produção. Muitos desenvolvedores o usam para evitar poluir sua mĂĄquina local com diferentes versĂ”es de linguagens, bancos de dados e ferramentas. Precisa de PostgreSQL para um projeto e MySQL para outro? Execute ambos em contĂȘineres sem conflitos.

ContĂȘineres vs MĂĄquinas Virtuais

ContĂȘineres e mĂĄquinas virtuais fornecem isolamento, mas funcionam de maneira muito diferente internamente. Entender essa diferença Ă© crucial para apreciar por que os contĂȘineres se tornaram tĂŁo populares.

MĂĄquinas Virtuais executam um sistema operacional completo com seu prĂłprio kernel sobre um hypervisor. Cada VM precisa de sua prĂłpria instalação de SO, consumindo gigabytes de espaço em disco e memĂłria significativa. Os tempos de inicialização sĂŁo medidos em minutos. Se vocĂȘ executar trĂȘs VMs, estarĂĄ executando trĂȘs sistemas operacionais completos simultaneamente.

ContĂȘineres compartilham o kernel do SO host e apenas empacotam a camada de aplicação. Eles tĂȘm megabytes de tamanho (nĂŁo gigabytes), iniciam em segundos (nĂŁo minutos), e vocĂȘ pode executar dezenas em uma Ășnica mĂĄquina sem problemas.

# Abordagem VM: Cada aplicação recebe um SO completo
App A → SO Convidado → Hypervisor → SO Host → Hardware
App B → SO Convidado → Hypervisor → SO Host → Hardware

# Abordagem ContĂȘiner: AplicaçÔes compartilham o kernel
App A → Runtime de ContĂȘiner → SO Host → Hardware
App B → Runtime de ContĂȘiner → SO Host → Hardware

Essa arquitetura leve torna os contĂȘineres ideais para microsserviços, onde vocĂȘ pode executar centenas de pequenos serviços em vez de uma aplicação monolĂ­tica. A eficiĂȘncia de recursos Ă© impressionante — um servidor que executa 10 VMs pode executar confortavelmente 100 contĂȘineres.

Recurso MĂĄquinas Virtuais ContĂȘineres
Tempo de Inicialização Minutos Segundos
Espaço em Disco Gigabytes (SO completo) Megabytes (apenas camada de aplicação)
Desempenho PrĂłximo ao nativo Nativo (sem sobrecarga de hypervisor)
Isolamento Completo (kernel separado) NĂ­vel de processo (kernel compartilhado)
Portabilidade Limitada (dependente de hypervisor) Alta (executa onde o Docker executa)
Uso de Recursos Pesado Leve

Dito isso, as VMs nĂŁo estĂŁo obsoletas. Elas fornecem isolamento mais forte, pois cada VM tem seu prĂłprio kernel. Para cargas de trabalho crĂ­ticas de segurança ou quando vocĂȘ precisa executar diferentes sistemas operacionais, as VMs continuam sendo a melhor escolha. Muitas organizaçÔes usam ambas: VMs para isolamento de infraestrutura e contĂȘineres para implantação de aplicaçÔes.

Conceitos Fundamentais do Docker

O Docker tem alguns conceitos-chave que vocĂȘ precisa entender antes de mergulhar em comandos e Dockerfiles. Esses blocos de construção formam a base de como o Docker funciona.

Imagens

Uma imagem Docker Ă© um modelo somente leitura contendo o cĂłdigo da sua aplicação, runtime, bibliotecas e dependĂȘncias. Pense nela como um snapshot ou blueprint. As imagens sĂŁo construĂ­das a partir de instruçÔes em um Dockerfile e armazenadas em registros como o Docker Hub.

As imagens sĂŁo compostas de camadas. Cada instrução em um Dockerfile cria uma nova camada. O Docker armazena essas camadas em cache, entĂŁo se vocĂȘ reconstruir uma imagem e apenas a Ășltima camada mudou, o Docker reutiliza as camadas em cache. Isso torna as construçÔes incrivelmente rĂĄpidas.

ContĂȘineres

Um contĂȘiner Ă© uma instĂąncia em execução de uma imagem. VocĂȘ pode criar mĂșltiplos contĂȘineres a partir da mesma imagem, e cada um executa isoladamente. Quando vocĂȘ para um contĂȘiner, quaisquer alteraçÔes feitas dentro dele sĂŁo perdidas, a menos que vocĂȘ as salve explicitamente ou use volumes.

Os contĂȘineres sĂŁo efĂȘmeros por design. Essa imutabilidade Ă© um recurso, nĂŁo um bug — garante consistĂȘncia e torna o escalonamento trivial.

Dockerfile

Um Dockerfile Ă© um arquivo de texto contendo instruçÔes para construir uma imagem Docker. Ele especifica a imagem base, copia seu cĂłdigo, instala dependĂȘncias e define como executar sua aplicação. Vamos nos aprofundar em Dockerfiles em uma seção posterior.

Registro Docker

Um registro Ă© um sistema de armazenamento e distribuição para imagens Docker. O Docker Hub Ă© o registro pĂșblico padrĂŁo, hospedando milhĂ”es de imagens. VocĂȘ tambĂ©m pode executar registros privados para aplicaçÔes proprietĂĄrias. Quando vocĂȘ executa docker pull nginx, o Docker baixa a imagem nginx do Docker Hub.

Volumes

Volumes sĂŁo o mecanismo do Docker para persistir dados. Como os contĂȘineres sĂŁo efĂȘmeros, quaisquer dados gravados dentro de um contĂȘiner desaparecem quando ele para. Os volumes permitem armazenar dados fora do sistema de arquivos do contĂȘiner, sobrevivendo a reinicializaçÔes e exclusĂ”es de contĂȘineres.

Dica profissional: Use nosso Gerador de Comandos Docker para criar rapidamente comandos Docker complexos sem memorizar todas as flags e opçÔes.

Comandos Essenciais do Docker

Vamos percorrer os comandos Docker que vocĂȘ usarĂĄ diariamente. Eles cobrem todo o ciclo de vida do contĂȘiner, desde baixar imagens atĂ© limpar recursos.

Trabalhando com Imagens

# Baixar uma imagem do Docker Hub
docker pull ubuntu:22.04

# Listar todas as imagens locais
docker images

# Remover uma imagem
docker rmi ubuntu:22.04

# Construir uma imagem a partir de um Dockerfile
docker build -t myapp:1.0 .

# Marcar uma imagem para enviar a um registro
docker tag myapp:1.0 username/myapp:1.0

# Enviar uma imagem para um registro
docker push username/myapp:1.0

Executando ContĂȘineres

# Executar um contĂȘiner em primeiro plano
docker run ubuntu:22.04 echo "Hello Docker"

# Executar um contĂȘiner em modo desanexado (background)
docker run -d nginx

# Executar com um nome personalizado
docker run -d --name my-nginx nginx

# Executar com mapeamento de porta (host:contĂȘiner)
docker run -d -p 8080:80 nginx

# Executar com variĂĄveis de ambiente
docker run -d -e POSTGRES_PASSWORD=secret postgres

# Executar com montagem de volume
docker run -d -v /host/path:/container/path nginx

# Executar interativamente com um shell
docker run -it ubuntu:22.04 /bin/bash

Gerenciando ContĂȘineres

# Listar contĂȘineres em execução
docker ps

# Listar todos os contĂȘineres (incluindo parados)
docker ps -a

# Parar um contĂȘiner
docker stop my-nginx

# Iniciar um contĂȘiner parado
docker start my-nginx

# Reiniciar um contĂȘiner
docker restart my-nginx

# Remover um contĂȘiner
docker rm my-nginx

# Remover um contĂȘiner em execução (forçar)
docker rm -f my-nginx

# Ver logs do contĂȘiner
docker logs my-nginx

# Seguir logs em tempo real
docker logs -f my-nginx

# Executar um comando em um contĂȘiner em execução
docker exec my-nginx ls /usr/share/nginx/html

# Abrir um shell em um contĂȘiner em execução
docker exec -it my-nginx /bin/bash

# Ver uso de recursos do contĂȘiner
docker stats

# Inspecionar detalhes do contĂȘiner
docker inspect my-nginx

Comandos de Limpeza

# Remover todos os contĂȘineres parados
docker container prune

# Remover imagens nĂŁo utilizadas
docker image prune

# Remover volumes nĂŁo utilizados
docker volume prune

# Remover tudo nĂŁo utilizado (contĂȘineres, imagens, redes, volumes)
docker system prune -a

As flags -it merecem menção especial. -i mantĂ©m o STDIN aberto (interativo), e -t aloca um pseudo-TTY (terminal). Juntas, elas permitem interagir com o contĂȘiner como uma sessĂŁo de shell normal.

Dica rĂĄpida: Use docker ps -q para obter apenas IDs de contĂȘineres, o que Ă© Ăștil para scripts. Por exemplo, docker stop $(docker ps -q) para todos os contĂȘineres em execução.

Escrevendo Dockerfiles

Um Dockerfile Ă© onde a mĂĄgica acontece. É uma receita para construir sua imagem Docker, especificando exatamente o que vai no seu contĂȘiner. Vamos detalhar as instruçÔes mais importantes e melhores prĂĄticas.

Estrutura BĂĄsica do Dockerfile

# Começar de uma imagem base
FROM node:18-alpine

# Definir o diretĂłrio de trabalho
WORKDIR /app

# Copiar arquivos de pacote
COPY package*.json ./

# Instalar dependĂȘncias
RUN npm install

# Copiar código da aplicação
COPY . .

# Expor a porta em que sua aplicação executa
EXPOSE 3000

# Definir o comando para executar sua aplicação
CMD ["node", "server.js"]

InstruçÔes Principais do Dockerfile

FROM especifica a imagem base. Sempre use tags de versão específicas (como node:18-alpine) em vez de latest para garantir construçÔes reproduzíveis. Variantes Alpine são menores e mais seguras.

WORKDIR define o diretório de trabalho para instruçÔes subsequentes. Ele cria o diretório se não existir. Isso é mais limpo do que usar RUN cd /app.

COPY copia arquivos da sua mĂĄquina host para a imagem. A sintaxe Ă© COPY origem destino. Use COPY . . para copiar tudo, mas tenha cuidado com o que vocĂȘ inclui (use .dockerignore).

RUN executa comandos durante o processo de construção. Cada instrução RUN cria uma nova camada. Encadeie comandos com && para reduzir camadas:

# Ruim: Cria 3 camadas
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# Bom: Cria 1 camada
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

EXPOSE documenta em qual porta sua aplicação escuta. Ele não publica a porta de fato — isso acontece com docker run -p.

CMD especifica o comando padrĂŁo a ser executado quando o contĂȘiner inicia. Use o formato de array JSON (["executĂĄvel", "param1"]) para evitar problemas de processamento de shell.

ENTRYPOINT Ă© similar ao CMD, mas mais difĂ­cil de sobrescrever. Use-o quando quiser que seu contĂȘiner se comporte como um executĂĄvel. VocĂȘ pode combinar ENTRYPOINT e CMD para padrĂ”es flexĂ­veis.

ConstruçÔes Multi-Estågio

ConstruçÔes multi-estĂĄgio permitem usar mĂșltiplas instruçÔes FROM em um Dockerfile. Isso Ă© incrivelmente poderoso para criar imagens de produção pequenas enquanto mantĂ©m as ferramentas de construção separadas.

# Estågio de construção
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Estågio de produção
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/server.js"]

A imagem de produção contĂ©m apenas o cĂłdigo compilado e dependĂȘncias de runtime, nĂŁo as ferramentas de construção. Isso pode reduzir o tamanho da imagem em 70% ou mais.

Arquivo .dockerignore

Crie um arquivo .dockerignore para excluir arquivos do contexto de construção. Isso acelera as construçÔes e reduz o tamanho da imagem.

node_modules
npm-debug.log
.git
.env
*.md
.DS_Store
coverage
.vscode