Contêineres com Docker e Podman rodando sobre o kernel Linux
1. Fundamentos dos Contêineres no Linux
Contêineres não são máquinas virtuais. Eles são processos Linux isolados que compartilham o mesmo kernel do hospedeiro. Esse isolamento é possível graças a dois mecanismos fundamentais do kernel: namespaces e cgroups.
Namespaces criam ambientes isolados para processos. Os principais tipos incluem:
- PID namespace: processos dentro do contêiner veem apenas seus próprios PIDs
- Network namespace: cada contêiner tem suas próprias interfaces de rede, tabelas de roteamento e regras de firewall
- Mount namespace: sistemas de arquivos são isolados entre contêineres
- User namespace: permite mapear usuários root do contêiner para usuários não privilegiados no host
Cgroups (control groups) limitam e monitoram recursos como CPU, memória e I/O de disco. Sem cgroups, um contêiner poderia consumir toda a memória do sistema, derrubando outros processos.
As imagens de contêiner utilizam Union Filesystems como OverlayFS (padrão no Docker e Podman modernos). Cada camada é somente leitura e empilhada sobre as anteriores. Quando você modifica um arquivo, o sistema cria uma camada writable no topo (copy-on-write). Isso permite compartilhamento eficiente de camadas entre múltiplos contêineres.
# Verificar namespaces ativos de um contêiner em execução
docker inspect --format '{{.State.Pid}}' meu-container | xargs -I {} ls -la /proc/{}/ns/
2. Docker vs Podman: Principais Diferenças
Docker utiliza uma arquitetura cliente-servidor com um daemon (dockerd) que gerencia contêineres, imagens e redes. O daemon roda como root e possui uma API REST.
Podman é daemonless — não há um processo central. Cada comando podman executa diretamente como um processo filho, usando o conceito de "fork/exec". Isso traz vantagens significativas:
- Execução rootless nativa (sem configuração adicional)
- Maior segurança: sem daemon como ponto único de falha
- Compatibilidade com Docker: Podman aceita a maioria dos comandos Docker
Podman também introduz o conceito de pods (inspirado no Kubernetes), permitindo agrupar múltiplos contêineres que compartilham o mesmo namespace de rede.
# Verificar se Podman está rodando sem daemon
ps aux | grep podman
# O comando acima mostra apenas o processo atual, não um daemon
3. Instalação e Configuração Inicial
Instalação do Docker Engine no Ubuntu
# Remover versões antigas
sudo apt remove docker docker-engine docker.io containerd runc
# Adicionar repositório oficial
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Testar instalação
sudo docker run hello-world
Instalação do Podman
# Ubuntu
sudo apt update
sudo apt install podman
# CentOS/RHEL
sudo dnf install podman
# Testar
podman run hello-world
4. Gerenciamento de Imagens e Contêineres
Comandos Essenciais
# Baixar imagem
docker pull nginx:alpine
podman pull nginx:alpine
# Executar contêiner interativo
docker run -it --name meu-ubuntu ubuntu:22.04 bash
podman run -it --name meu-ubuntu ubuntu:22.04 bash
# Listar contêineres em execução
docker ps
podman ps
# Executar comando em contêiner em execução
docker exec meu-ubuntu cat /etc/os-release
podman exec meu-ubuntu cat /etc/os-release
# Visualizar logs
docker logs -f meu-ubuntu
podman logs -f meu-ubuntu
# Parar e remover
docker stop meu-ubuntu && docker rm meu-ubuntu
podman stop meu-ubuntu && podman rm meu-ubuntu
Construção de Imagens com Dockerfile
# Dockerfile-exemplo
FROM alpine:3.19
RUN apk add --no-cache python3 py3-pip
COPY app.py /app/
WORKDIR /app
CMD ["python3", "app.py"]
# Construir imagem
docker build -t minha-app:1.0 .
podman build -t minha-app:1.0 .
Volumes e Bind Mounts
# Bind mount: compartilhar diretório do host com o contêiner
docker run -v /home/user/dados:/app/dados nginx
podman run -v /home/user/dados:/app/dados nginx
# Volume gerenciado pelo Docker/Podman
docker volume create meu-volume
docker run -v meu-volume:/data nginx
5. Redes em Contêineres
Tipos de Rede
# Rede bridge (padrão)
docker run --network bridge nginx
# Rede host (compartilha rede do host)
docker run --network host nginx
# Rede none (sem rede)
docker run --network none alpine sleep 3600
Expondo Portas
# Mapear porta 8080 do host para porta 80 do contêiner
docker run -p 8080:80 nginx
podman run -p 8080:80 nginx
Redes Personalizadas
# Criar rede personalizada
docker network create minha-rede --subnet 172.20.0.0/16
podman network create minha-rede --subnet 172.20.0.0/16
# Conectar contêineres à rede
docker run --network minha-rede --name web nginx
docker run --network minha-rede --name api alpine ping web
6. Segurança e Boas Práticas
Execução Rootless
# Podman já executa rootless por padrão
podman run alpine id
# Saída: uid=1000(usuario) gid=1000(usuario)
# Docker rootless (requer configuração)
dockerd-rootless-setuptool.sh install
Escaneamento de Vulnerabilidades com Trivy
# Instalar Trivy
sudo apt install trivy
# Escanear imagem
trivy image nginx:alpine
Limitação de Recursos
# Limitar memória e CPU
docker run --memory=512m --cpus=0.5 nginx
podman run --memory=512m --cpus=0.5 nginx
# Usar seccomp profile personalizado
docker run --security-opt seccomp=custom-profile.json nginx
7. Orquestração e Integração com o Sistema
Docker Compose
# docker-compose.yml
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: exemplo123
# Executar
docker compose up -d
podman-compose up -d # Requer podman-compose
Contêiner como Serviço Systemd
# /etc/systemd/system/meu-app.service
[Unit]
Description=Meu Contêiner
After=docker.service
[Service]
ExecStart=/usr/bin/docker run --name meu-app -p 3000:3000 minha-app:1.0
ExecStop=/usr/bin/docker stop meu-app
Restart=always
[Install]
WantedBy=multi-user.target
Migração entre Docker e Podman
# Alias para usar Podman como Docker
alias docker=podman
# Verificar compatibilidade
podman info | grep -i docker
8. Monitoramento e Troubleshooting
Logs e Eventos
# Logs em tempo real
docker logs -f --tail 100 meu-container
podman logs -f --tail 100 meu-container
# Eventos do Docker
docker events --filter 'container=meu-container'
# Logs via systemd (quando configurado)
journalctl -u docker.service -f
Monitoramento de Recursos
# Estatísticas em tempo real
docker stats
podman stats
# Inspecionar uso de memória
docker inspect --format '{{.State.Pid}}' meu-container | xargs -I {} cat /proc/{}/status | grep -E "VmRSS|VmSize"
Depuração de Falhas Comuns
# Falha OOM (Out of Memory)
docker inspect --format '{{.State.OOMKilled}}' meu-container
# Análise de rede
docker exec meu-container ip addr show
docker exec meu-container ping google.com
# Execução interativa para debug
docker run -it --rm alpine sh
Referências
- Documentação Oficial do Docker — Guia completo sobre instalação, configuração e uso do Docker Engine, incluindo Dockerfile, Compose e segurança.
- Documentação Oficial do Podman — Referência completa sobre Podman, incluindo execução rootless, pods e compatibilidade com Kubernetes.
- Linux Namespaces and Cgroups - Red Hat — Artigo técnico explicando os fundamentos de namespaces e cgroups no kernel Linux para contêineres.
- Trivy - Aqua Security — Repositório oficial do Trivy, ferramenta de escaneamento de vulnerabilidades para imagens de contêiner.
- OverlayFS - Kernel Linux — Documentação oficial do kernel sobre o sistema de arquivos OverlayFS usado por Docker e Podman.