Cambiar tema

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

Easton editorial illustration: image-layer stack

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-container no 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.

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:

  1. Conexión unidireccional: solo my-app puede acceder a mysql, no al revés
  2. Difícil de mantener: con muchos contenedores, la configuración de —link se complica
  3. 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:

  1. 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.

  2. 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.

  3. Mejor mantenibilidad: aunque la IP cambie tras un reinicio, usas el nombre del contenedor y el DNS actualiza el registro automáticamente.

  4. 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:

ProblemaPosible causaSolución
Ping al nombre fallaContenedores en redes distintasConfirma con docker network inspect; conecta con docker network connect
Ping OK pero la app no conectaPuerto mal configuradoRevisa el puerto en la app y el que escucha MySQL (3306 por defecto)
Base de datos rechaza conexiónUsuario/contraseña o permisosRevisa variables de entorno; entra al contenedor MySQL y comprueba permisos
Error de resolución DNSProbablemente red predeterminadaCrea 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 redEscenarioCaracterísticas
bridgeComunicación multi-contenedor en un solo hostModo predeterminado; aislamiento entre contenedores vía puente
hostContenedor que necesita red de alto rendimientoUsa la red del host directamente; sin aislamiento; mejor rendimiento
overlayComunicación entre hostsPara Docker Swarm o Kubernetes; contenedores en varias máquinas
noneContenedor totalmente aisladoSin 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:

  1. Actuar ya: migra tus proyectos a redes personalizadas y deja de hardcodear IPs

  2. Probar Compose: con más de 3 contenedores, Docker Compose simplifica mucho la gestión

  3. 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. 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. 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. 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. 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?
Causa raíz: la red predeterminada de Docker (bridge) solo permite comunicación por dirección IP, no resuelve nombres de contenedor, y cada reinicio reasigna la IP, 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 deja de funcionar.
¿Cómo resolver el problema de interconexión de contenedores? ¿Cómo configurar una red personalizada?
Solución: usar una red personalizada que resuelve nombres de contenedor; los contenedores pueden acceder entre sí por nombre y los cambios de IP no afectan la configuración. Es la práctica recomendada oficialmente por Docker.

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?
Técnica avanzada: usar docker-compose para crear la red automáticamente.

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

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog