Conceptos clave de Docker
Las piezas de Docker y cómo se conectan: imagen, contenedor, puertos, redes y volúmenes. Si recién empezás, hacé antes la guía Empezar desde cero; esta página explica el porqué de lo que hiciste ahí.
Términos de esta página
Definiciones cortas para tener a mano. Cada una se desarrolla abajo.
- Imagen
- Plantilla de solo lectura con un sistema base, las dependencias y tu app. No “corre”: es lo que se usa para crear contenedores.
- Contenedor
- Una imagen en ejecución: un proceso aislado con sus propios archivos, red y procesos. De una imagen se pueden crear muchos contenedores.
- Dockerfile
- Archivo de texto con los pasos para construir una imagen propia.
- Registry
- Un servidor que guarda imágenes. Docker Hub es el público por defecto.
- Tag
- La versión de una imagen: en
node:18,18es el tag. Sin tag, Docker usalatest. - ID
- Identificador único de un contenedor o imagen (un código largo). Para los comandos alcanza con los primeros caracteres o con el nombre.
- Puerto
- El número por el que un programa recibe conexiones de red. Mapear un puerto conecta uno de tu PC con uno del contenedor.
- Red (network)
- Una red virtual que conecta contenedores para que se hablen entre sí por nombre.
- Volumen
- Almacenamiento que vive fuera del contenedor, para que los datos no se pierdan al borrarlo.
- Bind mount
- Mostrar una carpeta de tu PC dentro del contenedor. Los cambios se ven de los dos lados al instante.
- Build context
- La carpeta que le pasás a
docker build; el Dockerfile solo puede copiar archivos que estén dentro de ella. - Docker Compose
- Una herramienta para definir y levantar varios contenedores juntos desde un archivo YAML.
El flujo general
De una receta (o de Docker Hub) a un proceso corriendo.
Hay dos formas de conseguir una imagen: descargarla ya hecha de Docker Hub (docker pull), como mongo o nginx, o construirla vos con un Dockerfile (docker build), que es lo que hacés con tu propia app.
Con una imagen creás un contenedor (docker create) y lo arrancás (docker start). Como casi siempre se hacen esos pasos juntos, existe docker run, que descarga si hace falta, crea y arranca de una sola vez. La relación es como la de un instalador y el programa instalado: de una misma imagen podés crear muchos contenedores independientes.
Glosario rápido
Una línea para cada concepto.
Imagen
Plantilla inmutable con SO base + dependencias + tu código. Se identifica como nombre:tag.
node:18,mongo:latest,miapp:1- Sin tag ⇒ se asume
:latest
Contenedor
Una instancia en ejecución de una imagen. Tiene su propio sistema de archivos, red y procesos.
- Se referencia por ID (alcanzan los primeros caracteres) o por nombre
- Si lo borrás, se pierde lo que no esté en un volumen
Dockerfile
Receta paso a paso para construir una imagen propia (FROM, COPY, RUN, CMD…).
- Se usa con
docker build
docker-compose.yml
Define varios contenedores juntos: cómo se construyen, puertos, variables, volúmenes y redes.
- Se usa con
docker compose up/down
Network
Permite que los contenedores se vean entre sí usando su nombre como hostname.
- Compose crea una red automáticamente para todos sus servicios
Volume
Almacenamiento que sobrevive al contenedor. Ideal para datos de bases de datos.
- Nombrado:
mongo-data:/data/db - Bind mount:
.:/home/app(carpeta de tu PC)
Mapeo de puertos
Expone un puerto del contenedor en tu PC: -p HOST:CONTENEDOR.
-p 8080:3000⇒ abríslocalhost:8080, la app escucha en 3000
Registry / Docker Hub
Servidor donde viven las imágenes. docker pull baja de ahí; docker push sube.
Build context
La carpeta que le pasás a docker build (el . final). COPY solo puede leer archivos dentro de esa carpeta.
Ciclo de vida de un contenedor
Qué comando lo lleva de un estado a otro.
Un contenedor pasa por estados, igual que un programa que abrís y cerrás. Recién creado está created (existe pero no hace nada); al arrancarlo pasa a running; si lo detenés o el programa termina, queda exited, que es como “apagado pero guardado”: conserva sus archivos internos y se puede volver a arrancar. Recién con docker rm desaparece del todo.
Clave: un contenedor vive mientras vive su proceso principal (el comando del CMD). Si ese programa termina o se cae, el contenedor pasa a exited.
Ojo: docker stop detiene el contenedor (envía SIGTERM, el proceso termina). Para pausar de verdad existe docker pause. Un contenedor detenido sigue existiendo hasta que hacés docker rm.
Mapeo de puertos
-p HOST:CONTENEDOR — siempre primero tu PC, después el contenedor.
Un contenedor tiene su propia red aislada: aunque tu app escuche en el puerto 3000 adentro, desde tu PC no se puede entrar hasta que “abrís una puerta”. Eso es el mapeo de puertos: -p 3000:3000 dice “lo que llegue al puerto 3000 de mi PC, mandalo al puerto 3000 del contenedor”.
El número de la izquierda lo elegís vos (tiene que estar libre en tu PC); el de la derecha es donde realmente escucha la app.
-p 8080:3000 ⇒ entrás por localhost:8080 y llega al 3000 del contenedor.
EXPOSE 3000 en el Dockerfile es solo informativo: no publica nada. Quien publica es -p o ports:.
Entre contenedores de la misma red no hace falta mapear puertos: se hablan directo por el puerto interno.
Redes: cómo se habla la app con la base de datos
En una misma red, el nombre del contenedor/servicio funciona como hostname.
Cuando tu app necesita conectarse a una base de datos que corre en otro contenedor, no puede usar localhost: para un contenedor, localhost es él mismo. La solución es poner los dos contenedores en la misma red de Docker. Dentro de esa red, cada contenedor se encuentra por su nombre, como si fuera una dirección web: el contenedor monguito es accesible en monguito:27017.
El hostname es el nombre de una máquina en la red; Docker hace que el nombre de cada contenedor funcione como hostname gracias a un DNS interno (un “directorio” que traduce nombres a direcciones).
Volúmenes: persistir y compartir archivos
Dos sabores con la misma sintaxis ORIGEN:DESTINO-EN-CONTENEDOR.
Todo lo que un contenedor escribe adentro se pierde cuando lo borrás. Para una base de datos eso es un problema: cada vez que recreás el contenedor, perdés los datos. Un volumen es una carpeta que vive fuera del contenedor y se “monta” en una ruta de adentro: el contenedor escribe ahí como siempre, pero los datos quedan guardados aunque lo borres y crees otro.
Persistir significa justamente eso: que los datos sobrevivan. Hay dos tipos: el volumen nombrado, que administra Docker (ideal para datos), y el bind mount, que es una carpeta de tu PC (ideal para ver tu código en vivo mientras desarrollás).
Volumen nombrado
Docker lo gestiona. Sobrevive a docker rm y a docker compose down.
Bind mount (carpeta de tu PC)
Tu carpeta se “ve” dentro del contenedor. Ideal para desarrollo: editás y el cambio está al instante.
¿Dónde guarda los datos cada base de datos?
La ruta de destino del volumen tiene que ser exactamente esta, si no los datos se pierden al recrear el contenedor.
| Motor | Ruta dentro del contenedor | Ejemplo en compose |
|---|---|---|
| MongoDB | /data/db | - mongo-data:/data/db |
| MySQL / MariaDB | /var/lib/mysql | - mysql-data:/var/lib/mysql |
| PostgreSQL | /var/lib/postgresql/data | - pg-data:/var/lib/postgresql/data |
| SQL Server | /var/opt/mssql | - mssql-data:/var/opt/mssql |
| Redis | /data | - redis-data:/data |
¿Qué va en el Dockerfile y qué en el compose?
Están separados a propósito.
Cómo se construye UNA imagen
- Imagen base (
FROM) - Copiar código, instalar dependencias, compilar
- Qué comando arranca la app (
CMD/ENTRYPOINT) - Es reusable solo:
docker build -t miapp . - No sabe de puertos externos, variables de entorno ni de otros contenedores
Cómo se orquestan VARIOS contenedores
- Qué servicios hay (app, db, migrator, frontend…)
build(context + dockerfile) oimageports,environment,volumes,depends_on- La red común para que se hablen por nombre
- Todo se levanta con
docker compose up