Saltar al contenido

Docker vs LXC en Proxmox: cuál elegir para empezar

Docker vs LXC en Proxmox en casa: qué aísla cada uno, cuándo usar una VM y cómo diagnosticar disco lleno y limitar los logs de Docker.

10 min de lecturaGonzalo
En esta guía7 secciones
Docker vs LXC en Proxmox para organizar servicios de un homelab

Docker vs LXC en Proxmox no se decide mirando sólo cuánta RAM consume un contenedor vacío. Docker empaqueta aplicaciones; LXC permite administrar un sistema Linux separado. Ambos comparten el kernel del host y ambos necesitan mantenimiento.

La lectura de disco del 2 de septiembre que aparece más abajo conserva una lección útil: «reclamable» no quiere decir «prescindible». Si has llegado porque falta espacio, salta al diagnóstico de disco y rotación de logs.

Yo elegí Docker para desplegar aplicaciones. Elegiría LXC cuando necesitase administrar un Linux separado dentro de Proxmox. Si hace falta otro kernel, un dispositivo delicado o una frontera más dura, salto a una máquina virtual. No intento que una herramienta gane las tres carreras.

Árbol de decisión Docker vs LXC en Proxmox según el tipo de aislamiento
La bifurcación que uso: Docker empaqueta la aplicación; LXC me da un sistema. Una VM entra cuando compartir kernel deja de ser aceptable.

Una lectura de disco, no un objetivo de limpieza

Tomé estas salidas el 2 de septiembre de 2026, sin parar ni limpiar nada para que el dibujo saliera más bonito:

ServerVersion=29.3.0 StorageDriver=overlay2 CgroupVersion=2 Containers=12 Running=11
volumes=31
up 2 hours, 27 minutes
temp_mC=53000

El detalle de disco fue menos fotogénico:

TYPE            TOTAL  ACTIVE  SIZE      RECLAIMABLE
Images          50     12      30.27GB   7.133GB (23%)
Containers      12     11      63.11MB   60.83MB (96%)
Local Volumes   31     6       3.458GB   3.325GB (96%)
Build Cache     68     0       2.475GB   0B

Esa salida es histórica, no el estado actual del servidor. Antes de borrar toca averiguar qué guarda cada volumen y qué imagen necesitas conservar. La columna «reclamable» habla de referencias de Docker, no del valor de los datos.

En aquella lectura se usaba ext4 sobre LVM y overlay2 para las capas. Cambiar Docker por LXC no resuelve por sí solo la acumulación de datos, imágenes o registros.

Docker llena el disco: qué mirar antes de borrar

Que Docker marque espacio «reclamable» no significa que puedas tirarlo. Un volumen sin contenedor puede guardar una base de datos pendiente de recuperar. Y un contenedor pequeño puede acumular muchos logs fuera de su capa de escritura.

Este problema aparece en una pregunta de soporte sobre logs que llenan el disco. Es un caso histórico, no una medición de cuántos lectores lo sufren. La solución actual empieza por separar datos de la aplicación, imágenes y registros.

Primero, localiza el espacio

En un host Linux con Docker Engine local, estos comandos consultan; no limpian:

docker context show
docker info --format '{{.DockerRootDir}}'
df -h
df -i
docker system df -v
docker ps -a --size

df -h muestra los sistemas de archivos llenos; df -i permite detectar si se han agotado los inodos (las entradas disponibles para archivos), aunque queden gigas libres. Cruza la ruta que devuelve DockerRootDir con su punto de montaje. Si tu contexto apunta a otro servidor, ejecuta df allí: el disco de tu portátil no explica el espacio del daemon remoto. Docker Desktop añade su propia máquina virtual y disco virtual; este recorrido no mide ese disco desde el sistema anfitrión.

docker system df -v desglosa imágenes, capas de contenedores, volúmenes y caché de construcción. No es una contabilidad completa del disco: los bind mounts viven en rutas del host y el tamaño de la capa escribible no incluye los logs del driver. Tampoco sumes tamaños virtuales de imágenes como si sus capas no se compartieran.

Para un servicio definido en Compose, entra en la carpeta de su proyecto y sustituye app por su nombre real. Usa las mismas opciones -f y -p con las que lo desplegaste, si las tiene:

docker compose config --services
contenedor=$(docker compose ps -aq app)
test -n "$contenedor" || exit 1
docker inspect --format '{{json .HostConfig.LogConfig}}' "$contenedor"
docker inspect --format '{{json .Mounts}}' "$contenedor"
docker logs --tail 50 "$contenedor"

