Back

Docker vs Podman en 2026: La guía completa de migración que nadie pidió (pero todos necesitan)

Algo raro está pasando en el mundo de los contenedores. Docker — la herramienta que literalmente inventó la contenedorización — está perdiendo terreno sin hacer ruido. Y no ante una startup deslumbrante, sino ante un proyecto open-source que la mayoría de los devs todavía no probó: Podman.

Los números son claros. Las estrellas de Podman en GitHub superaron las 30,000 a principios de 2026. Red Hat, SUSE y Canonical lo meten por defecto en sus distros. Kubernetes sacó a Docker como runtime en la versión 1.24, y desde entonces muchos equipos empezaron a preguntarse "¿nuestra pila de contenedores está bien así?". Para rematar, los cambios de licencia de Docker Desktop convirtieron "la herramienta gratis que todos usan" en "algo que sale 24/mes/usuariosituempresatienemaˊsde250empleadosofacturamaˊsde24/mes/usuario si tu empresa tiene más de 250 empleados o factura más de 10M."

Pero la mayoría de los artículos de comparación erran el foco: esto no es sobre si Podman es "mejor" que Docker. Es sobre si tu workflow, tu equipo, tus requisitos de seguridad y tu target de deploy hacen que uno te sirva materialmente más que el otro.

En esta guía entramos a fondo en las diferencias de arquitectura, recorremos escenarios reales de migración, medimos lo que realmente importa y armamos un framework de decisión concreto. Sin vueltas ni "depende" sin contexto. Vamos.

Arquitectura: La división fundamental

Antes que nada, hay que entender la diferencia de diseño más grande entre Docker y Podman. Todo lo demás sale de acá.

Docker: siempre hay un daemon corriendo

Docker funciona con una arquitectura cliente-servidor donde un daemon persistente (dockerd) está siempre en background:

┌─────────────┐     ┌──────────────┐     ┌───────────────┐
│ docker CLI  │────▶│   dockerd    │────▶│  containerd   │
│  (cliente)  │     │   (daemon)   │     │   (runtime)   │
└─────────────┘     └──────────────┘     └───────────────┘
                          │
                    Corre como root
                    Siempre escuchando
                    Administra todos los contenedores

Cuando corrés docker run nginx, el CLI le manda un request al daemon, que baja la imagen, crea el contenedor y maneja todo su ciclo de vida. Corre como root por defecto y administra todos los contenedores del sistema desde un solo proceso.

Las ventajas son reales:

  • Gestión centralizada: un proceso tiene visibilidad de todo el estado
  • Background transparente: los contenedores siguen vivos aunque cierres la terminal
  • Todo el ecosistema depende de él: Docker Compose, Swarm y miles de herramientas esperan el socket del daemon

Los costos también:

  • Superficie de ataque grande: el daemon corre como root. Si lo comprometen, tienen root en el host
  • Punto único de fallo: si dockerd se cae, todos los contenedores caen
  • Recursos en idle: el daemon consume memoria y CPU incluso cuando no hay nada corriendo

Podman: sin daemon

Podman lo resuelve de otra forma. No hay daemon.

┌─────────────┐     ┌───────────────┐
│ podman CLI  │────▶│    conmon     │
│  (directo)  │     │ (monitor por  │
└─────────────┘     │  contenedor)  │
                    └───────────────┘
                          │
                    Corre como usuario
                    Modelo fork-exec
                    Cada contenedor independiente

Cuando corrés podman run nginx, Podman forkea directamente el proceso del contenedor usando conmon (un monitor liviano). Sin daemon persistente. Cada contenedor corre como proceso independiente bajo tu cuenta de usuario.

¿Qué ganás?

  • No necesitás root: los contenedores corren con tu UID por defecto
  • Sin punto único de fallo: si un contenedor se cae, los demás ni se enteran
  • Cero overhead en idle: cuando no usás contenedores, no corre nada
  • Se integra con systemd: podés manejar contenedores como servicios systemd normales

