En esta lección daremos un salto cualitativo respecto a lo que vimos en el módulo anterior sobre redes básicas. Ahora analizaremos en profundidad los distintos drivers de red, entenderemos por qué las redes definidas por el usuario son superiores a la red bridge por defecto, exploraremos la resolución DNS interna entre contenedores, distinguiremos claramente entre publicar y exponer puertos, y aprenderemos a inspeccionar y resolver problemas de red. Dominar estos conceptos es esencial para construir arquitecturas de microservicios robustas, seguras y mantenibles.

Los Drivers de Red en Detalle

Docker utiliza un sistema de drivers (controladores) para implementar los distintos tipos de red. Cada driver responde a un caso de uso concreto. Conocer sus diferencias te permite elegir la opción correcta en cada situación.

Driver Alcance Caso de uso principal Aislamiento DNS interno
bridge Un solo host Aplicaciones multi-contenedor en una sola máquina Alto Sí (en redes definidas por el usuario)
host Un solo host Máximo rendimiento de red, sin capa de NAT Ninguno No aplica
overlay Múltiples hosts Servicios distribuidos en Swarm o clústeres Alto
macvlan Un solo host El contenedor aparece como un dispositivo físico en la LAN Medio Limitado
none Un solo host Contenedores totalmente aislados sin red Máximo No

Driver bridge

Es el driver predeterminado. Crea una red interna privada en el host mediante un puente virtual de Linux (docker0 para la red por defecto). Los contenedores conectados reciben una IP de un rango privado y se comunican entre sí a través de ese puente.

# Crear una red bridge definida por el usuario
docker network create --driver bridge mi_red_app
  • docker network create: comando para crear una red.
  • --driver bridge: especifica el driver. Aunque bridge es el valor por defecto, indicarlo de forma explícita mejora la legibilidad.
  • mi_red_app: nombre de la red.

Driver host

Elimina el aislamiento de red entre el contenedor y el host: el contenedor utiliza directamente la pila de red del anfitrión.

docker run -d --name servidor_web --network host nginx
  • --network host: el contenedor comparte la red del host. Si Nginx escucha en el puerto 80, lo hará directamente sobre el puerto 80 del host, sin necesidad de -p.

Ventaja: rendimiento máximo (no hay NAT ni traducción de puertos). Desventaja: pierdes el aislamiento y dos contenedores no pueden usar el mismo puerto.

Driver overlay

Permite que contenedores ubicados en hosts diferentes se comuniquen como si estuvieran en la misma red local. Es la base de Docker Swarm.

# Requiere un nodo en modo Swarm
docker swarm init
docker network create --driver overlay --attachable mi_red_overlay
  • docker swarm init: inicializa el modo Swarm en el nodo actual.
  • --attachable: permite que contenedores independientes (no solo servicios de Swarm) se conecten a la red.

Driver macvlan

Asigna a cada contenedor una dirección MAC propia, haciéndolo visible en la red física como si fuera un equipo más.

docker network create -d macvlan \
  --subnet=192.168.10.0/24 \
  --gateway=192.168.10.1 \
  -o parent=eth0 \
  mi_red_macvlan
  • --subnet y --gateway: definen el rango de IP y la puerta de enlace de la red física.
  • -o parent=eth0: indica la interfaz física del host a la que se asocia. Sustituye eth0 por el nombre real de tu interfaz.

Driver none

Desactiva por completo la red del contenedor. Solo tendrá la interfaz de loopback (lo). Útil para procesos por lotes que no requieren conectividad.

docker run -d --name proceso_aislado --network none alpine sleep 3600

Redes Definidas por el Usuario vs. la Red Bridge por Defecto

Cuando ejecutas un contenedor sin especificar red, este se conecta a la red bridge por defecto llamada bridge. Sin embargo, esta red tiene limitaciones importantes y no se recomienda para producción.

Característica Bridge por defecto Bridge definida por el usuario
Resolución DNS por nombre No (solo por IP) Sí (por nombre de contenedor)
Aislamiento entre aplicaciones Todos comparten la red Cada red está aislada
Conexión/desconexión en caliente Limitada Total
Configuración personalizada (subred, gateway) No

La diferencia más importante es la resolución DNS automática. En una red definida por el usuario, los contenedores pueden encontrarse por su nombre; en la red bridge por defecto, solo por IP, lo cual es frágil porque las IP cambian.

# Crear la red y conectar dos contenedores
docker network create tienda_red
docker run -d --name api --network tienda_red node:18-alpine
docker run -d --name frontend --network tienda_red nginx

Ahora el contenedor frontend puede contactar con api simplemente usando el nombre api como nombre de host.

Resolución DNS Interna entre Contenedores

Docker incorpora un servidor DNS embebido (accesible en la IP 127.0.0.11 dentro de cada contenedor) que resuelve automáticamente los nombres de los contenedores conectados a la misma red definida por el usuario.

# Verificar la resolución DNS desde frontend hacia api
docker exec -it frontend ping api
  • Docker traduce el nombre api a la IP interna del contenedor correspondiente.
  • Esto funciona sin que tengas que editar ficheros como /etc/hosts manualmente.

También puedes asignar alias de red adicionales:

docker run -d --name api --network tienda_red \
  --network-alias servicio-pedidos node:18-alpine
  • --network-alias servicio-pedidos: además de api, el contenedor también responderá al nombre servicio-pedidos dentro de la red.

Publicación de Puertos: -p vs. --expose

Es habitual confundir estas dos opciones, pero hacen cosas muy distintas.

Opción Qué hace ¿Accesible desde el host?
-p Publica un puerto del contenedor en el host (crea regla de NAT)
--expose Documenta/declara que el contenedor escucha en un puerto No (solo a otros contenedores)

Publicar puertos con -p

docker run -d --name web -p 8080:80 nginx
  • 8080:80: mapea el puerto 8080 del host al puerto 80 del contenedor.
  • Desde tu navegador podrás acceder a http://localhost:8080.

Puedes limitar la exposición a una interfaz concreta del host por seguridad:

docker run -d --name web -p 127.0.0.1:8080:80 nginx
  • 127.0.0.1:8080:80: el puerto solo será accesible desde el propio host (localhost), no desde la red externa.

Declarar puertos con --expose

docker run -d --name api --network tienda_red --expose 3000 node:18-alpine
  • --expose 3000: indica que el contenedor escucha en el puerto 3000. Otros contenedores de la misma red podrán acceder a api:3000, pero el puerto no se publica en el host.

Comunicación entre Contenedores y Aislamiento de Red

Cada red definida por el usuario es un dominio de aislamiento. Dos contenedores en redes distintas no se ven entre sí, salvo que conectes uno de ellos a ambas redes.

# Crear dos redes aisladas
docker network create red_frontend
docker network create red_backend

# La base de datos solo en la red backend (aislada del exterior)
docker run -d --name db --network red_backend postgres:16

# La API conectada a ambas redes para actuar de puente
docker run -d --name api --network red_backend node:18-alpine
docker network connect red_frontend api

# El frontend solo en la red frontend
docker run -d --name web --network red_frontend nginx
  • La base de datos db queda aislada: solo la api puede alcanzarla.
  • docker network connect red_frontend api: conecta el contenedor api también a la red frontend, permitiéndole comunicarse con web.
  • Este patrón implementa el principio de mínima exposición: la base de datos nunca queda accesible desde la red del frontend.

Inspección y Troubleshooting de Redes

Cuando algo no funciona, estos comandos son tus mejores aliados.

Inspeccionar una red

docker network inspect tienda_red
  • Muestra la subred, la puerta de enlace y, lo más útil, la lista de contenedores conectados con sus IP. Ideal para confirmar que un contenedor está realmente en la red que crees.

Ver las redes de un contenedor

docker inspect -f '{{json .NetworkSettings.Networks}}' api
  • -f '{{json ...}}': aplica una plantilla de formato Go para extraer solo la sección de redes en formato JSON.

Diagnóstico desde dentro del contenedor

# Instalar herramientas de red en una imagen Alpine
docker exec -it api sh -c "apk add --no-cache iputils bind-tools"

# Comprobar conectividad
docker exec -it api ping -c 3 db

# Comprobar resolución DNS
docker exec -it api nslookup db
  • ping -c 3 db: envía 3 paquetes a db para verificar conectividad de capa 3.
  • nslookup db: confirma que el DNS interno resuelve el nombre a una IP.

Limpiar redes sin uso

docker network prune
  • Elimina todas las redes que no tengan ningún contenedor conectado. Muy útil para mantener limpio el entorno.

Errores Comunes y Consejos

  • Usar la red bridge por defecto en producción: pierdes el DNS por nombre. Crea siempre redes definidas por el usuario.
  • Confundir -p con --expose: si no puedes acceder desde el navegador, probablemente usaste --expose en lugar de -p.
  • Olvidar que los nombres deben estar en la misma red: el DNS interno solo resuelve nombres de contenedores conectados a la misma red definida por el usuario.
  • Conflictos de subred: al crear redes con --subnet, evita rangos que solapen con tu red física para no provocar problemas de enrutamiento.
  • Asumir que localhost dentro del contenedor es el host: dentro de un contenedor, localhost se refiere al propio contenedor, no a la máquina anfitriona.
  • Consejo: nombra tus redes de forma descriptiva (red_backend, red_pagos) para que la topología sea autoexplicativa.

Ejercicios

Ejercicio 1: Aislamiento de tres capas

Crea una arquitectura de tres capas (web, api, base de datos) donde la base de datos solo sea accesible por la api, y la web solo pueda hablar con la api. Verifica que la web NO puede alcanzar la base de datos.

Ejercicio 2: Resolución DNS y alias

Crea una red definida por el usuario, lanza un contenedor llamado cache con el alias redis-server, y desde otro contenedor comprueba que ambos nombres resuelven correctamente.

Ejercicio 3: Diferencia entre publicar y exponer

Lanza dos contenedores Nginx: uno con -p 8081:80 y otro con --expose 80. Comprueba a cuál puedes acceder desde el navegador del host y razona por qué.

Soluciones

Solución 1

docker network create red_frontend
docker network create red_backend

docker run -d --name db --network red_backend postgres:16
docker run -d --name api --network red_backend node:18-alpine
docker network connect red_frontend api
docker run -d --name web --network red_frontend nginx

# La web NO debe poder resolver ni alcanzar db
docker exec -it web ping -c 2 db   # Debe fallar (host desconocido)
# La api SÍ alcanza db
docker exec -it api ping -c 2 db   # Debe funcionar

La web no encuentra a db porque ambos están en redes distintas y no comparten dominio DNS.

Solución 2

docker network create red_app
docker run -d --name cache --network red_app --network-alias redis-server redis:7-alpine
docker run -d --name worker --network red_app alpine sleep 3600

docker exec -it worker sh -c "apk add --no-cache bind-tools && nslookup cache && nslookup redis-server"

Ambos nombres resuelven a la misma IP del contenedor cache.

Solución 3

docker run -d --name publicado -p 8081:80 nginx
docker run -d --name expuesto --expose 80 nginx

Solo http://localhost:8081 responde. El contenedor expuesto no publica ningún puerto en el host; --expose únicamente declara el puerto para la comunicación entre contenedores de la misma red.

Conclusión

En esta lección hemos profundizado en el sistema de redes de Docker: los distintos drivers y cuándo usar cada uno, la superioridad de las redes definidas por el usuario gracias al DNS interno, la diferencia crítica entre publicar (-p) y exponer (--expose) puertos, los patrones de aislamiento entre capas y las herramientas para diagnosticar problemas. Estas técnicas son la base de cualquier arquitectura distribuida segura.

En la siguiente lección, Opciones de Almacenamiento Docker, exploraremos en profundidad cómo gestionar los datos: las diferencias entre volúmenes, bind mounts y tmpfs, los storage drivers y las estrategias de copia de seguridad y restauración.

© Copyright 2026. Todos los derechos reservados