El filesystem visible dentro de un contenedor no es un disco independiente. Es una vista compuesta por las capas read-only de la imagen, una capa writable propia de la instancia y cualquier mount aplicado sobre rutas concretas.
Texto
image layers read-only
+ container writable layer
+ volumes, bind mounts o tmpfs
= filesystem visible dentro del container
Esta composición explica por qué un archivo puede existir dentro de un contenedor, desaparecer al recrearlo o quedar oculto cuando se monta un volumen sobre su ruta.
Las imágenes deben poder compartirse entre muchas instancias sin duplicar todo su contenido ni permitir que un contenedor modifique el artefacto original.
Si cada contenedor copiara por completo la imagen:
la creación sería más lenta;
se desperdiciaría almacenamiento;
dos instancias no compartirían capas;
actualizar una imagen sería más costoso;
sería más difícil mantener inmutabilidad.
Docker utiliza una estrategia de capas y copy-on-write. Las capas de la imagen permanecen inmutables y compartidas. Cada contenedor recibe una capa de cambios separada.
image read-only
├── writable layer de api-1
└── writable layer de api-2
Si api-1 modifica /etc/app/config.json, Docker no cambia el archivo de la imagen. La versión modificada aparece en la writable layer de api-1. api-2 continúa viendo la versión original.
Cuando Docker resuelve una lectura:
busca primero el archivo visible en la capa superior;
si no existe allí, consulta capas inferiores;
respeta eliminaciones y ocultamientos registrados entre capas;
si existe un mount sobre la ruta, el mount domina la vista.
Copy-on-write significa que el contenido compartido se copia únicamente cuando una instancia necesita modificarlo.
Flujo simplificado:
Texto
lectura de archivo de la image
→ usar layer read-only directamente
modificación del archivo
→ copiar contenido a writable layer
→ aplicar cambio sobre la copia
→ futuras lecturas usan la copia superior
Este mecanismo ahorra espacio para workloads que leen mucho y modifican poco. Sin embargo, puede introducir coste cuando se actualizan archivos grandes o se realizan muchas escrituras pequeñas.
Según el filesystem y driver, puede implicar copias y operaciones adicionales. No asumas que mover un archivo grande dentro del contenedor siempre es una operación barata.
Si la imagen contiene archivos en /app/data y montas un volume vacío:
Bash
docker run --mounttype=volume,src=app-data,dst=/app/data my-app
el mount cubre la ruta. El proceso ve el contenido del volume, no directamente el contenido inferior de la imagen.
Dependiendo del tipo de volume y comportamiento de Docker, puede existir copia inicial de contenido en ciertos escenarios. No bases migrations o inicialización crítica en un comportamiento que no hayas verificado.
Un error frecuente es creer que los archivos fueron eliminados de la imagen cuando en realidad quedaron ocultos por el mount.
Docker puede usar distintas implementaciones para snapshots y filesystem por capas. En Linux, conceptos como OverlayFS han sido comunes; versiones recientes también pueden usar el image store de containerd según instalación y configuración.
La abstracción importante permanece:
capas read-only;
snapshot writable;
contenido administrado por Docker;
mounts explícitos para datos externos.
No manipules manualmente paths internos como /var/lib/docker. Su estructura depende del driver, versión y configuración, y modificarla puede corromper metadata.
Para reducir modificaciones accidentales o maliciosas:
Bash
docker run --read-only my-api
El root filesystem visible deja de aceptar escrituras. La aplicación puede necesitar paths escribibles específicos:
Bash
docker run \
--read-only \--tmpfs /tmp:rw,noexec,nosuid,size=64m \
my-api
También pueden montarse volumes para rutas durables.
Beneficios:
reduce persistencia de cambios tras comprometer el proceso;
descubre dependencias ocultas de escritura;
refuerza la idea de contenedor reemplazable;
limita algunos errores operativos.
No impide todas las modificaciones. Un proceso puede escribir en mounts permitidos, memoria, red o servicios externos. Es una capa de defensa, no una sandbox completa.
Escribir logs únicamente en /var/log/app.log dentro de la writable layer crea varios problemas:
desaparecen al eliminar la instancia;
pueden llenar el data root;
docker logs no los ve automáticamente;
varias réplicas producen archivos separados;
la investigación depende de entrar al contenedor.
Para aplicaciones modernas, suele preferirse stdout/stderr y un logging driver o collector con rotación y centralización.
Puede existir un caso válido para archivos de log específicos, pero entonces el mount, rotación, ownership y recolección deben diseñarse explícitamente.
Un named volume puede resolver persistencia local, pero si existen varias réplicas en hosts diferentes, cada host podría tener datos distintos. La arquitectura debe coincidir con disponibilidad y escalado requeridos.
Una aplicación descarga modelos o dependencias en /app/cache.
Si la cache puede regenerarse:
puede vivir en writable layer;
debe tener límite;
su pérdida al recrear es aceptable;
cold start debe contemplarse.
Si reconstruirla cuesta horas o depende de una fuente inestable, puede convenir un volume o cache externo. El criterio es el coste y garantía requerida, no solo “es un archivo”.
La writable layer comparte capacidad con otros recursos del Engine. Un contenedor que genera archivos sin límite puede impedir pulls, builds y logging de otros workloads.
Muestra paths añadidos, modificados o eliminados desde la perspectiva del contenedor. Es útil para detectar escrituras inesperadas, aunque no reemplaza observabilidad completa.