Tutoriales

Motor Podman y Docker en Linux

cualquiera en estibador El grupo puede convertirse efectivamente en root porque el demonio Docker se ejecuta como root y obedece los comandos enviados a través de su socket Unix. tablero Adopta un enfoque diferente: elimina los demonios centrales y admite contenedores, pods y servicios Quadlet sin raíz administrados a través de systemd.

Imagine que un desarrollador necesita ejecutar un contenedor en un servidor de compilación compartido, por lo que agrega su cuenta a docker grupo. Este cambio aparentemente inofensivo podría proporcionarles acceso de nivel raíz al host.

Por ejemplo, pueden ejecutar docker run -v /:/host y acceder o modificar archivos host porque el demonio Docker (dockerd) opera con privilegios de root y ejecuta las solicitudes recibidas a través de su socket.

La propia documentación de Docker advierte explícitamente: docker El grupo otorga permisos de nivel raíz, lo que lo convierte en un tema importante en entornos conscientes de la seguridad. Docker Engine ofrece un modo sin raíz, pero no es el modo predeterminado y no siempre está habilitado en los servidores de producción.

tabernero Elimine el demonio por completo, ejecute el contenedor como un proceso hijo del consumidor que inició el contenedor y use Linux El espacio de nombres de usuario asigna raíces de contenedores a usuarios de host sin privilegios.

También apoya Pods estilo Kubernetes E integrar con systemd a través de los siguientes métodos Cuadruplicarpermitiendo gestionar contenedores como servicios nativos.


En esta guía, veremos cómo funciona la arquitectura sin raíz de Podman, la compararemos con Docker desde una perspectiva de seguridad y cómo ejecutar contenedores, pods y servicios administrados por systemd sin proporcionar acceso innecesario a nivel de raíz a los usuarios.

Cómo Docker Engine y Podman inician contenedores

Ambos motor acoplable y tablero Ejecute la misma imagen de contenedor compatible con OCI. Las diferencias importantes son la ubicación entre los comandos y los contenedores, cómo se administran estos componentes y qué usuario los posee.

Arquitectura del motor Podman y Docker

Con la ayuda del motor Docker, docker El comando actúa como un cliente. Lo hace enviando una solicitud API. /var/run/docker.sock rootear propiedad dockerd demonio. Luego, Docker usa Containerd y el tiempo de ejecución OCI, p. runc Crear y gestionar contenedores.

De forma predeterminada, toda la ruta de control está asociada con el demonio Docker de propiedad raíz, razón por la cual el acceso a sus sockets proporciona efectivamente control a nivel de raíz del host.

si dockerd Una vez detenido, Docker normalmente también pierde el control de sus contenedores. La característica de resiliencia instantánea de Docker mantiene los contenedores en funcionamiento si el demonio no está disponible, pero no elimina el demonio de la arquitectura.

tablero Adopte un enfoque diferente. No hay ningún demonio central esperando las solicitudes de los clientes. este podman El comando crea e inicia directamente el contenedor, usa conmon (monitor de contenedor) para monitorear el proceso del contenedor y usa el tiempo de ejecución de OCI (generalmente crun) para crear el contenedor.

Debido a que cada contenedor tiene su propio proceso de monitoreo, tabernero No es necesario que el demonio compartido siga ejecutándose después de iniciar el contenedor. En modo sin raíz, estos procesos se pueden ejecutar con una cuenta de usuario normal en lugar de a través de un servicio de propiedad raíz.

Este diseño sin demonios también se adapta naturalmente a systemd y Quadlet, permitiendo que los contenedores y Pods se administren como consumidores o servicios del sistema sin la necesidad de introducir demonios de contenedores en ejecución permanente.

Si esto finalmente explica por qué el grupo Docker aparece en cada auditoría de seguridad, compártalo con cualquiera que todavía agregue desarrolladores de forma predeterminada.

Instale Podman en Rocky Linux y Ubuntu

