Kernel e Internals

Contêineres com Docker e Podman rodando sobre o kernel Linux

• 6 min de leitura

Contêineres com Docker e Podman rodando sobre o kernel 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.

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

💬 Comentários
Mais em Kernel e Internals