Interconexión de contenedores Docker: cómo hacer que los contenedores web y de base de datos se comuniquen correctamente

El viernes a las 3 de la tarde, estaba a punto de containerizar mi entorno de desarrollo local y me sentía bastante orgulloso: el contenedor MySQL arrancó bien, el contenedor Node.js también estaba en marcha, solo faltaba el último paso para conectarlos. Actualicé la página en el navegador y, de golpe, error 500; en los logs, un montón de «Connection refused».
Me quedé bloqueado: los dos contenedores estaban en ejecución, ¿no? Probé a hacer ping al nombre del contenedor MySQL y obtuve «unknown host». Bueno, probé con la dirección IP y ¡funcionó! La aplicación también conectó a la base de datos. Respiré aliviado, hice commit, apagué y me fui.
El lunes volví y llegó la tragedia: la aplicación volvió a caerse. Al investigar, resultó que el contenedor MySQL se había reiniciado y la IP cambió de 172.17.0.2 a 172.17.0.3. En ese momento me sentí realmente frustrado: ¿tengo que cambiar la configuración cada vez que reinicio un contenedor?
Si tú también has pasado por algo parecido, este artículo es para ti. Pasé una tarde estudiando el mecanismo de red de Docker y por fin entendí la forma correcta de interconectar contenedores. A continuación comparto contigo:
- Por qué el nombre del contenedor no responde al ping y cuál es la causa raíz
- Qué limitaciones tiene la red predeterminada de Docker
- Cómo las redes personalizadas resuelven estos problemas
- Los pasos completos para que tus contenedores se comuniquen por nombre
- Algunas técnicas avanzadas y buenas prácticas
¿Por qué el nombre del contenedor no responde al ping?
Limitaciones de la red predeterminada de Docker
La causa raíz está en la configuración de red predeterminada de Docker. Cuando inicias un contenedor sin especificar una red, Docker lo conecta automáticamente a la red bridge predeterminada, es decir, al puente docker0.
Esta red predeterminada tiene una limitación importante: solo permite comunicación por dirección IP, no resuelve nombres de contenedor.
¿Qué significa? En la red predeterminada:
- ✅ Puedes acceder a otros contenedores por IP (por ejemplo,
ping 172.17.0.2) - ❌ No puedes acceder por nombre de contenedor (por ejemplo,
ping mysql-containerno funciona)
¿Por qué? Porque la red predeterminada no tiene DNS integrado. Puedes imaginarlo como un móvil sin agenda de contactos: solo recuerdas el número (IP), pero no puedes encontrar a alguien por su nombre (nombre del contenedor).
Peor aún, cada vez que reinicias un contenedor, Docker reasigna la dirección IP. Hoy puedes conectar a MySQL con 172.17.0.2; mañana, tras un reinicio, puede ser 172.17.0.3 y la IP en la configuración de tu aplicación deja de servir.
Lo comprobé con comandos:
# Iniciar un contenedor MySQL (red predeterminada)
docker run -d --name mysql-demo \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:8.0
# Iniciar un contenedor busybox para probar la red
docker run -it --name test-box busybox sh
# Dentro de test-box, intentar ping al nombre del contenedor MySQL
/ # ping mysql-demo
ping: bad address 'mysql-demo' # ← resolución fallida
# Ver la IP del contenedor MySQL
docker inspect mysql-demo | grep IPAddress
# "IPAddress": "172.17.0.2"
# Con la IP sí responde al ping
/ # ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.123 ms
Como ves, con el nombre del contenedor no responde al ping; solo funciona con la IP.
El parámetro —link está obsoleto
Es posible que en tutoriales antiguos hayas visto el parámetro --link, la solución temprana de Docker. Se usaba así:
docker run --link mysql-demo:mysql -d my-app
Así, my-app podía acceder a mysql-demo mediante el nombre «mysql». Pero Docker ha dejado de recomendar —link y lo eliminará en versiones futuras.
¿Por qué se abandonó? Principalmente por:
- Conexión unidireccional: solo my-app puede acceder a mysql, no al revés
- Difícil de mantener: con muchos contenedores, la configuración de —link se complica
- Funcionalidad limitada: no admite una gestión de red flexible en escenarios con múltiples contenedores
Si aún usas —link, es hora de migrar al método nuevo.
Red personalizada: la forma correcta de interconectar contenedores
Ventajas de las redes personalizadas
Desde Docker 1.12, el comando docker network permite crear redes personalizadas. Es la forma recomendada oficialmente para la interconexión de contenedores.
Una red bridge personalizada frente a la predeterminada ofrece:
-
Resolución DNS automática: Docker ejecuta un servidor DNS integrado en la red personalizada; el nombre del contenedor se resuelve a su IP. Es como añadir una «agenda de contactos» a la red.
-
Aislamiento de red: los contenedores en redes personalizadas distintas están aislados por defecto. Puedes colocar frontend, backend y base de datos en redes separadas para mayor seguridad.
-
Mejor mantenibilidad: aunque la IP cambie tras un reinicio, usas el nombre del contenedor y el DNS actualiza el registro automáticamente.
-
Soporte multi-red: un contenedor puede unirse a varias redes para topologías más complejas.
Al principio yo también pensaba que la red de Docker era complicada, pero al entender estos puntos todo encajó.
Crear una red personalizada
El comando es muy sencillo:
# Forma más simple: solo el nombre de la red
docker network create my-app-net
# Versión con parámetros completos
docker network create \
--driver bridge \ # Tipo de driver; bridge por defecto
--subnet 172.20.0.0/16 \ # Rango IP personalizado (opcional)
--gateway 172.20.0.1 \ # Puerta de enlace personalizada (opcional)
my-app-net # Nombre de la red
Para la mayoría de escenarios, la primera opción basta. Docker asigna automáticamente un rango IP sin conflictos.
Tras crearla, puedes ver los detalles con:
docker network inspect my-app-net
Verás la configuración de la red: rango IP, puerta de enlace, contenedores conectados, etc.
Unir contenedores a la red personalizada
Hay dos formas:
Opción 1: especificar al iniciar (recomendado)
docker run -d \
--name mysql-demo \
--network my-app-net \ # ← parámetro clave
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:8.0
Opción 2: conectar un contenedor ya en ejecución
# Suponiendo que el contenedor ya está corriendo
docker network connect my-app-net existing-container
La primera es más directa. La segunda sirve para migrar contenedores existentes a una red nueva.
Caso práctico: aplicación web accediendo a MySQL
Basta de teoría; vamos a la práctica. Demostraré un escenario real: un contenedor Node.js conectándose a un contenedor MySQL.
Escenario
Objetivos:
- Contenedor MySQL llamado
mysql-server, en una red personalizada - Contenedor Node.js llamado
node-app, en la misma red - La aplicación conecta por nombre «mysql-server», no por IP
Pasos completos
Paso 1: crear la red personalizada
docker network create my-app-net
Deberías ver un ID de red, por ejemplo:
a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890
Eso confirma que la red se creó correctamente.
Paso 2: iniciar MySQL y unirlo a la red
docker run -d \
--name mysql-server \
--network my-app-net \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-e MYSQL_DATABASE=myapp_db \
mysql:8.0
Parámetros:
--name mysql-server: nombre del contenedor; es el host para acceder a la base de datos--network my-app-net: conexión a la red que acabamos de crear-e MYSQL_ROOT_PASSWORD: contraseña root-e MYSQL_DATABASE: base de datos inicial
Paso 3: iniciar la aplicación y unirla a la red
Ejemplo sencillo con Node.js; adapta según tu caso:
docker run -d \
--name node-app \
--network my-app-net \
-p 3000:3000 \
-e DB_HOST=mysql-server \
-e DB_USER=root \
-e DB_PASSWORD=my-secret-pw \
-e DB_NAME=myapp_db \
my-node-app:latest
Fíjate en DB_HOST=mysql-server: es el nombre del contenedor, no la IP.
Paso 4: usar el nombre del contenedor en el código
Ejemplo en Node.js:
const mysql = require('mysql2');
// Configuración de conexión con variables de entorno
const connection = mysql.createConnection({
host: process.env.DB_HOST, // valor: 'mysql-server' (nombre del contenedor)
user: process.env.DB_USER, // valor: 'root'
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
connection.connect((err) => {
if (err) {
console.error('Error de conexión a la base de datos:', err);
return;
}
console.log('¡Conexión exitosa a MySQL!');
});
Lo clave es que host usa el nombre del contenedor mysql-server; el DNS de Docker lo resuelve a la IP actual de MySQL.
Paso 5: verificar la conectividad
Entra al contenedor node-app y prueba manualmente:
# Entrar al contenedor de la aplicación
docker exec -it node-app sh
# Ping al nombre del contenedor MySQL
/ # ping mysql-server
PING mysql-server (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.089 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.096 ms
¡Funciona! El nombre se resuelve y responde al ping.
También puedes usar nslookup:
/ # nslookup mysql-server
Server: 127.0.0.11 # ← DNS integrado de Docker
Address: 127.0.0.11:53
Name: mysql-server
Address: 172.20.0.2 # ← resuelve automáticamente a la IP de MySQL
Docker ejecuta un servidor DNS (127.0.0.11) en la red personalizada que resuelve los nombres de contenedor.
Aunque reinicies MySQL y cambie la IP, la aplicación no se verá afectada porque el DNS actualiza el registro.
Técnicas de diagnóstico
Si algo falla, estos comandos suelen ayudar:
1. Ver detalles de la red
docker network inspect my-app-net
Devuelve JSON con:
- Rango IP y puerta de enlace de la red
- Lista de contenedores conectados
- IP de cada contenedor en esa red
2. Ver la configuración de red del contenedor
docker inspect mysql-server | grep -A 20 Networks
Muestra a qué redes está conectado el contenedor y su IP en cada una.
3. Revisar logs del contenedor
docker logs node-app
docker logs mysql-server
Los logs suelen incluir detalles del error de conexión.
Lista de comprobación de problemas frecuentes:
| Problema | Posible causa | Solución |
|---|---|---|
| Ping al nombre falla | Contenedores en redes distintas | Confirma con docker network inspect; conecta con docker network connect |
| Ping OK pero la app no conecta | Puerto mal configurado | Revisa el puerto en la app y el que escucha MySQL (3306 por defecto) |
| Base de datos rechaza conexión | Usuario/contraseña o permisos | Revisa variables de entorno; entra al contenedor MySQL y comprueba permisos |
| Error de resolución DNS | Probablemente red predeterminada | Crea red personalizada y reinicia los contenedores |
Técnicas avanzadas y buenas prácticas
Escenario multi-red: separación frontend/backend
En proyectos reales a veces necesitas una topología más compleja: frontend, backend y base de datos en capas de red distintas:
# Crear dos redes
docker network create frontend-net # red frontend
docker network create backend-net # red backend
# Frontend solo en frontend-net
docker run -d --name nginx \
--network frontend-net \
-p 80:80 \
nginx:latest
# API en ambas redes (frontend y backend la necesitan)
docker run -d --name api-server \
--network frontend-net \
my-api:latest
docker network connect backend-net api-server
# Base de datos solo en backend-net (frontend no accede; más seguro)
docker run -d --name postgres \
--network backend-net \
-e POSTGRES_PASSWORD=secret \
postgres:14
Ventajas de esta arquitectura:
- nginx puede acceder a api-server, pero no a la base de datos
- api-server puede acceder a la base de datos
- La base de datos queda aislada; solo el backend accede, más seguro
En nuestro proyecto de empresa desplegamos así y la seguridad mejoró bastante.
Simplificar con Docker Compose
Con muchos contenedores, gestionarlos a mano es pesado. Ahí entra Docker Compose.
Crea un archivo docker-compose.yml:
version: '3.8'
services:
# Servicio MySQL
mysql:
image: mysql:8.0
container_name: mysql-server
environment:
MYSQL_ROOT_PASSWORD: my-secret-pw
MYSQL_DATABASE: myapp_db
networks:
- app-network
volumes:
- mysql-data:/var/lib/mysql
# Servicio Node.js
app:
image: my-node-app:latest
container_name: node-app
ports:
- "3000:3000"
environment:
DB_HOST: mysql # ← usa el nombre del service, no container_name
DB_USER: root
DB_PASSWORD: my-secret-pw
DB_NAME: myapp_db
networks:
- app-network
depends_on:
- mysql
# Definir red
networks:
app-network:
driver: bridge
# Definir volúmenes
volumes:
mysql-data:
Luego un solo comando para todo:
docker-compose up -d
Docker Compose automáticamente:
- Crea la red app-network
- Inicia todos los contenedores y los conecta
- Configura la resolución DNS entre contenedores
- Respeta el orden de
depends_on(primero mysql, luego app)
Parar y limpiar también es sencillo:
# Parar todos los servicios
docker-compose down
# Parar y eliminar volúmenes
docker-compose down -v
Hoy casi no gestiono contenedores a mano; todo va con Docker Compose y la eficiencia sube mucho.
Otros modos de red
Además de bridge, Docker soporta otros modos según el escenario:
| Modo de red | Escenario | Características |
|---|---|---|
| bridge | Comunicación multi-contenedor en un solo host | Modo predeterminado; aislamiento entre contenedores vía puente |
| host | Contenedor que necesita red de alto rendimiento | Usa la red del host directamente; sin aislamiento; mejor rendimiento |
| overlay | Comunicación entre hosts | Para Docker Swarm o Kubernetes; contenedores en varias máquinas |
| none | Contenedor totalmente aislado | Sin interfaz de red; para requisitos de seguridad extremos |
En la mayoría de casos basta una red bridge personalizada. El modo host sirve cuando el rendimiento de red es crítico (por ejemplo, trading de alta frecuencia). Overlay es la base de Swarm y K8s; normalmente no hace falta configurarlo a mano.
Preguntas frecuentes (FAQ)
P1: ¿Por qué funciona con IP pero no con el nombre del contenedor?
R: Porque tus contenedores están en la red bridge predeterminada (docker0). Esa red no tiene DNS y no resuelve nombres. Crea una red personalizada y añade los contenedores.
P2: ¿Sigue funcionando —link?
R: Aún funciona, pero Docker ya no lo recomienda y lo eliminará en el futuro. Migra a redes personalizadas: más capacidades y alineado con la evolución del producto.
P3: ¿Las redes personalizadas afectan al rendimiento?
R: Casi no. Red personalizada y predeterminada son bridge; la implementación es la misma, solo añade DNS. La diferencia de rendimiento es despreciable.
P4: ¿Cómo acceden los contenedores a Internet?
R: Por defecto, los contenedores en bridge acceden a Internet vía NAT. Si no pueden, revisa las reglas iptables de Docker o la red del host.
P5: ¿Cómo migrar contenedores existentes a una red personalizada?
R: Dos pasos:
# 1. Conectar el contenedor a la nueva red
docker network connect my-app-net old-container
# 2. (Opcional) Desconectar de la red predeterminada
docker network disconnect bridge old-container
Es más recomendable recrear el contenedor con --network apuntando a la red personalizada.
P6: ¿El nombre del contenedor puede llevar mayúsculas?
R: Sí, pero no se recomienda. DNS suele usar minúsculas, números y guiones; es más portable y evita problemas.
P7: ¿Un contenedor puede estar en varias redes a la vez?
R: ¡Sí! Es una de las ventajas de las redes personalizadas. Usa docker network connect para unirlo a varias redes y construir topologías complejas.
Resumen
Repasemos lo esencial:
Paso 1: entender la causa raíz
- La red predeterminada de Docker no resuelve nombres; solo IP
- La IP cambia al reiniciar y la conexión falla
- —link está obsoleto; no lo uses
Paso 2: crear una red personalizada
docker network create my-app-net
Paso 3: unir contenedores a la red y comunicarse por nombre
# Al iniciar, especificar la red
docker run -d --name mysql-server --network my-app-net mysql:8.0
# En la aplicación, conectar por nombre
host: 'mysql-server' // no IP, sino nombre del contenedor
Este método es sencillo y es la práctica recomendada oficialmente por Docker. Tus aplicaciones containerizadas serán más estables y fáciles de mantener.
Si trabajas en microservicios o proyectos multi-contenedor, te recomiendo:
-
Actuar ya: migra tus proyectos a redes personalizadas y deja de hardcodear IPs
-
Probar Compose: con más de 3 contenedores, Docker Compose simplifica mucho la gestión
-
Profundizar: overlay y el modelo de red de Kubernetes son base del cloud native
La red de contenedores tiene curva de aprendizaje, pero una vez la dominas, Docker se vuelve mucho más útil. ¿Te apetece abrir la terminal y crear tu primera red personalizada?
Si tienes dudas, comenta abajo; intentaré responder.
Flujo completo de configuración de interconexión de contenedores Docker
Usa una red personalizada para resolver fallos de resolución por nombre y cambios de IP, y lograr comunicación estable entre contenedores web y de base de datos
⏱️ Estimated time: 15 min
- 1
Step 1: Entender la causa raíz: limitaciones de la red predeterminada de Docker
Causa raíz:
• La red predeterminada de Docker (bridge) solo permite comunicación por dirección IP, no resuelve nombres de contenedor
• Cada reinicio reasigna la IP del contenedor, invalidando la configuración de la aplicación
Limitaciones de la red predeterminada:
• No tiene DNS integrado; solo se puede acceder por IP
• El nombre del contenedor no responde al ping (unknown host)
• La IP cambia y no es adecuada para producción
Escenario real:
• El contenedor MySQL arranca correctamente y el contenedor Node.js también está en ejecución
• Pero la aplicación no puede conectar a la base de datos por nombre de contenedor, solo por IP
• Tras reiniciar el contenedor, la IP cambia y la configuración de la aplicación deja de funcionar - 2
Step 2: Crear una red personalizada
Crear una red personalizada:
• Usa el comando docker network create
• Comando: docker network create my-app-net
• Las redes personalizadas resuelven nombres de contenedor; los contenedores pueden acceder entre sí por nombre
• Los cambios de IP no afectan la configuración de la aplicación
Verificar la creación:
• Usa docker network ls para ver todas las redes
• Confirma que la red personalizada se ha creado - 3
Step 3: Especificar la red al iniciar contenedores
Especificar la red al iniciar contenedores:
• Usa el parámetro --network
• Comando: docker run -d --name mysql-server --network my-app-net mysql:8.0
• En la aplicación, conecta por nombre de contenedor (host: 'mysql-server', no IP, sino el nombre del contenedor)
Verificar la conexión:
• Prueba con ping al nombre del contenedor: docker exec -it web-container ping mysql-server
• O prueba la conexión de la aplicación a la base de datos - 4
Step 4: Usar docker-compose para crear la red automáticamente
Técnica avanzada: usar docker-compose para crear la red automáticamente
Define la red en docker-compose.yml:
• networks:
my-app-net:
driver: bridge
• Los servicios se unen a la misma red, los nombres se resuelven automáticamente, configuración simple y fiable
Ejemplo de configuración docker-compose:
• Define los servicios en services
• Define la red en networks
• Los servicios usan la red indicada y los nombres se resuelven automáticamente
Este método no solo es sencillo, sino que es la práctica recomendada oficialmente por Docker; tus aplicaciones containerizadas serán más estables y fáciles de mantener.
FAQ
¿Por qué el nombre del contenedor no responde al ping? ¿Qué limitaciones tiene la red predeterminada de Docker?
Limitaciones de la red predeterminada:
• No tiene DNS integrado
• Solo se puede acceder por IP
• El nombre del contenedor no responde al ping (unknown host)
• La IP cambia y no es adecuada para producción
Escenario real: el contenedor MySQL arranca correctamente y el contenedor Node.js también está en ejecución, pero la aplicación no puede conectar a la base de datos por nombre de contenedor, solo por IP; tras reiniciar el contenedor, la IP cambia y la configuración deja de funcionar.
¿Cómo resolver el problema de interconexión de contenedores? ¿Cómo configurar una red personalizada?
Pasos completos:
1. Crear red personalizada: docker network create my-app-net
2. Especificar la red al iniciar contenedores: docker run --network my-app-net
3. Conectar por nombre en la aplicación: host: 'mysql-server'
4. Verificar la conexión: ping al nombre del contenedor o probar la conexión de la aplicación
¿Cómo configurar la red de contenedores con docker-compose?
Pasos de configuración:
• Define la red en docker-compose.yml (networks: my-app-net: driver: bridge)
• Los servicios se unen automáticamente a la misma red
• Los nombres de contenedor se resuelven automáticamente
• Configuración simple y fiable
Ejemplo de configuración docker-compose:
• Define los servicios en services
• Define la red en networks
• Los servicios usan la red indicada
• Los nombres se resuelven automáticamente
Este método no solo es sencillo, sino que es la práctica recomendada oficialmente por Docker; tus aplicaciones containerizadas serán más estables y fáciles de mantener.
12 min de lectura · Publicado el: 17 dic 2025 · Actualizado el: 21 ago 2026
Guía práctica de Docker
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Modos de red Docker: bridge, host, none y container — rendimiento y cuándo usar cada uno
Análisis profundo de los cuatro modos de red Docker (bridge, host, none y container): principios, comparación de rendimiento y escenarios de uso. Te ayuda a elegir la configuración correcta, con casos prácticos y guía de decisión.
Parte 18 de 38
Siguiente
Mapeo de puertos en Docker: no dejes que «puerto ya asignado» arruine tu viernes por la noche
Desde el diagnóstico de puertos ocupados hasta la optimización del rendimiento: resuelve de forma sistemática todos los dolores del mapeo de puertos en Docker y despídete del error port already allocated
Parte 20 de 38



Comentarios
Inicia sesión con GitHub para dejar un comentario