Ahora que sabes lo que sucede bajo el capó, instalemos tablero En el servidor de laboratorio (192.168.122.248) como un usuario normal de tecmint sudo Derechos de uso. No hay demonios que puedan habilitarse posteriormente.

existir LokiLinux, AlmaLinuxy RHELPodman está disponible a través del repositorio de AppStream, por lo que dnf Se puede instalar directamente:

sudo dnf install -y podman

existir ubuntu y Durbanprimero actualice el índice del paquete para que apt pueda instalar la última versión empaquetada:

sudo apt update
sudo apt install -y podman

exacto tabernero La versión depende de la distribución y distribución. Por ejemplo, Ubuntu 26.04 LTS Paquete actual Tablero 5.7.0mientras que la documentación ascendente de Podman ya está disponible 6.1 serie.

Los comandos y el flujo de trabajo sin raíz utilizados en esta guía son los mismos que tablero 5 y 6.

Establecer ID de usuario esclavo

Usos de Podman sin raíces linux El espacio de nombres de usuario asigna usuarios de contenedores a usuarios de host sin privilegios. Para que este mapeo funcione correctamente, el usuario debe estar subordinado a los rangos UID y GID. /etc/subuid y /etc/subgid. tabernero Verifique estos archivos al crear un contenedor sin raíz.

comprobar si tecmint La cuenta ya tiene el alcance requerido:

grep tecmint /etc/subuid /etc/subgid

Debería ver un resultado similar al siguiente:

/etc/subuid:tecmint:100000:65536
/etc/subgid:tecmint:100000:65536

Si no hay entradas tecmint en ninguno de los archivos, agregue los rangos UID y GID dependientes:

sudo usermod --add-subuids 100000-165535 \
             --add-subgids 100000-165535 tecmint

Luego migre el estado Podman existente del usuario:

podman system migrate

El paso de migración es importante al cambiar los rangos de ID subordinados porque Podman sin raíz puede mantener activos los programas suspendidos y los espacios de nombres de consumidores existentes con sus contrapartes anteriores. La migración del sistema Podman detiene los contenedores relevantes y pausa el proceso para que nuevos /etc/subuid y /etc/subgid El mapeo entrará en vigor.

En este punto, tecmint tiene todo lo que necesitas para comenzar a usar Podman en modo rootless sin pertenecer a un grupo de Docker privilegiado.

Compare Podman y Docker con cargas de trabajo reales

y tabernero Después de la instalación, la forma más clara de ver la diferencia es ejecutar una carga de trabajo que normalmente se ejecutaría usando Docker y luego verificar qué consumidor de host posee el proceso resultante.

Ejemplo 1: comprobar qué usuario de host posee un proceso contenedor

Ejemplo 1: comprobar qué usuario de host posee un proceso contenedor

Inicie el contenedor Alpine: tecmint No sudoy luego observe su proceso desde el lado del host:

podman run -d --name sleeper docker.io/library/alpine sleep 600
ps -o user,pid,cmd -C sleep

Debería ver un resultado similar al siguiente:

USER         PID CMD
tecmint     4821 sleep 600

Ahora revisa al consumidor desde el interior del contenedor:

podman exec sleeper whoami

Este comando imprime:

root

Esta es una distinción importante: la raíz dentro de un contenedor sin raíz no es la raíz en la máquina host. tabernero Utilice un espacio de nombres de usuario para asignar el usuario raíz del contenedor a una identidad de host sin privilegios. Desde la perspectiva del anfitrión, el proceso de sueño pertenece a tecmint.

A modo de comparación, inicie la misma carga de trabajo a través de un demonio propiedad de la raíz de Docker:

sudo docker run -d --name sleeper-docker docker.io/library/alpine sleep 600
ps -o user,pid,cmd -C sleep

El proceso del contenedor Docker aparece como propietario root en la máquina anfitriona.

Por lo tanto, Rootless Podman reduce el impacto de un compromiso o escape de un contenedor: un atacante que viola un contenedor no obtiene automáticamente acceso raíz al host. Inicialmente heredan los permisos del usuario host en el que se ejecuta el contenedor. Sigue siendo importante que la cuenta tecmint solo tenga los permisos que realmente necesita.

Limpie los dos contenedores de prueba antes de continuar:

podman rm -f sleeper
sudo docker rm -f sleeper-docker

Si alguna vez ha tenido que justificar el acceso al contenedor ante su equipo de seguridad, comparta esta información con sus colegas que todavía están ejecutando cada contenedor. sudo Estibadores.

Ejemplo 2: agrupar servidores web y bases de datos en Pods

El primer ejemplo ejecuta un único contenedor, pero las aplicaciones reales suelen constar de varios contenedores que necesitan comunicarse. estibador Este problema normalmente se soluciona utilizando redes definidas por el usuario, mientras que tabernero Los contenedores relacionados se pueden colocar en pods que comparten un espacio de nombres de red.

Crea un Pod y publica el puerto. 8080 Vaya al puerto en la máquina host 80 Dentro de la cápsula:

podman pod create --name webstack -p 8080:80

Ahora inicia MariaDB y Nginx en el mismo pod:

podman run -d --pod webstack --name db -e MARIADB_ROOT_PASSWORD=ChangeMe123 docker.io/library/mariadb:11
podman run -d --pod webstack --name web docker.io/library/nginx:alpine

Comprobar módulo:

podman pod ps

Debería ver un resultado similar al siguiente:

POD ID        NAME        STATUS      CREATED         INFRA ID      # OF CONTAINERS
3f9c2a71b0de  webstack    Running     40 seconds ago  8a1d5e2c4f90  3

Incluso si solo inició dos contenedores, es normal ver tres contenedores. tabernero Cree un contenedor de infraestructura adicional para el Pod. Mantiene abierto el espacio de nombres de red compartido del pod para que otros contenedores puedan compartirlo.

Dado que los contenedores del Pod comparten el mismo espacio de nombres de red, pueden acceder entre sí a través de localhost. Por ejemplo, un contenedor Nginx puede conectarse a MariaDB:

127.0.0.1:3306

Este ejemplo no tiene configuración. nginx usar base de datos maríapor lo que esta conexión solo demuestra el modelo de red. En aplicaciones prácticas, web El contenedor requiere configuración y credenciales a nivel de aplicación para comunicarse con la base de datos.

tabernero También es posible generar YAML compatible con Kubernetes desde pods:

podman kube generate webstack > webstack.yaml

Luego puedes usar este YAML para reconstruir la carga de trabajo:

podman kube play webstack.yaml

esto da tablero Un puente útil entre los contenedores nativos y las definiciones de cargas de trabajo estilo Kubernetes. Docker proporciona otros mecanismos para definir aplicaciones de múltiples contenedores, como Compose, pero no utiliza el mismo Podman. kube generate y kube play Exporte y vuelva a crear el flujo de trabajo del Pod.

Ejemplo 3: uso de Quadlet para ejecutar un contenedor como servicio systemd

El pod del ejemplo 2 no regresa después del reinicio porque no hay ningún demonio para reiniciarlo. tabernero Descargue este trabajo a systemd a través de Quadlet, lo que .container Coloque los archivos en su directorio personal en una unidad systemd:

mkdir -p ~/.config/containers/systemd

existir ubuntu y Durbanusa nano para crear archivos unitarios:

nano ~/.config/containers/systemd/webapp.container

existir LokiLinux, AlmaLinuxy RHELla instalación mínima usa vi en lugar de nano, así que usa vi allí:

vi ~/.config/containers/systemd/webapp.container

Luego agregue la siguiente configuración al archivo:

# ~/.config/containers/systemd/webapp.container
[Unit]
Description=Nginx web container managed by Quadlet

