En el artículo anterior aprendimos a conectar un contenedor con el “mundo exterior” usando puertos (-p). Pero, ¿qué pasa cuando queremos conectar dos contenedores entre sí?
Imagina el escenario más clásico del desarrollo web:
- Un contenedor con tu Aplicación (Node.js, PHP, Python…).
- Un contenedor con tu Base de Datos (MySQL, Mongo…).
Tu aplicación necesita la dirección de la base de datos para conectarse. Al hacer un docker inspect, ves que la base de datos tiene la IP 172.17.0.2. La pones en tu código, despliegas y funciona.
Al día siguiente, reinicias el ordenador, arrancas Docker y… todo roto 💥. La base de datos ahora tiene la IP 172.17.0.3 porque arrancó en distinto orden.
Las IPs en Docker son efímeras y dinámicas. Nunca, bajo ningún concepto, debes confiar en ellas.
La solución es usar nombres en lugar de números. Y para eso, necesitamos crear nuestra propia red.
La Red “Default” vs “User-Defined”
Docker viene con una red por defecto llamada bridge (la que usa si no especificas nada). Sin embargo, la red por defecto NO tiene resolución de nombres (DNS) automática.
Para que los contenedores puedan llamarse por su nombre (ej: ping base-datos), necesitamos crear una User-Defined Bridge Network (una red puente definida por el usuario).
Al hacerlo, Docker activa un Servidor DNS interno. Si un contenedor intenta conectar con http://mi-base-datos, Docker intercepta la llamada, busca qué IP tiene ese contenedor en ese momento y la resuelve automáticamente.
Paso 1: Crear una red propia
Crear una red es tan sencillo como ponerle un nombre. Vamos a crear una red para nuestro proyecto:
docker network create mi-red-app
Si listamos las redes, veremos la nuestra nueva:
docker network ls
Paso 2: Conectar contenedores a esa red
Ahora vamos a lanzar dos contenedores, pero les diremos explícitamente que se conecten a mi-red-app usando el flag --network.
Importante: Debemos usar el flag --name, porque ese nombre será el dominio que usaremos para encontrarlos.
Vamos a usar un Nginx, pero imaginemos que es una base de datos a la que llamaremos servidor-bd.
docker run -d --name servidor-bd --network mi-red-app nginx
Fíjate que no hace falta publicar puertos (-p). Como la comunicación va a ser interna (entre contenedores de la misma red), no necesitamos exponer nada al exterior. El puerto 80 es accesible por sus “vecinos” de red.
Ahora vamos a lanzar un contenedor ligero (Alpine) para hacer pruebas de conexión. Lo llamaremos mi-app.
docker run -it --name mi-app --network mi-red-app alpine /bin/sh
Paso 3: El DNS interno
Ahora estamos dentro de la terminal de mi-app (el contenedor Alpine). Vamos a intentar conectar con el otro contenedor.
Si hacemos ping a la IP, funcionaría, pero hemos dicho que eso está prohibido. Vamos a hacer ping al nombre del contenedor:
/ # ping servidor-bd
Verás una respuesta:
PING servidor-bd (172.18.0.2): 56 data bytes 64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.098 ms 64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.102 ms
¡Funciona! Docker ha resuelto que servidor-bd corresponde a 172.18.0.2.
Si mañana reinicias Docker y servidor-bd obtiene la IP 172.18.0.55, tu ping seguirá funcionando igual, porque Docker actualizará el registro DNS automáticamente.
Esta es la razón por la que en los archivos de configuración de tus aplicaciones, en el campo “Database Host”, pondrás el nombre del contenedor (ej: mysql-container) y no localhost ni una IP.
