📦 Como containers funcionam
Containers não são máquinas virtuais — não há hypervisor, não há kernel separado. Eles são processos Linux com dois superpoderes do kernel: namespaces (isolamento de visibilidade) e cgroups (limitação de recursos). A imagem é apenas um sistema de arquivos em camadas.
① Intuição
Um container é uma ilusão cuidadosamente construída. Por dentro, o processo acredita que é o único no sistema, tem seu próprio IP e vê apenas seus arquivos. Por fora, o host sabe que é apenas mais um processo entre muitos.
Essa ilusão é criada inteiramente pelo kernel Linux — sem nenhuma camada de virtualização extra. É por isso que containers sobem em milissegundos e consomem muito menos memória que VMs.
② Visualização — explore cada camada
Use as abas para explorar a estrutura de uma imagem Docker, os namespaces que criam isolamento, os cgroups que limitam recursos, e a comparação com VMs.
③ Explicação técnica
Imagens em camadas — Dockerfile
Cada instrução no Dockerfile cria uma camada imutável. Camadas são compartilhadas entre imagens — se duas imagens usam a mesma base Alpine, essa camada existe apenas uma vez no disco:
# Cada instrução = uma camada no índice FROM python:3.12-alpine # camada base (5 MB) WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt # camada de dependências COPY . . # camada da sua app EXPOSE 8080 CMD ["python", "server.py"]
Namespaces — isolamento por syscall
A syscall clone() (ou unshare()) cria namespaces.
O Docker usa 6 deles por container:
# Python: criar namespace isolado (simplificado) import os import ctypes # Em C: clone(fn, stack, CLONE_NEWPID | CLONE_NEWNET | ...) # Python-nível: usar unshare() libc = ctypes.CDLL("libc.so.6") CLONE_NEWPID = 0x20000000 CLONE_NEWNET = 0x40000000 # Criar processo em novo namespace de PIDs e rede libc.unshare(CLONE_NEWPID | CLONE_NEWNET) # A partir daqui, este processo tem PID 1 # e uma interface de rede virtual própria
Cgroups — limitação de recursos
O kernel expõe cgroups como arquivos em /sys/fs/cgroup/. Escrever
neles é tão simples quanto escrever em arquivo:
# Criar cgroup e limitar CPU/memória import os CGROUP = "/sys/fs/cgroup/meu-container" # 1. Criar o cgroup os.makedirs(CGROUP, exist_ok=True) # 2. Limitar CPU a 50% de 1 core with open(f"{CGROUP}/cpu.max", "w") as f: f.write("50000 100000") # 50ms a cada 100ms # 3. Limitar memória a 256 MB with open(f"{CGROUP}/memory.max", "w") as f: f.write(str(256 * 1024 * 1024)) # 4. Adicionar nosso PID ao cgroup with open(f"{CGROUP}/cgroup.procs", "w") as f: f.write(str(os.getpid()))
O que docker run realmente faz
O Docker é um orchestrador que combina namespaces, cgroups, bind mounts e iptables em uma única chamada de alto nível:
# docker run por dentro (simplificado) docker run \ --memory=256m \ # cgroup: memory.max --cpus=0.5 \ # cgroup: cpu.max --network=bridge \ # namespace: NET --pid=container \ # namespace: PID -v /host/dados:/app/dados \ # bind mount -p 8080:80 \ # port mapping (iptables NAT) minha-imagem:latest
④ Projeto
Container do zero em Python (Linux required):
- Fork um processo filho
- No filho, chame
unshare(CLONE_NEWPID | CLONE_NEWUTS) - Mude o hostname para "meu-container" com
os.uname_result - Faça
chrootpara um rootfs mínimo (Alpine tarballed) - Monte
/procpara que comandos comopsfuncionem - Execute um shell — parabéns, você criou um container!
⑤ Perguntas rápidas
- Se containers compartilham o kernel, um exploit de kernel afeta todos os containers?
- O que é um "container rootless" e por que é mais seguro?
- Por que rodar como root dentro de um container é um risco de segurança?
- Qual a diferença entre um volume Docker e um bind mount?
⑥ Aplicações no mundo real
- Kubernetes — orquestra milhares de containers, distribui workload, faz health checks e rolling deploys
- GitHub Actions / GitLab CI — cada job de CI roda em um container isolado, garantindo reprodutibilidade
- AWS Lambda / Cloud Functions — internamente são micro-containers com cold start de milissegundos
- Heroku / Render / Railway — build da sua app vira uma imagem OCI, rodada em um container gerenciado