El ejemplo supone una sola réplica de app. Si hay varias, examina cada ID por separado. Mounts distingue un volumen de una carpeta montada desde el host; comprueba esa carpeta antes de culpar a las imágenes. Los registros y las rutas pueden contener información privada: no pegues la salida completa en un foro.

Limita los logs de un servicio, no reinicies todo Docker

Docker documenta que json-file sin rotación puede agotar el disco. Recomienda el driver local para el uso general porque rota por defecto. Si tu recolector depende de json-file, puedes mantenerlo y fijar límites explícitos. Añade este bloque dentro del servicio existente, junto a image y volumes, sin sustituir el resto de su configuración:

services:
  app:
    # Conserva aquí su imagen, volúmenes, puertos y demás opciones
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

El fragmento no es un Compose completo. Son límites por contenedor, no una cuota global ni una garantía de conservar varios días. Las líneas antiguas se van descartando cuando rota. Si necesitas historial, guárdalo fuera con una política de retención; no confundas rotación con copia.

Reiniciar no aplica el cambio. Hay que recrear el contenedor. Antes, confirma que los datos están en sus volúmenes o carpetas persistentes y que dispones de copia recuperable. Guarda los logs necesarios antes de retirar el contenedor anterior y reserva una breve interrupción del servicio. Después:

docker compose config -q
docker compose up -d --no-deps --force-recreate --pull never app
contenedor=$(docker compose ps -aq app)
test -n "$contenedor" || exit 1
docker inspect --format '{{json .HostConfig.LogConfig}}' "$contenedor"
docker compose ps app
docker compose logs --tail 50 app

Mantén la misma imagen local y el mismo Compose: no mezcles la rotación con una actualización. --pull never impide descargar otra imagen, pero no recupera una imagen que ya no tienes ni fija una etiqueta que alguien haya cambiado localmente. Verifica además que la aplicación responde; un estado running no acredita su funcionamiento.

No hace falta cambiar daemon.json ni reiniciar el motor para esta receta por servicio. Y no borres ni trunques a mano los archivos internos de logs: Docker reserva su gestión al daemon.

Lo que comprobó el ensayo

3 de octubre de 2026, Docker Engine 29.8.0 y Compose 5.5.1. Un contenedor aislado emitió 1.500 líneas de relleno y una marca final. Con json-file, max-size: "10m" y max-file: "1", se recuperaron las 1.501 líneas mediante docker logs. La capa escribible figuraba en 0 bytes, pese a los 288.009 bytes de texto devueltos por ese comando. Son bytes de texto, no una medida del archivo de logs en disco.

Al cambiar el Compose a 10k y tres archivos, restart mantuvo la configuración anterior. Tras recrear únicamente app, la inspección sí mostró los nuevos límites y quedaron 97 líneas, desde linea-1405 hasta la marca final. El archivo ficticio montado desde el host seguía igual y el contenedor vecino conservó su ID. Se usó un umbral pequeño para provocar rotación sin llenar ningún disco; no es un ensayo de recuperación con el disco lleno ni una prueba de una base de datos.

Si todavía falta espacio, vuelve al desglose inicial. docker system prune elimina contenedores parados, redes sin uso, imágenes colgantes y caché de construcción; no borra volúmenes por defecto. -a amplía la limpieza de imágenes y --volumes añade volúmenes anónimos sin uso. No lo uses como tratamiento automático para cualquier aviso de disco. Identifica primero qué ocupa, a qué servicio pertenece y qué necesitas conservar para volver atrás.

Docker empaqueta la aplicación

Docker encaja cuando quiero declarar una aplicación con su imagen, variables, volúmenes y red, y repetir ese despliegue. El ejemplo real es Immich: servidor, base de datos, Redis y aprendizaje automático forman un stack. En la lectura del 2 de septiembre ocupaban 793,6 MiB, 98,76 MiB, 20,35 MiB y 383,9 MiB, respectivamente, en una lectura instantánea.

La ventaja no es que «pese poco». Algunas imágenes son enormes. Lo que compro con Docker es una unidad de despliegue: puedo fijar versión, reconstruir el contenedor y conservar los datos fuera de su capa desechable. La documentación de Docker sobre contenedores insiste en esa separación entre imagen, contenedor y datos persistentes.

También me gusta Compose porque deja el servicio en un fichero revisable. Eso no lo vuelve automático. Las políticas always y unless-stopped no expresan la misma intención. Un contenedor en Exited (0) puede haberse parado a propósito, sin que haya nada que Docker deba curar. Si no recuerdas esa intención, el orquestador parece caprichoso cuando en realidad obedece al pie de la letra.

