Podman (Pod Manager) es un motor de contenedores de código abierto y sin demonio, desarrollado por Red Hat, que proporciona una CLI compatible con Docker para construir, ejecutar y gestionar contenedores y pods OCI. A diferencia de Docker, Podman no requiere un demonio en segundo plano con privilegios de root, lo que lo hace inherentemente más seguro tanto para estaciones de trabajo de desarrollo como para servidores de producción. Si has estado usando Docker y buscas una alternativa más segura, compatible con systemd y que ejecute contenedores como tu usuario regular, Podman es la herramienta a adoptar.
Esta guía cubre todo lo necesario para comenzar con Podman en Ubuntu: instalación, ejecución de contenedores sin root, gestión de imágenes, creación de pods, compatibilidad con Compose, integración con systemd, redes y una ruta de migración completa desde Docker.
Requisitos Previos
Antes de comenzar, asegúrate de tener:
- Un sistema ejecutando Ubuntu 22.04 o 24.04 (edición escritorio o servidor)
- Acceso a la terminal con privilegios sudo
- Una conexión a internet estable
- Familiaridad básica con contenedores y la línea de comandos de Linux
- Al menos 2 GB de espacio libre en disco para imágenes
Nota: Podman funciona en cualquier distribución Linux moderna, pero esta guía se enfoca en Ubuntu. Si estás migrando desde Docker, no se requiere ninguna instalación de Docker — Podman lo reemplaza por completo.
¿Qué Es Podman?
Podman es una herramienta de gestión de contenedores que implementa la misma interfaz CLI que Docker pero con una arquitectura fundamentalmente diferente. El nombre viene de Pod Manager, reflejando su soporte nativo para pods estilo Kubernetes — grupos de contenedores que comparten namespaces de red e IPC.
Características clave de Podman:
- Sin demonio: No hay servicio en segundo plano ejecutándose como root. Cada comando
podmanlanza contenedores directamente como procesos hijos víaconmon(el monitor de contenedores). - Sin root por defecto: Los contenedores se ejecutan bajo tu cuenta de usuario regular usando user namespaces de Linux, sin necesidad de privilegios root.
- Compatible con OCI: Podman construye y ejecuta imágenes que cumplen con la especificación Open Container Initiative (OCI), garantizando total compatibilidad con imágenes y registros Docker.
- Pods nativos: Podman puede agrupar contenedores en pods, reflejando la semántica de pods de Kubernetes para desarrollo y pruebas locales.
- Integración con systemd: Podman genera archivos de unidad systemd a partir de contenedores en ejecución, facilitando la gestión del ciclo de vida de contenedores como servicios del sistema.
Podman vs Docker
Comprender las diferencias arquitectónicas entre Podman y Docker te ayuda a tomar una decisión informada y planificar tu migración.
| Característica | Podman | Docker |
|---|---|---|
| Arquitectura | Sin demonio (fork/exec) | Cliente-servidor (demonio dockerd) |
| Requisito de root | Sin root por defecto | Requiere demonio root (modo sin root opcional) |
| Runtime de contenedores | crun / runc vía conmon | containerd + runc |
| Compatibilidad CLI | Reemplazo directo (podman = docker) | CLI nativa |
| Soporte de pods | Nativo (estilo Kubernetes) | No disponible |
| Soporte Compose | podman-compose / podman compose | docker compose (plugin integrado) |
| Integración systemd | Nativa (podman generate systemd) | Requiere archivos de unidad manuales |
| Formato de imagen | OCI / Docker | OCI / Docker |
| Herramienta de construcción | Buildah (integrado) | BuildKit |
| Modelo de seguridad | Sin demonio root, user namespaces | Demonio root, sin root opcional |
| Socket | Opcional (podman.socket) | Requerido (docker.socket) |
La diferencia más significativa es el demonio. Docker requiere que el demonio dockerd se ejecute en todo momento como root, creando un único punto de fallo y un vector potencial de escalación de privilegios. Podman elimina esto por completo — cuando ejecutas podman run, directamente crea un nuevo proceso para el contenedor usando conmon como monitor de contenedores. Si Podman mismo se cae, los contenedores en ejecución continúan operando.
Instalar Podman en Ubuntu
Podman está disponible en los repositorios oficiales de Ubuntu a partir de Ubuntu 22.04. Instálalo junto con sus herramientas de soporte:
sudo apt update
sudo apt install -y podman
Verifica la instalación:
podman --version
Salida esperada:
podman version 4.9.3
Verifica la información del sistema para confirmar que el modo sin root está disponible:
podman info --format '{{.Host.Security.Rootless}}'
Esto debería devolver true cuando se ejecuta como usuario no root.
Para la última versión de Podman (si la versión del repositorio de Ubuntu es demasiado antigua), puedes agregar el repositorio oficial de Kubic:
sudo mkdir -p /etc/apt/keyrings
curl -fsSL "https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg] \
https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \
| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null
sudo apt update
sudo apt install -y podman
Configurar Registros de Contenedores
Por defecto, Podman requiere nombres de imagen completamente calificados (ej., docker.io/library/nginx). Para habilitar nombres cortos como nginx, configura los registros de búsqueda no calificados:
sudo tee /etc/containers/registries.conf.d/00-unqualified-search.conf <<'EOF'
[registries.search]
registries = ['docker.io', 'quay.io', 'ghcr.io']
EOF
Alternativamente, edita /etc/containers/registries.conf y agrega los registros de búsqueda bajo la sección [registries.search].
Ejecutar Tu Primer Contenedor
Con Podman instalado, ejecuta un contenedor de prueba como tu usuario regular (no root):
podman run --rm docker.io/library/hello-world
Deberías ver el familiar mensaje “Hello from Docker!”, confirmando que Podman puede descargar y ejecutar imágenes OCI. Nota que no se requiere sudo.
Ejecuta un contenedor interactivo:
podman run -it --rm docker.io/library/ubuntu:24.04 bash
Dentro del contenedor, verifica el usuario:
whoami
# root (dentro del user namespace del contenedor)
id
# uid=0(root) gid=0(root) groups=0(root)
Aunque apareces como root dentro del contenedor, en realidad estás ejecutándote como tu usuario regular en el host. Este es el poder de los contenedores sin root con mapeo de user namespace.
Sal del contenedor con exit o Ctrl+D.
Contenedores sin Root
Los contenedores sin root son la característica definitoria de Podman. Entender cómo funcionan te ayuda a solucionar problemas de permisos y diseñar despliegues de contenedores seguros.
Cómo Funcionan los Contenedores sin Root
Cuando ejecutas un contenedor como usuario no root, Podman usa user namespaces de Linux para crear un entorno aislado donde:
- El proceso del contenedor se ve a sí mismo como
root(UID 0) dentro del contenedor. - En el host, el proceso se ejecuta como un UID subordinado mapeado desde el rango permitido de tu usuario.
- El mapeo se define en
/etc/subuidy/etc/subgid.
Verifica los mapeos de UID/GID subordinados de tu usuario:
cat /etc/subuid
# jc:100000:65536
cat /etc/subgid
# jc:100000:65536
Esto significa que el usuario jc puede mapear UIDs 100000 a 165535 dentro de los contenedores. El UID 0 del contenedor se mapea al UID de tu usuario en el host, y los UIDs 1-65535 dentro del contenedor se mapean a los UIDs 100000-165535 del host.
Verificar la Operación sin Root
Ejecuta un contenedor y verifica el proceso desde el host:
podman run -d --name test-rootless docker.io/library/nginx:alpine
Desde otra terminal en el host:
ps aux | grep nginx
# jc 12345 ... nginx: master process
El proceso nginx se ejecuta como tu usuario (jc), no como root. Si el contenedor fuera comprometido, el atacante solo tendría los privilegios de tu usuario — no acceso root al host.
Configurar User Namespaces
Si /etc/subuid o /etc/subgid no contienen entradas para tu usuario, agrégalas:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
Después de modificar estos archivos, reinicia el almacenamiento de Podman para aplicar los cambios:
podman system migrate
Trabajar con Imágenes
Podman usa el mismo formato de imagen que Docker y puede descargar desde cualquier registro compatible con OCI.
Descargar Imágenes
# Descargar desde Docker Hub
podman pull docker.io/library/nginx:alpine
# Descargar desde Quay.io
podman pull quay.io/podman/hello
# Descargar desde GitHub Container Registry
podman pull ghcr.io/actions/actions-runner:latest
Listar Imágenes
podman images
Salida:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/library/nginx alpine a2bd6d6e82f0 2 weeks ago 43.3 MB
quay.io/podman/hello latest 5dd467fce50b 3 months ago 787 kB
Construir Imágenes
Podman usa Containerfile (o Dockerfile — ambos son soportados) y Buildah internamente:
# Containerfile
FROM docker.io/library/python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
Construye la imagen:
podman build -t my-python-app:latest .
Construir con un nombre de archivo específico:
podman build -f Containerfile.prod -t my-python-app:prod .
Subir Imágenes a un Registro
Etiqueta y sube una imagen a un registro:
podman tag my-python-app:latest quay.io/myuser/my-python-app:latest
podman login quay.io
podman push quay.io/myuser/my-python-app:latest
Eliminar Imágenes
# Eliminar una imagen específica
podman rmi docker.io/library/nginx:alpine
# Eliminar todas las imágenes sin usar
podman image prune -a
Gestión de Pods
Los pods son un concepto tomado de Kubernetes. Un pod agrupa uno o más contenedores que comparten el mismo namespace de red, lo que significa que pueden comunicarse a través de localhost y compartir mapeos de puertos.
Crear un Pod
Crea un pod con mapeos de puertos definidos a nivel de pod:
podman pod create --name my-web-pod -p 8080:80 -p 5432:5432
Agregar Contenedores a un Pod
Agrega un contenedor nginx y un contenedor PostgreSQL al pod:
podman run -d --pod my-web-pod --name web-server docker.io/library/nginx:alpine
podman run -d --pod my-web-pod --name db-server \
-e POSTGRES_PASSWORD=secretpass \
-e POSTGRES_DB=appdb \
docker.io/library/postgres:16-alpine
Ambos contenedores ahora comparten el mismo namespace de red. El contenedor nginx puede conectarse a PostgreSQL en localhost:5432, y los clientes externos acceden a nginx vía host:8080.
Gestionar Pods
# Listar todos los pods
podman pod ls
# Ver detalles del pod
podman pod inspect my-web-pod
# Detener todos los contenedores en un pod
podman pod stop my-web-pod
# Iniciar un pod
podman pod start my-web-pod
# Eliminar un pod y sus contenedores
podman pod rm -f my-web-pod
Generar YAML de Kubernetes desde Pods
Una de las características únicas de Podman es generar manifiestos de Kubernetes a partir de pods en ejecución:
podman generate kube my-web-pod > my-web-pod.yaml
Esto crea un archivo YAML compatible con Kubernetes que puedes desplegar directamente en un clúster de Kubernetes con kubectl apply -f my-web-pod.yaml. Esto hace de Podman una excelente herramienta para desarrollo local cuando tu objetivo de producción es Kubernetes.
Podman Compose
Podman soporta archivos Docker Compose para stacks de aplicaciones multi-contenedor. Hay dos enfoques:
Usar podman-compose
Instala podman-compose (una reimplementación comunitaria en Python):
sudo apt install -y python3-pip
pip3 install podman-compose
Úsalo igual que docker-compose:
podman-compose up -d
podman-compose ps
podman-compose logs -f
podman-compose down
Usar el Comando Integrado podman compose
Podman 4.7+ incluye un comando integrado podman compose que delega a un proveedor de compose externo (docker-compose o podman-compose):
podman compose up -d
podman compose down
Ejemplo de docker-compose.yml
Un archivo docker-compose.yml estándar funciona sin modificación:
version: "3.8"
services:
web:
image: docker.io/library/nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html:ro
depends_on:
- api
api:
image: docker.io/library/node:20-alpine
working_dir: /app
volumes:
- ./api:/app
command: node server.js
environment:
- DB_HOST=db
- DB_PORT=5432
db:
image: docker.io/library/postgres:16-alpine
environment:
POSTGRES_PASSWORD: secretpass
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Ejecutar con Podman Compose:
podman-compose up -d
Generar Unidades systemd desde Contenedores
Podman se integra con systemd para gestionar contenedores como servicios del sistema. Esto es especialmente útil para servidores donde necesitas que los contenedores inicien en el arranque y se reinicien ante fallos.
Generar un Archivo de Unidad desde un Contenedor en Ejecución
Primero, inicia un contenedor:
podman run -d --name my-nginx -p 8080:80 docker.io/library/nginx:alpine
Genera la unidad systemd:
podman generate systemd --new --name my-nginx > ~/.config/systemd/user/container-my-nginx.service
La bandera --new asegura que el archivo de unidad cree un contenedor nuevo cada vez (en lugar de reiniciar uno existente), lo cual es la práctica recomendada.
Habilitar e Iniciar el Servicio
mkdir -p ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable --now container-my-nginx.service
Habilitar Lingering para Sesiones sin Inicio de Sesión
Por defecto, los servicios systemd de usuario se detienen cuando el usuario cierra sesión. Habilita lingering para mantenerlos ejecutándose:
sudo loginctl enable-linger $USER
Verificar el Servicio
systemctl --user status container-my-nginx.service
Quadlet (Podman 4.4+)
Para Podman 4.4 y posterior, Quadlet proporciona un formato declarativo más simple. Crea un archivo .container en ~/.config/containers/systemd/:
# ~/.config/containers/systemd/my-nginx.container
[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80
Volume=./html:/usr/share/nginx/html:ro
[Service]
Restart=always
[Install]
WantedBy=default.target
Recarga systemd e inicia el servicio:
systemctl --user daemon-reload
systemctl --user start my-nginx.service
Migrar de Docker a Podman
Si actualmente usas Docker, la ruta de migración a Podman es directa.
Instalar el Paquete de Compatibilidad Docker
sudo apt install -y podman-docker
Esto instala un comando docker que es alias de podman y crea un socket de emulación /var/run/docker.sock. Los scripts existentes que llaman a docker usarán Podman en su lugar.
Migrar Imágenes Docker
Exporta imágenes desde Docker e impórtalas en Podman:
# En el sistema Docker
docker save my-app:latest -o my-app.tar
# En el sistema Podman
podman load -i my-app.tar
Convertir Archivos Docker Compose
La mayoría de los archivos docker-compose.yml funcionan sin modificación. Los principales ajustes a tener en cuenta:
- Calificar completamente los nombres de imagen: Reemplaza
nginx:alpinecondocker.io/library/nginx:alpine - Modo de red: Algunos modos de red específicos de Docker pueden diferir
- Plugins de volumen: Los plugins de volumen de Docker no son soportados; usa los drivers de volumen nativos de Podman
Actualizar Pipelines CI/CD
Reemplaza comandos docker con podman en tus scripts de pipeline, o instala podman-docker para que el alias docker lo maneje:
# Ejemplo de GitHub Actions
steps:
- name: Install Podman
run: sudo apt install -y podman podman-docker
- name: Build image
run: podman build -t my-app:${{ github.sha }} .
- name: Push image
run: |
podman login -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_PASS }} ghcr.io
podman push my-app:${{ github.sha }} ghcr.io/${{ github.repository }}:${{ github.sha }}
Redes
El modelo de red de Podman difiere entre los modos con root y sin root.
Redes sin Root
En modo sin root, Podman usa slirp4netns o pasta (Podman 5.0+) para proporcionar conectividad de red sin privilegios de root:
- slirp4netns: Crea un dispositivo TAP en un user namespace, proporcionando redes basadas en NAT. El reenvío de puertos por encima de 1024 funciona sin root.
- pasta: Una alternativa más nueva y rápida que proporciona rendimiento mejorado y menor sobrecarga.
Mapear puertos en modo sin root:
podman run -d -p 8080:80 docker.io/library/nginx:alpine
Nota: Vincular a puertos por debajo de 1024 (ej., 80, 443) requiere privilegios de root o ajustar el inicio de puertos no privilegiados del sistema con
sudo sysctl net.ipv4.ip_unprivileged_port_start=80.
CNI y Netavark
Podman soporta dos backends de red:
- CNI (Container Network Interface): El backend legacy usando plugins CNI.
- Netavark: La pila de red moderna basada en Rust (por defecto en Podman 4.0+).
Crear una red personalizada:
podman network create my-network
Ejecutar contenedores en la red personalizada:
podman run -d --network my-network --name container-a docker.io/library/alpine sleep 3600
podman run -d --network my-network --name container-b docker.io/library/alpine sleep 3600
Los contenedores en la misma red pueden alcanzarse entre sí por nombre:
podman exec container-a ping -c 3 container-b
Inspeccionar Redes
# Listar redes
podman network ls
# Inspeccionar una red
podman network inspect my-network
# Eliminar una red
podman network rm my-network
Referencia de Comandos de Podman
La siguiente tabla lista los comandos de Podman más utilizados y sus equivalentes en Docker:
| Comando Podman | Equivalente Docker | Descripción |
|---|---|---|
podman run | docker run | Crear e iniciar un contenedor |
podman ps | docker ps | Listar contenedores en ejecución |
podman ps -a | docker ps -a | Listar todos los contenedores |
podman images | docker images | Listar imágenes locales |
podman pull | docker pull | Descargar una imagen de un registro |
podman build | docker build | Construir una imagen desde un Containerfile/Dockerfile |
podman push | docker push | Subir una imagen a un registro |
podman exec | docker exec | Ejecutar un comando en un contenedor en ejecución |
podman logs | docker logs | Ver logs del contenedor |
podman stop | docker stop | Detener un contenedor en ejecución |
podman rm | docker rm | Eliminar un contenedor |
podman rmi | docker rmi | Eliminar una imagen |
podman volume create | docker volume create | Crear un volumen con nombre |
podman network create | docker network create | Crear una red |
podman pod create | N/A | Crear un pod |
podman pod ls | N/A | Listar pods |
podman generate systemd | N/A | Generar archivos de unidad systemd |
podman generate kube | N/A | Generar YAML de Kubernetes |
podman system prune | docker system prune | Eliminar datos sin usar |
podman login | docker login | Iniciar sesión en un registro de contenedores |
podman inspect | docker inspect | Ver información detallada de contenedor/imagen |
Solución de Problemas
Error: short-name resolution enforced
Problema: Podman se niega a descargar una imagen usando un nombre corto como nginx.
Solución: Usa el nombre de imagen completamente calificado o configura los registros de búsqueda:
# Usar nombre completamente calificado
podman pull docker.io/library/nginx:alpine
# O configurar registros de búsqueda
sudo tee /etc/containers/registries.conf.d/00-unqualified-search.conf <<'EOF'
[registries.search]
registries = ['docker.io', 'quay.io']
EOF
Error: cannot find UID/GID mapping
Problema: Los contenedores sin root fallan porque los mapeos de UID/GID subordinados no están configurados.
Solución: Agrega mapeos para tu usuario:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
podman system migrate
Error: permission denied on volume mount
Problema: Un contenedor sin root no puede acceder a un directorio montado por bind.
Solución: Agrega el sufijo de etiqueta SELinux :Z o :z, o asegúrate de que el directorio sea propiedad de tu usuario:
# Corregir propiedad
podman unshare chown -R 0:0 /path/to/volume
# O usar flag Z para SELinux
podman run -v /path/to/volume:/data:Z my-image
El Contenedor No Puede Vincular al Puerto 80
Problema: Podman sin root no puede vincular a puertos por debajo de 1024.
Solución: Reduce el valor de inicio de puertos no privilegiados:
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
# Hacerlo persistente
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-podman-ports.conf
sudo sysctl --system
Podman Compose Falla con Error de Red
Problema: podman-compose produce errores al crear redes.
Solución: Asegúrate de que el backend de red de Podman esté funcionando y reinicia si es necesario:
podman network ls
podman system reset --force
# Recrea tus contenedores después del reset
Los Contenedores No Inician Después del Reinicio
Problema: Los contenedores systemd a nivel de usuario no inician después de un reinicio.
Solución: Habilita lingering para tu usuario:
sudo loginctl enable-linger $USER
Descarga Lenta de Imágenes
Problema: La descarga de imágenes es lenta en modo sin root.
Solución: Habilita fuse-overlayfs para mejor rendimiento de almacenamiento:
sudo apt install -y fuse-overlayfs
Verifica que se esté usando:
podman info --format '{{.Store.GraphDriverName}}'
# Debería mostrar: overlay
Resumen
Podman es un motor de contenedores maduro, seguro y compatible con Docker que elimina la necesidad de un proceso demonio privilegiado. Su enfoque de sin root por defecto, soporte nativo de pods e integración con systemd lo convierten en una excelente opción tanto para entornos Linux de desarrollo como de producción. Para cualquier persona que ejecute contenedores en servidores Linux, Podman proporciona una clara ventaja de seguridad sin sacrificar compatibilidad con el ecosistema Docker.
En esta guía aprendiste cómo instalar Podman en Ubuntu, ejecutar contenedores sin root, gestionar imágenes y pods, usar Podman Compose con archivos docker-compose.yml existentes, generar unidades systemd para la gestión automática del ciclo de vida de contenedores, configurar redes y migrar desde Docker.
Para temas relacionados con contenedores, consulta nuestras guías sobre Cómo Instalar Docker en Ubuntu y Docker Compose: Guía Práctica para Administradores de Sistemas.