system onlinepath: /guias/devops-cloud/docker-desde-cero-imagenes-contenedores-y-volumenes/mode: knowledge_baselocal:
DevOps y cloud · Nivel inicial

Docker desde cero: imágenes, contenedores y volúmenes

Docker resolvió una frase que costaba horas: «en mi máquina funciona». Empaqueta la aplicación con todo lo que necesita para correr, de modo que se comporta igual en cualquier lado.

11 min de lectura▣ Actualizada el ◇ Por Underc0de
Respuesta rápida

Docker empaqueta una aplicación junto con todo lo que necesita para funcionar —el código, sus dependencias, sus librerías, su configuración— en una unidad que corre igual en cualquier máquina. Así desaparece el clásico «en mi computadora funciona»: si funciona en el contenedor, funciona en todos lados. Hay que distinguir dos cosas. Una imagen es una plantilla inmóvil, de solo lectura, con la aplicación y su entorno; es como una receta o un molde. Un contenedor es una instancia en ejecución de esa imagen; de una imagen se arrancan muchos contenedores iguales. La imagen se construye con un Dockerfile, un archivo de texto con los pasos para armarla. Y como un contenedor es efímero —al borrarlo se pierde lo que tenía dentro—, los datos que deben sobrevivir (una base de datos, archivos subidos) se guardan en volúmenes, un almacenamiento que vive fuera del contenedor. Docker no es una máquina virtual: comparte el núcleo del sistema, así que es mucho más liviano y rápido. Es la base de casi todo el DevOps moderno, incluida la orquestación.

Ver índice de contenidos
  1. 01Qué problema resuelve Docker
  2. 02Imagen y contenedor
  3. 03El Dockerfile
  4. 04Volúmenes: datos que sobreviven
  5. 05Errores frecuentes
  6. 06Preguntas frecuentes
  7. 07Fuentes

Qué problema resuelve Docker

Durante años, llevar una aplicación de la máquina del desarrollador al servidor era una fuente constante de problemas: versiones distintas de un lenguaje, una librería que faltaba, una variable de configuración diferente. El resultado era la frase temida: «en mi máquina funciona». El problema no era el código, sino el entorno donde corría.

La idea de empaquetar el entorno

Docker resuelve esto empaquetando la aplicación junto con su entorno completo: el sistema base, las dependencias, las librerías, la configuración, todo dentro de una unidad. Esa unidad corre igual en la laptop del desarrollador, en el servidor de pruebas y en producción, porque lleva su entorno consigo. Se acabó el «en mi máquina funciona»: la máquina viaja con la aplicación.

Una aclaración importante: Docker no es una máquina virtual. Una máquina virtual emula un sistema operativo entero, con su propio núcleo, lo que la hace pesada y lenta de arrancar. Un contenedor comparte el núcleo del sistema anfitrión y solo aísla la aplicación, por lo que ocupa mucho menos, arranca en segundos y permite correr decenas en una máquina que apenas sostendría unas pocas máquinas virtuales.

Imagen y contenedor

La relación entre imagen y contenedor en Docker y cómo los volúmenes conservan los datos, mostrada como un flujo. A la izquierda, el Dockerfile: un archivo de texto con la receta paso a paso para construir la aplicación, que indica de qué imagen base partir, qué dependencias instalar, qué código copiar y qué comando ejecutar al arrancar. Una flecha con la etiqueta construir lleva del Dockerfile a la imagen. En el centro a la izquierda, la imagen: una plantilla inmóvil y de solo lectura que contiene la aplicación con todo su entorno, comparada con un molde o una receta ya preparada; la imagen no corre por sí sola, es solo el paquete. Una flecha con la etiqueta ejecutar lleva de la imagen a los contenedores. En el centro a la derecha, los contenedores: instancias en ejecución de la imagen, y se muestran tres contenedores idénticos arrancados desde la misma imagen para ilustrar que de una sola imagen se pueden correr muchos contenedores iguales a la vez, cada uno aislado del resto. Cada contenedor es efímero: cuando se borra, todo lo que se escribió dentro de él se pierde. A la derecha, el volumen: un almacenamiento que vive fuera del contenedor, en el sistema anfitrión, y que se conecta al contenedor para guardar los datos que deben sobrevivir, como el contenido de una base de datos o los archivos que suben los usuarios; se muestra una flecha de doble sentido entre el contenedor y el volumen, indicando que el contenedor lee y escribe ahí pero los datos permanecen aunque el contenedor se elimine y se vuelva a crear. En el centro, resaltada, la diferencia clave que más confunde al empezar: la imagen es la plantilla de solo lectura y el contenedor es la instancia viva que corre, igual que en programación una clase es la plantilla y un objeto es la instancia. Abajo, la ventaja de fondo: como un contenedor comparte el núcleo del sistema en lugar de emular uno entero como hace una máquina virtual, es mucho más liviano y arranca en segundos. Al pie, la advertencia destacada: nunca se guardan datos importantes dentro del contenedor ni secretos dentro de la imagen; los datos van en volúmenes y los secretos en variables de entorno.
El Dockerfile construye la imagen; la imagen ejecuta contenedores; los volúmenes conservan los datos. La imagen es la plantilla; el contenedor, la instancia viva.

La confusión más común al empezar es entre imagen y contenedor. La analogía que lo aclara viene de la programación orientada a objetos: la imagen es como una clase (la plantilla) y el contenedor es como un objeto (la instancia creada a partir de esa plantilla).

  • Una imagen es inmóvil y de solo lectura: contiene la aplicación y su entorno, pero no corre por sí sola. Se descarga de un registro (como Docker Hub) o se construye a partir de un Dockerfile.
  • Un contenedor es una imagen en ejecución. De una misma imagen se arrancan muchos contenedores idénticos y aislados entre sí, lo que hace trivial escalar una aplicación corriendo más copias.
bash
# Descargar una imagen y correr un contenedor a partir de ella
docker pull nginx
docker run -d -p 8080:80 nginx   # -d en segundo plano, -p mapea puertos

# Ver los contenedores en ejecución
docker ps

El Dockerfile

Para empaquetar tu aplicación necesitás construir tu propia imagen, y eso se hace con un Dockerfile: un archivo de texto con la receta, paso a paso, de cómo se arma. Cada instrucción crea una capa, y Docker las reutiliza si no cambiaron, lo que acelera las reconstrucciones.

dockerfile
# De qué imagen base partir
FROM node:20-alpine
# Carpeta de trabajo dentro del contenedor
WORKDIR /app
# Copiar e instalar dependencias primero (aprovecha la caché)
COPY package*.json ./
RUN npm ci --omit=dev
# Copiar el resto del código
COPY . .
# Qué comando corre al arrancar el contenedor
CMD ["node", "server.js"]

Con ese archivo, docker build -t mi-app . construye la imagen, y docker run mi-app la corre. La imagen resultante lleva la aplicación y su entorno; se puede subir a un registro y desplegar en cualquier servidor. Un detalle de rendimiento y peso: partir de una imagen base pequeña (las variantes alpine) y copiar las dependencias antes que el código aprovecha la caché de capas.

Volúmenes: datos que sobreviven

Un contenedor es efímero: está pensado para crearse y destruirse con facilidad, y cuando se borra, todo lo que se escribió dentro de él desaparece. Eso es una ventaja para la aplicación —siempre arranca limpia— pero un desastre para los datos que deben persistir.

!
Los datos importantes nunca viven dentro del contenedor

El contenido de una base de datos, los archivos que suben los usuarios, los registros que hay que conservar: todo eso va en un volumen, un almacenamiento gestionado por Docker que vive fuera del contenedor, en el sistema anfitrión. El contenedor lee y escribe en el volumen, pero los datos permanecen aunque el contenedor se elimine y se vuelva a crear. Guardar datos importantes dentro del contenedor es uno de los errores que más caro se pagan.