LXC me sirve cuando quiero un Linux separado

Un contenedor LXC en Proxmox se parece más a una máquina ligera. Tiene su userspace, paquetes, usuarios, red y ciclo de vida. Lo administras como sistema. Esa es su virtud y la factura escondida: otro apt update, otro SSH, otro fichero de configuración y otra instancia que inventariar.

Lo usaría para un servicio que espera una distribución completa, para separar responsabilidades o para una aplicación que se lleva mal con el modelo de imagen inmutable. La documentación de Proxmox Container Toolkit explica que LXC comparte el kernel del host y distingue contenedores privilegiados y no privilegiados. Un LXC no es una VM diminuta.

Asistente oficial de creación de un contenedor LXC en Proxmox, con hostname y pestañas de plantilla, disco, CPU, memoria y red
Al crear un LXC eliges la identidad y los recursos de un sistema, no una imagen de aplicación Docker. Captura de la documentación de Proxmox, © Proxmox Server Solutions GmbH, GFDL 1.3 o posterior, sin modificaciones.

Hay una manía que evitaría: crear un LXC por aplicación y, dentro de cada LXC, instalar Docker. Puede servir si buscas una frontera administrativa concreta, pero como receta apila dos inventarios, dos redes y dos lugares donde perseguir permisos. El primer sábado parece ordenado. En enero ya no recuerdas qué capa expone el puerto.

La diferencia no está en una tabla de RAM

Docker y LXC comparten kernel; el consumo real depende mucho más del servicio, su caché y su base de datos que de la etiqueta pegada al contenedor. En mi lectura, el blog usaba 12,27 MiB y el aprendizaje automático de Immich 383,9 MiB. Ambos eran Docker. Convertir el segundo en LXC no haría desaparecer el modelo cargado en memoria.

La diferencia que sí noto cada mes es operativa:

  • Docker me pide cuidar imágenes, Compose, secretos, redes y volúmenes.
  • LXC me pide cuidar sistemas: paquetes, usuarios, plantillas, snapshots y configuración interior.
  • Una VM añade kernel y firmware virtual, a cambio de una frontera más clara.

Tres líneas bastan. El error es elegir por una cifra tomada con el servicio vacío y olvidar el trabajo que habrá cuando toque restaurarlo.

Qué pondría en cada sitio

Para una aplicación mantenida como imagen, empezaría por Docker. Immich, un proxy o un panel encajan si sus datos persistentes están definidos y la copia se ha probado. La guía sobre qué merece la pena autoalojar pone el filtro antes del compose up, que es donde se ahorran más disgustos.

Para un servidor Linux que necesito tratar como unidad, usaría LXC. Un entorno con paquetes propios o un servicio heredado que espera tocar /etc son ejemplos razonables. Preferiría un contenedor no privilegiado mientras el caso no exija lo contrario.

Reservaría la VM para Windows, otro kernel, passthrough sensible o una carga cuyo compromiso no quiero compartir con el host. El comparador de mini PC para virtualización deja filtrar por RAM y núcleos antes que por el logotipo de la CPU. Y un snapshot no sustituye la regla 3-2-1 del homelab: es rápido volver atrás, pero no es una copia fuera de la máquina.

Mi elección para empezar

Si el objetivo es servir aplicaciones en casa, empezaría con Docker sobre un Linux sencillo. Un host, un Compose por stack, versiones fijadas y una libreta corta que diga dónde viven los datos. Para el siguiente paso, consulta cómo actualizar un stack y conservar la imagen anterior: volver a una imagen vieja no devuelve una base de datos a su estado anterior. Ya da trabajo de sobra.

Si el objetivo es aprender Proxmox, levantaría un LXC no privilegiado y una VM pequeña para entender la diferencia. Después metería Docker donde haya aplicaciones, no como papel pintado dentro de cada contenedor.

Si falta espacio, primero identifica su origen. Cambiar de herramienta sin distinguir imágenes, datos y logs sólo mueve el problema de sitio.

Mediciones ejecutadas el 2 de septiembre de 2026 en un Intel N100 de Homelabista. docker stats y docker system df son lecturas puntuales; no son benchmarks de Docker frente a LXC. No se ejecutó LXC en este host y no se atribuyen cifras propias a Proxmox.

Antes de publicar el servicio, comprueba también por qué UFW puede no bloquear un puerto de Docker y cómo verificarlo desde fuera. Elegir Docker o LXC no sustituye esa comprobación de acceso.