¿Qué perdés?

  • Sin estado centralizado: la gestión es por sesión (la base de datos de Podman maneja la persistencia)
  • Background requiere setup extra: para que un contenedor sobreviva al logout necesitás podman generate systemd o flags --restart
  • Herramientas que asumen Docker: las que esperan /var/run/docker.sock necesitan adaptación

Seguridad: Por qué esto importa de verdad

"Contenedores rootless" suena a buzzword hasta que entendés qué previene concretamente.

El problema del root en Docker

El daemon de Docker corre como root por defecto. Cuando montás un volumen con -v /host/path:/container/path, el proceso del contenedor puede leer y escribir esos archivos como root en el host. Docker tiene mitigaciones (user namespaces, seccomp, AppArmor), pero son opt-in y la mayoría de los equipos no las activa.

Para dimensionarlo:

# Escape de contenedor con daemon root docker run -v /:/host --privileged alpine chroot /host # → acceso root completo al filesystem del host

El modo rootless de Docker (desde 20.10) lo resuelve, pero hay que configurarlo explícitamente:

# Habilitar modo rootless dockerd-rootless-setuptool.sh install # Verificar docker info | grep "Root Dir" # Debería mostrar algo bajo ~/.local/share/docker

En la práctica, la mayoría de las instalaciones siguen corriendo el daemon como root. Es el default y la mayoría de los tutoriales ni mencionan rootless.

Podman: rootless de fábrica

Podman corre rootless sin tocar nada. Sale así de caja:

# Funciona directo, sin root, sin daemon, sin configurar nada podman run -d nginx # Verificar que corre con tu usuario podman top -l user # Muestra tu UID, no root

Por debajo, Podman usa Linux user namespaces para mapear UIDs del contenedor a UIDs no privilegiados del host:

# Dentro del contenedor, nginx cree que es root (UID 0) # Pero en el host, realmente corre como tu usuario (ej: UID 1000) podman unshare cat /proc/self/uid_map # Output: # 0 1000 1 # 1 100000 65536

Si alguien logra escapar del contenedor, lo único que obtiene son los permisos de tu usuario no privilegiado. Root está fuera de alcance.

Seguridad: la comparación

FeatureDocker (default)Docker (rootless)Podman
Daemon corre comorootusuarioSin daemon
UID del contenedor en hostrootmapeadomapeado
Socket privilegiado/var/run/docker.sock (root)$XDG_RUNTIME_DIR/docker.sockNinguno
Capabilities defaultAmpliasReducidasMínimas
SELinux/AppArmorOpcionalOpcionalHabilitado por defecto
Perfil SeccompPerfil defaultPerfil defaultDefault más estricto
Si comprometen el daemonAcceso root completoAcceso de usuarioN/A

Para equipos con requisitos de compliance (SOC 2, PCI-DSS, HIPAA), la postura de seguridad de Podman simplifica mucho la auditoría.

Compatibilidad CLI: La realidad del "alias docker=podman"

Una de las decisiones más inteligentes de Podman fue hacer su CLI prácticamente 100% compatible con Docker:

# Agregá esto a tu .bashrc/.zshrc alias docker=podman # Y todo esto funciona como siempre: docker pull nginx docker run -d -p 8080:80 nginx docker ps docker build -t myapp . docker push myregistry/myapp

Lo que funciona directo

  • docker run / build / pull / push
  • docker ps / logs / exec
  • docker images / rmi
  • docker network create/ls/rm
  • docker volume create/ls/rm

Lo que no

Docker Compose — Podman ofrece podman-compose y soporta Docker Compose v2 vía su socket de compatibilidad:

# Opción 1: podman-compose (Python, más simple) pip install podman-compose podman-compose up -d # Opción 2: socket compatible → Docker Compose v2 systemctl --user enable --now podman.socket export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock docker compose up -d

Docker Swarm — Podman no lo soporta. Si usás Swarm (cada vez menos común), es un blocker total.

Docker-in-Docker (DinD) — Común en CI/CD, pero en Podman es diferente:

# Docker: necesitás privileged docker run --privileged -v /var/run/docker.sock:/var/run/docker.sock docker # Podman: rootless, sin privileged podman run --security-opt label=disable \ -v $XDG_RUNTIME_DIR/podman/podman.sock:/var/run/docker.sock \ docker

Features de Docker Desktop — GUI, Kubernetes integrado, Extensions Marketplace y Dev Environments no tienen equivalente directo en Podman. Podman Desktop cubre parte, pero no es lo mismo.

Kubernetes: La ventaja real de Podman

Acá Podman tiene algo que Docker no puede replicar fácilmente por diseño.

Soporte nativo de Pods

Podman maneja pods — grupos de contenedores que comparten network namespace, igual que en Kubernetes — como ciudadanos de primera clase:

# Crear un pod podman pod create --name webapp -p 8080:80 # Meter contenedores podman run -d --pod webapp --name frontend nginx podman run -d --pod webapp --name api node:20-slim # Ambos comparten localhost # frontend accede al API en localhost:3000

Esto es exactamente como Kubernetes organiza contenedores. Docker no tiene este concepto — cada contenedor vive en su propio network namespace.

Generar YAML de Kubernetes

Podés exportar un pod corriendo directamente a YAML compatible con Kubernetes:

# Generar YAML de un pod en ejecución podman generate kube webapp > webapp.yaml cat webapp.yaml
# Generado por Podman apiVersion: v1 kind: Pod metadata: name: webapp spec: containers: - name: frontend image: docker.io/library/nginx:latest ports: - containerPort: 80 hostPort: 8080 - name: api image: docker.io/library/node:20-slim

Y funciona en la dirección inversa:

# Correr YAML Kubernetes localmente podman play kube webapp.yaml # Bajarlo podman play kube webapp.yaml --down

Este workflow de podman play kube tiene usos muy concretos:

  • Desarrollo local que replica producción Kubernetes exactamente
  • Probar manifests sin levantar un cluster entero
  • Migración gradual de Docker Compose a Kubernetes

Docker y Kubernetes: la relación es indirecta

El approach de Docker hacia Kubernetes pasa por herramientas intermedias:

# Docker Desktop incluye un K8s single-node # Pero es un cluster K8s completo, no un concepto liviano de pod # Para convertir Docker Compose a K8s necesitás herramientas externas kompose convert -f docker-compose.yaml # → el output generalmente necesita bastante edición manual

Docker Compose y Kubernetes son abstracciones fundamentalmente distintas. Compose define servicios, Kubernetes define workloads. La traducción siempre pierde información. El concepto de pod de Podman cierra esa brecha de forma nativa.

Docker Compose vs Podman Compose: Lo que pasa en la práctica

La mayoría de los devs no corren contenedores sueltos — orquestan múltiples contenedores con archivos Compose. Acá la migración se pone interesante.

Docker Compose (v2)

Docker Compose v2 es maduro y probado en producción:

# docker-compose.yaml services: web: build: ./frontend ports: - "3000:3000" depends_on: - api - db environment: - API_URL=http://api:4000 api: build: ./backend ports: - "4000:4000" depends_on: db: condition: service_healthy environment: - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp db: image: postgres:16 volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=secret healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 5s retries: 5 volumes: pgdata:
docker compose up -d docker compose logs -f docker compose down

Las opciones en Podman

Opción 1: podman-compose (Python, de la comunidad):

pip install podman-compose podman-compose up -d

Simple y liviano. Pero no cubre todas las features de Docker Compose v2 (healthcheck.condition, algunos modos de red, profiles).

Opción 2: Docker Compose v2 vía socket Podman (para setups complejos):

# Levantar el socket Docker-compatible de Podman systemctl --user start podman.socket # Apuntar el CLI a Podman export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock # Docker Compose funciona normalmente docker compose up -d

Al pasar por la API Docker-compatible de Podman, tenés compatibilidad completa. Es el camino más suave para archivos Compose complejos.

Opción 3: Quadlet (nativo de Podman, integrado con systemd):

# ~/.config/containers/systemd/webapp.container [Container] Image=docker.io/library/nginx:latest PublishPort=8080:80 Volume=webdata:/usr/share/nginx/html [Service] Restart=always [Install] WantedBy=default.target
systemctl --user daemon-reload systemctl --user start webapp.service

Quadlet define contenedores como unit files de systemd. Más orientado a producción que Compose, pero implica reescribir la orquestación.

CI/CD: Integración en pipelines

CI/CD es la parte más compleja de la migración, porque casi toda la infra CI se construyó pensando en Docker.

GitHub Actions

Docker (default):

jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t myapp:${{ github.sha }} . - name: Push to registry run: | echo ${{ secrets.REGISTRY_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin docker push ghcr.io/${{ github.repository }}/myapp:${{ github.sha }}

Podman (reemplazo directo):

jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: podman build -t myapp:${{ github.sha }} . - name: Push to registry run: | podman login ghcr.io -u ${{ github.actor }} -p ${{ secrets.REGISTRY_TOKEN }} podman push ghcr.io/${{ github.repository }}/myapp:${{ github.sha }}

Podman viene preinstalado en los runners ubuntu-latest de GitHub, así que literalmente cambiás el nombre del comando y listo.

GitLab CI

GitLab CI tradicionalmente usa DinD (Docker-in-Docker), que necesita modo privilegiado:

Docker (necesita privileged):

build: image: docker:latest services: - docker:dind variables: DOCKER_TLS_CERTDIR: "/certs" script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Podman (sin privileged):

build: image: quay.io/podman/stable script: - podman build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - podman push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

No necesitar --privileged elimina una superficie de ataque importante en CI. Es un cambio silencioso pero significativo.

Buildah: builds especializados

El ecosistema de Podman incluye Buildah, una herramienta dedicada a construir imágenes con capacidades que docker build no tiene:

# Build from scratch: sin imagen base, superficie de ataque mínima container=$(buildah from scratch) buildah copy $container ./static-binary /app buildah config --entrypoint '["/app"]' $container buildah commit $container myapp:minimal # → imagen sin paquetes, sin shell, solo tu binario
# Control a nivel de capa individual buildah run $container -- pip install -r requirements.txt buildah run $container -- pip cache purge buildah commit $container myapp:optimized

Buildah es especialmente útil en entornos con requisitos de seguridad estrictos, porque nunca levanta un daemon y puede construir imágenes sin runtime de contenedor.

Benchmarks: Los números que importan

Vamos a lo que realmente hace diferencia en el día a día:

Startup

Inicio de contenedor (nginx, Alpine, SSD):

Docker:  ~0.8-1.2s  (daemon ya corriendo)
Podman:  ~0.5-0.9s  (fork-exec, sin daemon)

Primer contenedor después del boot:
Docker:  ~2-4s  (hay que esperar al daemon)
Podman:  ~0.5-0.9s  (no hay daemon que esperar)

Podman gana en cold-start. En servidores long-running donde el daemon ya está activo, la diferencia es despreciable.

Build

Build de imagen (Node.js multi-stage, cache frío):

Docker BuildKit:  ~45-60s
Podman (Buildah): ~48-65s

Cache caliente:
Docker BuildKit:  ~3-5s
Podman (Buildah): ~3-5s

Efectivamente lo mismo. BuildKit tiene leves ventajas en gestión de cache para builds multi-stage complejos, pero rara vez supera el 10%.

Memoria

Consumo idle:

Docker daemon:     ~50-100MB (siempre corriendo)
Podman:            ~0MB (nada corre en idle)

Por contenedor:
Docker:            ~5-10MB (conmon + shim)
Podman:            ~3-8MB (solo conmon)

El costo cero en idle pesa en máquinas de desarrollo y runners CI. En un servidor de producción con 50+ contenedores, el overhead por contenedor es casi idéntico.

Pull de imágenes

nginx:latest (comprimido ~70MB):
Docker:   ~4-6s
Podman:   ~4-6s

Imagen ML grande (~5GB):
Docker:   ~45-90s
Podman:   ~45-90s

Sin diferencia relevante. Mismo protocolo OCI, misma velocidad.

Docker Desktop vs Podman Desktop

Para devs en macOS y Windows, la experiencia de escritorio importa:

Docker Desktop

  • Costo: gratis para uso personal, educación y empresas <250 empleados con <10Mdefacturacioˊn.10M de facturación. 24/mes/usuario para el resto (Business tier)
  • Kubernetes: cluster single-node integrado
  • Extensions: marketplace con 100+ extensiones
  • Dev Environments: entornos remotos estilo Codespaces
  • VM: gestión automática de VM Linux en macOS/Windows
  • Recursos: GUI para límites de CPU/memoria
  • Volúmenes: GUI para inspección y gestión

Podman Desktop

  • Costo: gratis, open-source (Apache 2.0)
  • Kubernetes: integración Kind/Minikube (no integrado)
  • Extensions: sistema de plugins en crecimiento
  • VM: gestión automática vía podman machine
  • Recursos: controles básicos de CPU/memoria
  • Pods: UI de primera clase para crear y gestionar pods

Para devs individuales y equipos chicos, Podman Desktop compite bien. Para equipos que dependen de las Extensions, Dev Environments o features enterprise de Docker Desktop (SSO, gestión de acceso a imágenes, Hardened Desktop), Docker sigue adelante.

Playbook de migración: De Docker a Podman

Si decidiste migrar, este es el orden que mejor funciona:

Fase 1: Desarrollo local (Semana 1-2)

# 1. Instalar Podman # macOS: brew install podman podman machine init podman machine start # Linux (Ubuntu/Debian): sudo apt install podman # 2. Alias (no rompe nada, Docker sigue funcionando) echo 'alias docker=podman' >> ~/.zshrc source ~/.zshrc # 3. Probar workflows existentes docker pull your-registry/your-app:latest docker run -d -p 3000:3000 your-registry/your-app:latest # 4. Probar compatibilidad Compose systemctl --user start podman.socket export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock docker compose up -d

Fase 2: Pipeline CI/CD (Semana 3-4)

# Job paralelo al build Docker existente para validar sin romper nada build-podman: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build with Podman run: | podman build -t myapp:${{ github.sha }} . podman push ghcr.io/${{ github.repository }}/myapp:${{ github.sha }}

Fase 3: Producción (Semana 5+)

# Generar servicios systemd desde contenedores podman generate systemd --new --files --name webapp # Instalar y activar cp container-webapp.service ~/.config/systemd/user/ systemctl --user enable --now container-webapp.service # O usá Quadlet (ver la sección de Quadlet arriba)

Trampas comunes en la migración

  1. Permisos de volúmenes: el modo rootless mapea UIDs diferente. Puede que necesites podman unshare chown para volúmenes montados
  2. Binding de puertos: rootless no puede bindear puertos bajo 1024 sin sysctl net.ipv4.ip_unprivileged_port_start=0
  3. Modos de red: --network=host funciona distinto en rootless
  4. Mounts del socket: herramientas que montan /var/run/docker.sock necesitan apuntar al socket de Podman

Framework de decisión: Docker vs Podman en 2026

Sin ambigüedad, concreto:

Quedate con Docker si:

  • Tu equipo tiene menos de 250 personas (facturación <$10M) y Docker Desktop es gratis. El ecosistema pesa
  • Dependés de Docker Swarm. Podman no tiene alternativa
  • Tus pipelines usan features Docker-específicas (cache mounts avanzados de BuildKit, Compose completo en testing, DinD) y cambiarlas tiene alto costo
  • Usás Extensions de Docker Desktop en tu día a día (escaneo de vulnerabilidades, explorador de logs, herramientas de DB)
  • Tu equipo trabaja en macOS/Windows y necesita la experiencia pulida de Docker Desktop

Pasate a Podman si:

  • El compliance de seguridad es prioridad. Rootless por defecto, sin daemon privilegiado, capabilities mínimas — la postura es significativamente más fuerte
  • Estás pagando Docker Desktop con un equipo grande. 24/seat/mes×100personas=24/seat/mes × 100 personas = 28,800/año. Podman Desktop es gratis
  • Tu target es Kubernetes y querés que el desarrollo local refleje producción. El concepto de pod y podman play kube son herramientas genuinamente útiles
  • Corrés en servidores Linux y querés gestión nativa con systemd (Quadlet)
  • Necesitás builds rootless en CI. Poder buildear sin modo privilegiado es una mejora real de seguridad
  • La eficiencia de recursos importa (runners compartidos, laptops de desarrollo). Cero overhead de daemon idle suma

El enfoque híbrido (lo más común)

La realidad: la mayoría de los equipos no migra de un día para otro.

  1. Podman en servidores Linux — rootless, systemd, sin licensing
  2. Docker Desktop en máquinas de desarrollo — UX pulida, extensions, onboarding fácil
  3. Podman en CI/CD — sin contenedores privilegiados, preinstalado en GitHub runners

El estándar OCI garantiza imágenes 100% intercambiables, así que este mix funciona sin fricción.

Mirando hacia adelante: 2026 y después

El ecosistema de contenedores converge en estándares y diverge en implementación.

La estandarización OCI está lista. Imágenes, runtimes y specs de distribución son maduros. Docker y Podman buildean y corren las mismas imágenes. La época de "funciona en Docker, rompe en Podman" quedó atrás.

Contenedores WebAssembly (Wasm) están apareciendo como tecnología complementaria. Docker (vía runwasi) y Podman (vía crun-wasm) pueden correr workloads Wasm junto a contenedores Linux tradicionales. Arrancan en milisegundos, usan una fracción de la memoria y ofrecen sandboxing más fuerte. No van a reemplazar contenedores Linux, pero van a tomar una porción creciente de workloads livianos.

Rootless como default se está volviendo norma en la industria. Docker viene mejorando su modo rootless release a release. La filosofía de Podman — rootless y sin daemon por defecto — está ganando el argumento arquitectónico, uses la herramienta que uses.

Dev Containers y entornos de desarrollo basados en contenedores siguen madurando. Docker (vía la spec Dev Containers) y Podman (vía Podman Desktop) soportan este patrón. Si el futuro del desarrollo es contenedores de punta a punta, la elección de runtime se vuelve aún más importante.

Conclusión

La respuesta honesta: depende de qué estés optimizando, pero es menos ambigua que hace dos años.

Si seguridad, costo y alineación con Kubernetes son tus prioridades, Podman es la opción más fuerte en 2026. Rootless por defecto, cero overhead de daemon, soporte nativo de pods — son ventajas técnicas genuinas que Docker viene persiguiendo.

Si lo que más pesa es la madurez del ecosistema, la experiencia de escritorio en macOS/Windows y la inercia del tooling, Docker sigue siendo el default pragmático. El ecosistema es más grande, el escritorio más pulido, y hay más tutoriales, respuestas de Stack Overflow y templates de CI que asumen Docker.

La buena noticia: como ambas herramientas siguen OCI, no hay lock-in. Podés empezar con Docker, pasar a Podman para CI, usar Podman en producción y mantener Docker Desktop para desarrollo local. Las imágenes, los registries y los Dockerfiles (sí, Podman buildea Dockerfiles) son los mismos.

El mundo de los contenedores se dividió no por incompatibilidad sino por filosofía: daemon centralizado vs daemonless, root por defecto vs rootless por defecto, producto comercial vs proyecto comunitario. En 2026, las dos filosofías producen resultados de nivel producción. Tu elección debería reflejar tus restricciones y prioridades, no cuál herramienta tiene más hinchada en Twitter.

Elegí uno, levantá contenedores, y enfocate en lo que realmente es difícil: el código adentro de ellos.

DockerPodmancontainersDevOpsKubernetesCI/CDsecurityLinux

Explora herramientas relacionadas

Prueba estas herramientas gratuitas de Pockit