Tabla de Contenidos

02 - Docker

Los proyectos no viven solo del código: alrededor hay una base de datos, un almacenamiento de ficheros, un proxy… Cada pieza es un servidor ajeno, con su instalación y su configuración. Docker permite empaquetar cada pieza con todo lo que necesita y ejecutarla aislada y reproducible, en cualquier máquina y sin instalar nada más.

1. Entornos que no coinciden

Instalar y configurar cada servidor a mano tiene dos problemas: el trabajo no se traslada (lo que funciona en una máquina no va igual en otra: versiones y configuraciones distintas) y las piezas comparten el sistema, así que una actualización toca a todas. Docker resuelve ambos: cada servidor se empaqueta en una imagen con su versión exacta y corre en un contenedor aislado del resto.

2. Imagen, contenedor y registro

Concepto Qué es
Imagen Plantilla inmutable con el sistema de ficheros y el comando de arranque; tiene una versión (*tag*)
Contenedor Proceso aislado en ejecución, creado a partir de una imagen
Registro Repositorio de imágenes; Docker Hub es el público más usado

La imagen es la plantilla; el contenedor, la instancia. De una imagen salen tantos contenedores como se quieran.

Máquina virtual Contenedor
Qué incluye SO invitado completo + aplicación Solo la aplicación y sus dependencias
Arranque Minutos (arranca un SO) Milisegundos (es un proceso)
Coste Gigabytes por VM Megabytes; comparte el kernel del host

Ambos aíslan; el contenedor comparte el kernel del host y por eso es tan ligero. Para servidores de aplicación es el enfoque dominante.

Los nombres de imagen siguen el patrón usuario/imagen:tag: usuario identifica al publicador y es opcional —si falta, la imagen es oficial—; imagen es obligatorio; tag señala la versión y también es opcional. Sin tag se descarga latest, que no siempre es la más nueva: es la versión que los creadores etiquetaron como tal. Fijar la versión (mariadb:11, no mariadb) es lo reproducible.

3. Imágenes

Docker Hub es el registro público: en la web se busca y se distinguen las imágenes oficiales. En una terminal sin entorno gráfico, lo mismo lo hace docker search.

Comando Qué hace
docker search <imagen> busca imágenes con ese nombre en el registro
docker pull <imagen> descarga la imagen
docker images lista las imágenes del sistema local
docker rmi <imagen> elimina una imagen local, por REPOSITORY:TAG o IMAGE ID
docker tag crea un alias de una imagen existente
docker save / docker load exporta o importa imágenes en un fichero .tar, sin registro

$ docker search mariadb
$ docker pull mariadb:11
$ docker images
$ docker rmi mariadb:11

4. Contenedores

docker run crea y arranca un contenedor desde una imagen; si no está en local, la descarga antes. Sus opciones completan la configuración del contenedor en el momento de crearlo:

Opción Efecto
-d en segundo plano (*detached*), sin ocupar la terminal
-p host:contenedor publica el puerto del contenedor en el host
–name nombre para referirse al contenedor sin depender del ID
-e VAR=valor variable de entorno: así se configura el servidor (contraseñas, rutas…)
-v volumen:ruta guarda datos fuera del contenedor (sección 5)
–restart always lo vuelve a arrancar si el contenedor o la máquina se reinician

$ docker run -d -p 8080:80 nginx                       # un servidor web en el 8080 del host
$ docker run -d --name db \
    -e MARIADB_ROOT_PASSWORD=secreto \
    -p 3306:3306 mariadb:11

El contenedor se para y se arranca sin perderse; se elimina y ya no hay nada:

$ docker ps                    # contenedores en ejecución (con -a, también los parados)
$ docker stop db               # lo detiene
$ docker start db              # lo vuelve a arrancar: el mismo contenedor, con lo que tiene dentro
$ docker logs -f db            # sigue la salida del contenedor
$ docker rm db                 # lo elimina (con -f también si está en marcha)

docker exec ejecuta comandos en un contenedor en marcha, sin detenerlo:

$ docker exec -it db bash      # una terminal dentro del contenedor (para salir, exit)
$ docker exec db ls /app       # un comando suelto, sin terminal

5. Puertos y volúmenes

Puertos: -p 9000:9000 conecta el puerto del host con el del contenedor. Sin él, el servicio no es accesible desde fuera; entre contenedores no hace falta: se ven por la red interna (tema 08).

Volúmenes: el sistema de ficheros del contenedor es efímero: al eliminar el contenedor se pierde lo que guardó dentro. Un volumen vive fuera del contenedor y persiste:

$ docker run -d --name db -v db-data:/var/lib/mysql mariadb:11

Los datos de MariaDB quedan en el volumen db-data y sobreviven al contenedor.

Forma Sintaxis Cuándo usarla
Volumen nombrado -v db-data:/var/lib/mysql datos que deben sobrevivir al contenedor; los gestiona Docker y no los liga a una ruta del host
Bind mount -v ./html:/usr/share/nginx/html trabajar con una carpeta concreta de la máquina: el host es dueño de los ficheros

$ docker volume create db-data     # crear el volumen por adelantado
$ docker volume inspect db-data    # sus datos: el Mountpoint es la carpeta real del host

6. Dockerfile

Los servidores oficiales ya vienen empaquetados; la aplicación propia se define en un Dockerfile: un fichero de texto que describe cómo se construye una imagen —de qué parte, qué añade y con qué comando arranca.

Instrucción Qué hace
FROM imagen base de la que se parte; toda imagen empieza aquí
RUN ejecuta un comando durante la construcción (instalar paquetes…)
COPY / ADD copia ficheros del host a la imagen (ADD admite URLs y descomprime)
WORKDIR directorio de trabajo para las siguientes instrucciones
ENV variables de entorno fijas de la imagen
EXPOSE documenta el puerto que usa la aplicación; no lo publica (eso lo hace -p)
CMD comando por defecto al arrancar el contenedor; se puede sobreescribir
ENTRYPOINT el programa principal, fijo; lo que se añade en docker run son sus argumentos

FROM python:3
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]

$ docker build -t miapp:1.0 .      # construye la imagen desde este directorio
$ docker run miapp:1.0

La forma no cambia aunque crezca lo que hay que instalar: el Dockerfile es la lista de pasos —base, añadidos, arranque— que sustituye a toda la instalación manual del servidor.

7. Redes

Cada contenedor nace aislado en su propia red. Para que dos contenedores se vean, comparten una red: un conmutador virtual —de tipo bridge por defecto— donde se alcanzan por el nombre del contenedor, como un hostname.

$ docker network create mi-red
$ docker run -d --name db --network mi-red mariadb:11
$ docker run -d --name app --network mi-red alpine
$ docker exec app ping db          # db responde a su nombre: la red los une

Comando Qué hace
network create crea la red (bridge por defecto)
network connect / disconnect añade o retira un contenedor en marcha a/de la red
network ls lista las redes
network inspect detalle de la red: driver, contenedores conectados y sus IP
network rm elimina la red, sin contenedores conectados

8. docker compose

Con varios contenedores, los comandos manuales no escalan: hay que recordar orden, puertos y variables de cada uno. Docker Compose describe el sistema completo —servicios, redes y volúmenes— en un fichero compose.yaml y lo levanta con un solo comando:

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html

  db:
    image: mariadb:11
    environment:
      MARIADB_ROOT_PASSWORD: secreto
      MARIADB_DATABASE: miapp
    volumes:
      - db-data:/var/lib/mysql

volumes:
  db-data:

Comando Qué hace
docker compose up -d crea, si faltan, y arranca todos los servicios, en segundo plano
docker compose start / stop arranca o para los contenedores existentes, sin eliminarlos
docker compose ps estado de los servicios
docker compose logs -f la salida de todos, ordenada por servicio
docker compose down para y elimina contenedores y red; con -v, también los volúmenes
docker compose down elimina contenedores pero conserva los volúmenes nombrados: los datos sobreviven. Es el modo normal de reiniciar el sistema; -v solo si se quieren borrar de verdad.

Con un solo servicio Compose parece excesivo; su valor aparece al describir sistemas con varios servidores: es el caso del tema de arquitectura (tema 08).