bash
# Crear un volumen y montarlo en un contenedor de base de datos
docker volume create datos-db
docker run -d -v datos-db:/var/lib/postgresql/data postgres

La misma lógica separa la aplicación (sin estado, en la imagen) de los datos (con estado, en el volumen). Esa separación es la que permite luego actualizar la aplicación sin cortar el servicio y respaldar los datos por separado.

Errores frecuentes

  • Confundir imagen con contenedor. La imagen es la plantilla de solo lectura; el contenedor, la instancia que corre.
  • Guardar datos importantes dentro del contenedor. Al borrarlo se pierden; van en volúmenes.
  • Escribir secretos en la imagen o el Dockerfile. Quedan grabados en las capas; van en variables de entorno.
  • Imágenes enormes. Partir de bases pesadas o copiar todo sin filtrar hace imágenes lentas de mover; usar bases pequeñas y un .dockerignore.
  • Correr todo como root dentro del contenedor. Conviene un usuario sin privilegios por seguridad.
  • Meter varios servicios en un solo contenedor. La convención es un proceso por contenedor; para varios, se combinan con orquestación.
  • Creer que Docker es una máquina virtual. Comparte el núcleo; es mucho más liviano y no aísla igual.

Preguntas frecuentes

¿Qué es Docker y para qué sirve?

Docker es una herramienta que empaqueta una aplicación junto con todo lo que necesita para funcionar —su código, sus dependencias, sus librerías y su configuración— en una unidad que corre de la misma manera en cualquier máquina. Sirve para eliminar el clásico problema de que un programa funcione en la computadora de quien lo desarrolló pero falle en el servidor por diferencias de entorno, resumido en la frase «en mi máquina funciona». Con Docker, la aplicación lleva su entorno consigo, así que si funciona dentro del contenedor funcionará igual en la laptop del desarrollador, en el entorno de pruebas y en producción. Esto simplifica enormemente el despliegue, hace reproducibles los entornos y es la base de gran parte de las prácticas modernas de DevOps, incluidas la integración continua, el despliegue automatizado y la orquestación de aplicaciones a gran escala con herramientas como Kubernetes.

¿Cuál es la diferencia entre una imagen y un contenedor?

Una imagen es una plantilla inmóvil y de solo lectura que contiene la aplicación con todo su entorno, pero que no corre por sí sola: es como una receta o un molde ya preparado. Un contenedor es una instancia en ejecución de esa imagen, es decir, la aplicación efectivamente corriendo. La analogía más clara viene de la programación orientada a objetos: la imagen es como una clase, que define cómo son las cosas, y el contenedor es como un objeto, una instancia concreta creada a partir de esa clase. De una misma imagen se pueden arrancar muchos contenedores idénticos y aislados entre sí, lo que hace muy sencillo escalar una aplicación simplemente corriendo más copias. Las imágenes se descargan de registros como Docker Hub o se construyen a partir de un Dockerfile, mientras que los contenedores se crean, arrancan, detienen y borran a partir de esas imágenes según haga falta.

¿Qué es un Dockerfile?

Es un archivo de texto que contiene la receta, paso a paso, para construir una imagen de Docker con tu propia aplicación. En él se indica de qué imagen base partir, qué dependencias instalar, qué archivos de código copiar dentro y qué comando debe ejecutarse cuando el contenedor arranque. Cada instrucción del Dockerfile genera una capa, y Docker reutiliza las capas que no cambiaron entre una construcción y otra, lo que acelera mucho las reconstrucciones cuando solo se modifica el código. A partir del Dockerfile, un comando de construcción arma la imagen, que luego puede subirse a un registro y desplegarse en cualquier servidor. Escribir bien el Dockerfile —partir de una imagen base pequeña, copiar las dependencias antes que el código para aprovechar la caché y no incluir archivos innecesarios— influye directamente en el tamaño de la imagen y en la velocidad tanto de construcción como de despliegue.