[Container]
Image=docker.io/library/nginx:alpine
ContainerName=webapp
PublishPort=8081:80
AutoUpdate=registry

[Service]
Restart=always

[Install]
WantedBy=default.target

aquí:

  • Image Utilice la ruta de registro completa donde AutoUpdate necesidad.
  • ContainerName Reemplazar nombre predeterminado systemd-webapp.
  • PublishPort Utilice el puerto 8081 para evitar conflictos con el Pod del ejemplo 2.
  • AutoUpdate=registry Jean Boardman auto-update Extraiga imágenes más nuevas.
  • Restart=always Reinicie el contenedor cada vez que se detenga.
  • WantedBy=default.target Para iniciarlo con su sesión de usuario, reemplace systemctl enable.

Guarde el archivo y salga del editor. Dado que una instancia de systemd no rooteada se detiene al cerrar sesión, primero habilite el retraso y luego cargue e inicie la unidad resultante:

sudo loginctl enable-linger tecmint
systemctl --user daemon-reload
systemctl --user start webapp.service

Si el inicio falla y no se encuentra Unit webapp.service, Quadlet rechaza el archivo y /usr/libexec/podman/quadlet -dryrun -user imprime el error exacto. Después de comenzar, pruebe si hay fallas matando el contenedor y verificando el servicio después de unos segundos:

podman kill webapp
systemctl --user status webapp.service --no-pager

producción:

● webapp.service - Nginx web container managed by Quadlet
     Loaded: loaded (/home/tecmint/.config/containers/systemd/webapp.container; generated)
     Active: active (running) since Tue 2026-10-06 11:42:17 IST; 4s ago

este 4s ago La marca de tiempo muestra que systemd inició un nuevo contenedor sin root.

¿Qué pasaría si Quadlet simplemente reemplazara un montón de ejecución de Docker? --restart Los scripts se escriben para usted y se comparten con las personas que mantienen los runbooks de su servidor.

Cuándo elegir el motor Podman o Docker

Después de estos tres paradigmas, la elección suele depender de su entorno. motor acoplable Cuando su equipo depende de funciones específicas de Docker Desktop, Docker Swarm o BuildKit, es aún más fácil porque estas herramientas se basan en el demonio Docker.

tabernero Más adecuado para servidores compartidos, clústeres basados ​​en RHEL y en cualquier lugar donde la auditoría pregunte quién puede convertirse en root. este podman-docker El paquete proporciona un docker comando llamado taberneroy las herramientas que requieren sockets Docker (como los ejecutores de CI) pueden usar los sockets API de Podman. systemctl --user enable --now podman.socket.

La mayoría de las personas enfrentan una limitación. Los contenedores sin raíz no pueden vincular puertos por debajo de 1024, por lo que -p 80:80 No se puede exponer el puerto privilegiado debido a una falla en el puerto rootless 80. Publique un puerto alto detrás de un proxy inverso o reduzca el límite usando sudo sysctl net.ipv4.ip_unprivileged_port_start=80 y guardarlo en /etc/sysctl.d/.

en conclusión

tablero Ejecute la misma imagen que a continuación. motor acoplable No es necesario un demonio raíz, asigne la raíz del contenedor a un usuario normal y deje que systemd administre el contenedor a través de Quadlet. En un servidor compartido, esto elimina el mayor riesgo de establecer la configuración predeterminada de Docker sin cambiar los comandos diarios.

Si está trabajando para obtener la certificación Red Hat, nuestro RHCSA (RHEL 10/EX200) El curso Pro tecmint cubre las habilidades de RHEL en las que dependen los contenedores sin raíz, incluidos systemd y SELinux.

Nos encantaría saber cómo su equipo está ejecutando contenedores hoy. ¿Ha movido sus cargas de trabajo de producción a Podman desarraigado o Swarm le permite continuar usando Docker? Comparta sus archivos Quadlet o errores de migración en los comentarios.

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba