Skip to content

A estratégia copy-on-write (CoW)

Copy-on-Write é uma técnica de otimização onde múltiplos processos/containers compartilham os mesmos dados até que alguém tente modificá-los. Só então é feita uma cópia.

Princípio: “Por que copiar algo que ninguém vai modificar?”


Imagens Docker são compostas por camadas empilhadas, cada uma somente leitura:

┌─────────────────────────┐
│ Container Layer (R/W) │ ← Camada gravável (CoW ativo aqui)
├─────────────────────────┤
│ Layer 3: app files │ ← Somente leitura
├─────────────────────────┤
│ Layer 2: dependencies │ ← Somente leitura
├─────────────────────────┤
│ Layer 1: base OS │ ← Somente leitura
└─────────────────────────┘

Múltiplos containers da mesma imagem compartilham as camadas base:

Container A ──┐
Container B ──┼──→ [Mesmas camadas base compartilhadas]
Container C ──┘

Economia: Se a imagem tem 500 MB e você tem 10 containers, não ocupa 5 GB, mas ~500 MB + pequenas diferenças individuais.


Container lê /etc/config.conf
Lê diretamente da camada base (compartilhada)
Nenhuma cópia é feita

Container modifica /etc/config.conf
1. Sistema detecta tentativa de escrita
2. Copia o arquivo para a camada do container
3. Modifica a cópia (não o original)
4. Outros containers continuam vendo o original

Suponha um arquivo app.py de 1 MB na imagem base:

Estado Inicial:
├── Layer base: app.py (1 MB) [compartilhado]
├── Container 1: [vazio] → lê app.py da base
├── Container 2: [vazio] → lê app.py da base
└── Container 3: [vazio] → lê app.py da base
Após Container 1 modificar app.py:
├── Layer base: app.py (1 MB) [compartilhado]
├── Container 1: app.py (1 MB) [cópia modificada] ← CoW acionado
├── Container 2: [vazio] → ainda lê da base
└── Container 3: [vazio] → ainda lê da base

Exemplo de Dockerfile
FROM ubuntu:22.04 # Layer 1 (base)
RUN apt-get update # Layer 2 (+ metadata de pacotes)
RUN apt-get install python3 # Layer 3 (+ Python)
COPY app.py /app/ # Layer 4 (+ seu código)
CMD ["python3", "/app/app.py"] # Metadata (não cria layer)

Cada instrução RUN, COPY, ADD cria uma nova camada imutável.


Ver camadas de uma imagem:

Camadas de uma imagem
docker image inspect nginx:latest | grep -A 20 Layers


Ver uso de disco por container:

Uso de disco por container
docker ps -s
  • size = camada gravável do container
  • virtual size = tamanho total (incluindo imagem base)

Agrupe comandos RUN:

Dockerfile
# ❌ Ruim - 3 camadas
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean
# ✅ Bom - 1 camada
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean

Evite copiar arquivos desnecessários


Reduza o tamanho final:

Dockerfile
FROM golang:1.20 AS builder
COPY . .
RUN go build -o app
FROM alpine:latest
COPY --from=builder /app /app # Só copia o binário

Dados que mudam frequentemente devem estar em volumes:

Volume persistente
docker run -v /host/data:/container/data minhaimagem:latest
┌─────────────────────────────────────────┐
│ Container Filesystem (Union Mount) │
├─────────────────────────────────────────┤
│ R/W Layer (Container-specific) │ ← CoW acontece aqui
│ ├── modified_file.txt (cópia) │
│ └── new_log.txt (novo arquivo) │
├─────────────────────────────────────────┤
│ R/O Layer 3 (App layer) │ ← Compartilhado
│ ├── app.py │
│ └── requirements.txt │
├─────────────────────────────────────────┤
│ R/O Layer 2 (Dependencies) │ ← Compartilhado
│ └── /usr/lib/python3/* │
├─────────────────────────────────────────┤
│ R/O Layer 1 (Base OS) │ ← Compartilhado
│ └── /bin, /etc, /lib, etc. │
└─────────────────────────────────────────┘

Copy-on-Write é fundamental para a eficiência de containers, permitindo que centenas de containers rodem em um único host sem duplicar todo o sistema de arquivos. Esta técnica é um dos pilares que torna a conteinerização tão eficiente em termos de recursos.


Docker: The copy-on-write (CoW) strategy