¿Por qué necesito volúmenes si el contenedor ya guarda datos?

Porque un contenedor es efímero por diseño: está pensado para crearse y destruirse con facilidad, y cuando se borra, todo lo que se escribió dentro de él se pierde. Eso es una ventaja para la aplicación, que siempre arranca en un estado limpio y conocido, pero sería un desastre para los datos que deben conservarse, como el contenido de una base de datos, los archivos que suben los usuarios o los registros históricos. Los volúmenes resuelven esto: son un almacenamiento gestionado por Docker que vive fuera del contenedor, en el sistema anfitrión, y que se conecta al contenedor para que este lea y escriba ahí. Así, los datos permanecen aunque el contenedor se elimine y se vuelva a crear, por ejemplo al actualizar la aplicación a una versión nueva. Esta separación entre la aplicación sin estado y los datos con estado es fundamental, porque es lo que permite actualizar o reemplazar contenedores sin perder información.

¿Docker es lo mismo que una máquina virtual?

No, y confundirlos es un malentendido habitual. Una máquina virtual emula un sistema operativo completo, con su propio núcleo corriendo sobre el sistema anfitrión, lo que la hace relativamente pesada en consumo de recursos y lenta de arrancar, aunque ofrece un aislamiento muy fuerte. Un contenedor de Docker, en cambio, no emula un sistema operativo entero: comparte el núcleo del sistema anfitrión y solo aísla la aplicación y su entorno inmediato. Como consecuencia, un contenedor ocupa mucho menos espacio, arranca en segundos y permite correr decenas de ellos en una máquina que apenas sostendría unas pocas máquinas virtuales. La contrapartida es que el aislamiento es menor y que todos los contenedores comparten el mismo núcleo, lo que hay que tener en cuenta en escenarios donde la separación estricta es un requisito de seguridad. En la práctica, ambas tecnologías conviven y muchas veces los contenedores corren dentro de máquinas virtuales.

¿Dónde guardo las contraseñas y claves que usa mi contenedor?

En variables de entorno que se pasan al contenedor al ejecutarlo, o mediante un mecanismo de gestión de secretos, pero nunca escritas dentro de la imagen ni en el Dockerfile. La razón es que todo lo que se incluye en la imagen queda grabado de forma permanente en sus capas, y esas capas se pueden inspeccionar, de modo que un secreto escrito ahí queda expuesto a cualquiera que tenga acceso a la imagen, incluso si se «borra» en un paso posterior, porque la capa anterior sigue existiendo. Lo correcto es mantener la imagen genérica y sin credenciales, e inyectar los secretos en el momento de ejecutar el contenedor a través de variables de entorno o de un sistema de gestión de secretos, que además permite usar credenciales distintas en desarrollo, pruebas y producción con la misma imagen. Esta es exactamente la misma regla que se aplica al código fuente y a los pipelines: los secretos viven en un mecanismo aparte pensado para protegerlos, no dentro de lo que se versiona o se distribuye.

Fuentes

Documentación oficial y material de la comunidad consultados para esta guía. Fecha de consulta: 28 de julio de 2026.

Aportes de la comunidad Underc0de

  1. Underc0de, foro. Sección GNU/Linux. Consultas sobre contenedores, servidores y despliegue.
  2. Underc0de, foro. Sección Programación. Empaquetado y entrega de aplicaciones.

Documentación oficial

  1. Docker. Get started. La introducción oficial a imágenes y contenedores.
  2. Docker. Dockerfile reference. Todas las instrucciones para construir una imagen.
  3. Docker. Volumes. Cómo persistir datos fuera del contenedor.
  4. Open Container Initiative. OCI. El estándar abierto de imágenes y runtime de contenedores.