Redes en Compose
Compose gestiona la red por ti de forma predeterminada, pero te ofrece un control detallado cuando lo necesitas. Esta página explica cómo funciona la red por defecto y cómo los contenedores se descubren entre sí por su nombre. También cubre cuándo y cómo definir redes personalizadas, conectar servicios en proyectos de Compose independientes, mapear nombres de host personalizados y depurar problemas de conectividad.
Red por defecto y descubrimiento de servicios
Por defecto, Compose configura una única
red para tu aplicación. Cada contenedor de un servicio se une a la red por defecto y es tanto accesible por otros contenedores en esa red como detectable por su nombre de servicio. Esta red utiliza el controlador bridge. Para comprender cuándo utilizarías un controlador diferente, consulta Controladores de red: bridge frente a host.
Para la mayoría de las configuraciones de desarrollo, la red por defecto es suficiente. Al ejecutar docker compose up, Compose crea una red llamada <project-name>_default y conecta todos los servicios a ella. Cada servicio registra su nombre con un servidor DNS interno, de modo que los contenedores pueden comunicarse entre sí utilizando el nombre del servicio directamente. No se necesitan direcciones IP ni configuración manual.
Por ejemplo, supón que tu aplicación está en un directorio llamado myapp y tu archivo compose.yaml se ve así:
services:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres:latest
ports:
- "8001:5432"Compose conecta automáticamente todos los servicios a la red por defecto, por lo que no es necesario definir networks de forma explícita en el archivo de Compose.
Al ejecutar docker compose up, sucede lo siguiente:
- Se crea una red llamada
myapp_default. - Se crea un contenedor utilizando la configuración de
web. Se une amyapp_defaultbajo el nombreweb. - Se crea un contenedor utilizando la configuración de
db. Se une amyapp_defaultbajo el nombredb.
Ahora, cada contenedor puede buscar el nombre de servicio web o db y obtener la dirección IP del contenedor correspondiente. El servicio web puede conectarse a la base de datos en postgres://db:5432. Desde la máquina host, se puede acceder a la misma base de datos en postgres://localhost:8001 si tu contenedor se ejecuta localmente.
TipDocker asigna direcciones IP de contenedores de forma dinámica desde la subred de la red cada vez que se inicia un contenedor, por lo que no se persisten tras reinicios o recreaciones. Esto significa que siempre debes hacer referencia a los servicios por su nombre, no por la dirección IP. Cuando se recrean los contenedores, por ejemplo tras un cambio de configuración, reciben una nueva dirección IP. El nombre del servicio permanece estable.
A la red de tu aplicación se le asigna un nombre basado en el "nombre del proyecto", el cual se toma del nombre del directorio en el que reside. Puedes sobrescribir el nombre del proyecto con la
bandera --project-name o con la variable de entorno COMPOSE_PROJECT_NAME.
El HOST_PORT y el CONTAINER_PORT sirven para propósitos diferentes. En el ejemplo anterior, para db, el HOST_PORT es 8001 y el puerto del contenedor es 5432 (el valor por defecto de Postgres). La comunicación entre servicios en red utiliza el CONTAINER_PORT. El puerto del host solo se utiliza cuando se accede al servicio desde fuera de la red.
Actualización de contenedores en la red
Si realizas un cambio de configuración en un servicio y ejecutas docker compose up para actualizarlo, el contenedor antiguo se elimina y el nuevo se une a la red bajo una dirección IP diferente pero con el mismo nombre. Los contenedores en ejecución pueden buscar ese nombre y conectarse a la nueva dirección, pero la dirección antigua deja de funcionar.
Si algún contenedor tiene conexiones abiertas con el contenedor antiguo, estas se cierran. Es responsabilidad de cada contenedor detectar esta condición, volver a buscar el nombre y reconectarse.
Cambiar el modo de red
Por defecto, cada servicio se une a la red bridge del proyecto. Es el modo de red más seguro. Si no especificas
network_mode, este es el tipo de red que estás creando.
Puedes sobrescribir el modo de red por servicio. La opción network_mode admite los siguientes valores:
host: El contenedor comparte la pila de red del host. No se necesita ni se admite el mapeo de puertos, y la resolución DNS por nombre de servicio no funciona. Úsalo para herramientas a nivel de sistema, como monitores de red, que requieren acceso directo a las interfaces del host. Un contenedor que utilizanetwork_mode: hostpuede acceder a todos los puertos del host y observar todo el tráfico de red en él. Úsalo únicamente cuando sea realmente necesario.none: Desactiva toda la red del contenedor.service:{name}: Otorga al contenedor acceso al contenedor especificado haciendo referencia a su nombre de servicio.container:{name}: Otorga al contenedor acceso al contenedor especificado haciendo referencia a su ID de contenedor.
Puedes mezclar modos en un solo proyecto:
services:
app:
image: myapp
networks:
- isolated
ports:
- "3000:3000"
monitoring:
image: netdata/netdata
network_mode: host # Puede monitorear el sistema host y todos los puertos del host
networks:
isolated:
driver: bridgeEspecificar redes personalizadas
En lugar de limitarte a utilizar la red por defecto de la aplicación, puedes especificar tus propias redes con la clave de nivel superior networks. Esto te permite crear topologías más complejas y especificar
controladores de red personalizados y opciones. También puedes utilizarlo para conectar servicios a redes creadas externamente que no son gestionadas por Compose.
Cada servicio puede especificar a qué redes conectarse mediante la clave networks a nivel de servicio, que consiste en una lista de nombres que hacen referencia a las entradas bajo la clave de nivel superior networks.
El siguiente ejemplo muestra un archivo de Compose que define dos redes personalizadas. El servicio proxy está aislado del servicio db, porque no comparten una red en común. Solo app puede comunicarse con ambos.
services:
proxy:
build: ./proxy
networks:
- frontend
app:
build: ./app
networks:
- frontend
- backend
db:
image: postgres:latest
networks:
- backend
networks:
frontend:
driver: bridge # Especificar opciones del controlador
driver_opts:
com.docker.network.bridge.host_binding_ipv4: "127.0.0.1"
backend:
driver: custom-driver # Usar un controlador personalizadoLas redes se pueden configurar con direcciones IP estáticas estableciendo ipv4_address y/o ipv6_address para cada red conectada.
A las redes también se les puede asignar un nombre personalizado:
services:
# ...
networks:
frontend:
name: custom_frontend
driver: custom-driver-1Redes internas
Establecer internal: true en una red la crea sin conexión a las interfaces de red del host. No tiene una puerta de enlace (gateway) por defecto para la conectividad externa. Esto es útil para servicios como bases de datos que deben ser completamente inaccesibles desde fuera de la red del contenedor:
services:
cache:
image: redis
networks:
- isolated
worker:
image: myworker
networks:
- isolated
- public
networks:
isolated:
internal: true # Sin conectividad externa
public: # Red bridge estándar, creada por Compose al ejecutar docker compose upTen en cuenta que un servicio conectado tanto a una red interna como a una no interna (como worker en el ejemplo anterior) aún puede acceder a internet a través de la red no interna public.
Configurar la red por defecto
En lugar de, o además de especificar tus propias redes, también puedes cambiar la configuración de la red por defecto de toda la aplicación definiendo una entrada bajo networks llamada default:
services:
web:
build: .
ports:
- "8000:8000"
db:
image: postgres:latest
networks:
default:
driver: custom-driver-1 # Usar un controlador personalizadoUsar una red externa existente
Si has creado manualmente una red bridge utilizando docker network create, puedes conectar tus servicios de Compose a ella marcando la red como
external:
services:
# ...
networks:
network1:
name: my-pre-existing-network
external: trueEn lugar de crear <project-name>_default, Compose busca a red llamada my-pre-existing-network y conecta tus contenedores a ella.
Conectar múltiples proyectos de Compose
Las redes externas son especialmente útiles cuando los servicios de diferentes proyectos de Compose necesitan comunicarse. Crea una red compartida una vez y luego haz referencia a ella como externa en cada proyecto:
docker network create inter-projectbackend-compose.yaml:
services:
api:
image: myapi:latest
networks:
- shared
- default # Conservar también la red interna del proyecto
networks:
shared:
external: true
name: inter-projectfrontend-compose.yaml:
services:
web:
image: myfrontend:latest
environment:
API_URL: http://api:8080 # Referencia por nombre de servicio
networks:
- shared
networks:
shared:
external: true
name: inter-projectLos servicios en la misma red externa pueden comunicarse entre sí por el nombre del servicio, al igual que los servicios dentro de un solo proyecto.
ImportantLa red externa debe existir antes de ejecutar
docker compose up. Si no existe, Compose falla con el errorNetwork not found. Créala siempre primero condocker network create.
Red híbrida
Un servicio puede pertenecer tanto a una red compartida externa como a su propia red interna de proyecto. Esto te permite exponer únicamente los servicios que deben ser accesibles desde otros proyectos, manteniendo todo lo demás, como las bases de datos, completamente aislado:
services:
api:
image: myapp-api
networks:
- shared # Accesible desde otros proyectos
- internal # También puede acceder a la base de datos
database:
image: postgres:latest
networks:
- internal # No expuesto en la red compartida
networks:
shared:
name: inter-project
external: true
internal: {} # Específica del proyecto, aisladaDNS personalizado con extra_hosts
Puedes añadir asignaciones personalizadas de nombre de host a IP en el archivo /etc/hosts de un contenedor utilizando
extra_hosts. Esto resulta útil cuando un servicio necesita resolver un nombre de host que no está registrado en el DNS interno de Docker. Por ejemplo, una dependencia con IP fija o un endpoint de pruebas (staging):
services:
app:
image: myapp
extra_hosts:
- "api.staging:192.168.1.100"
- "cache.internal:192.168.1.101"Para mapear un nombre de host dinámicamente a la IP de la máquina host, utiliza el valor especial host-gateway:
services:
app:
image: myapp
extra_hosts:
- "host.docker.internal:host-gateway"En Linux, host-gateway se resuelve como la IP del host en la red bridge por defecto. En Mac y Windows, Docker proporciona esto de forma automática, por lo que host-gateway se resuelve en la misma dirección IP interna que host.docker.internal.
También puedes controlar extra_hosts desde variables de entorno, lo que facilita apuntar los servicios a diferentes destinos por entorno:
services:
app:
image: myapp
extra_hosts:
- "api.service:${API_HOST:-127.0.0.1}"
- "auth.service:${AUTH_HOST:-127.0.0.1}"Donde .env.development podría establecer API_HOST=localhost y un archivo de entorno de producción podría configurar API_HOST=10.0.1.50.
Para verificar qué se ha inyectado, inspecciona el archivo hosts dentro del contenedor:
$ docker compose exec app cat /etc/hostsRedes multi-host
Al desplegar una aplicación de Compose en un Docker Engine con el
modo Swarm habilitado, puedes utilizar el controlador incorporado overlay para permitir la comunicación multi-host. Las redes overlay siempre se crean como conectables (attachable). De forma opcional, puedes establecer la propiedad
attachable en false.
Para obtener más información, consulta la documentación del controlador de red overlay.
Vincular contenedores (Link)
Los enlaces (links) permiten definir alias adicionales mediante los cuales un servicio es accesible desde otro servicio. No son necesarios para la comunicación básica de servicio a servicio. Por defecto, cualquier servicio puede comunicarse con cualquier otro utilizando el nombre de ese servicio. En el siguiente ejemplo, db es accesible desde web tanto a través del nombre de host db como de database:
services:
web:
build: .
links:
- "db:database"
db:
image: postgres:latestConsulta la referencia de links para obtener más información.
Depuración (Debugging)
Cuando un servicio no puede comunicarse con otro, realiza los siguientes pasos en orden: primero confirma que la configuración de red sea correcta, luego confirma que los contenedores estén realmente conectados y finalmente prueba la conectividad en vivo.
Inspeccionar mapeo de puertos
Para averiguar qué puerto del host se mapea a un puerto del contenedor, utiliza docker compose port:
# ¿Qué puerto del host se mapea al puerto 5432 del contenedor en db?
$ docker compose port db 5432
# Output: 0.0.0.0:8001Esto resulta especialmente útil al utilizar el mapeo de puertos dinámico, donde el puerto del host cambia en cada docker compose up:
services:
web:
image: nginx
ports:
- "80" # Docker asigna el puerto del host dinámicamente$ docker compose port web 80
# Output: 0.0.0.0:55432Al escalar un servicio, cada réplica obtiene su propio puerto dinámico. Utiliza --index para consultar una réplica específica:
$ docker compose up -d --scale web=3
$ docker compose port --index=1 web 80 # Output: 0.0.0.0:55001
$ docker compose port --index=2 web 80 # Output: 0.0.0.0:55002
$ docker compose port --index=3 web 80 # Output: 0.0.0.0:55003Por defecto, docker compose port busca mapeos TCP. Si un servicio expone tanto TCP como UDP en el mismo puerto, utiliza --protocol:
$ docker compose port --protocol=udp myservice 53Verificar pertenencia a la red
Para comprobar qué contenedores están conectados a una red (útil al solucionar problemas de conectividad a través de redes externas o personalizadas):
$ docker network inspect <network-name>Comprobar conectividad
Si la pertenencia a la red parece correcta pero los servicios aún no pueden comunicarse entre sí, prueba la conectividad desde el interior de un contenedor en ejecución utilizando docker compose exec.
Información de referencia adicional
Para obtener detalles completos de las opciones de configuración de red disponibles, consulta las siguientes referencias: