Redes en docker
1. ¿Por qué necesitamos redes? #
Hasta ahora hemos creado contenedores independientes:
1Nginx 2MySQL 3Debian 4Aplicaciones
Pero en una aplicación real es muy habitual que varios contenedores necesiten comunicarse.
Por ejemplo:
1APLICACIÓN WEB 2 │ 3 ↓ 4 MYSQL
La aplicación necesita conectarse con el servidor de base de datos.
Docker proporciona un sistema de redes que permite que los contenedores puedan:
- Comunicarse entre ellos.
- Comunicarse con el exterior.
- Mantener grupos de contenedores aislados.
- Localizar otros contenedores por su nombre.
2. Redes Docker #
Cuando Docker está instalado crea redes internas para poder conectar los contenedores.
Podemos ver las redes existentes mediante:
1docker network ls
La salida puede ser parecida a:
1NETWORK ID NAME DRIVER 2xxxxxxxx bridge bridge 3xxxxxxxx host host 4xxxxxxxx none null
Docker dispone de diferentes controladores de red. Entre los principales están bridge, host, none, overlay, ipvlan y macvlan.
3. La red bridge #
La red más habitual para trabajar con contenedores en un único equipo es:
1bridge
Cuando ejecutamos un contenedor sin especificar una red personalizada, Docker lo conecta normalmente a su red bridge predeterminada.
Por ejemplo:
1docker run -it debian bash
Docker proporciona al contenedor:
- Una interfaz de red.
- Una dirección IP.
- Una puerta de enlace.
- Acceso a determinados servicios de red.
4. Ver las redes #
Ejecutamos:
1docker network ls
Podremos ver algo parecido a:
1NETWORK ID NAME DRIVER SCOPE 2... 3 bridge bridge local 4 host host local 5 none null local
Las redes pueden variar dependiendo del sistema utilizado y de los proyectos que hayamos creado.
5. Inspeccionar una red #
Para obtener información detallada utilizamos:
1docker network inspect <red>
Por ejemplo:
1docker network inspect bridge
La salida aparece en formato JSON.
Podemos encontrar:
- Nombre.
- Driver.
- Subred.
- Gateway.
- Contenedores conectados.
- Direcciones IP.
6. Dirección IP de los contenedores #
Cada contenedor conectado a una red Docker obtiene normalmente una dirección IP dentro de esa red.
Podríamos tener:
1RED DOCKER 2 3172.18.0.0/16 4 5 │ 6 ├── nginx → 172.18.0.2 7 │ 8 └── mysql → 172.18.0.3
Estas direcciones son internas a la red Docker.
No debemos confundirlas con la dirección IP de nuestro ordenador.
7. Crear nuestra propia red #
Podemos crear una red utilizando:
1docker network create <nombre>
Por ejemplo:
1docker network create red-clase
Si no indicamos otro driver, Docker crea normalmente una red de tipo:
1bridge
Podemos comprobarla:
1docker network ls
8. Crear explícitamente una red bridge #
También podemos escribir:
1docker network create --driver bridge red-clase
o de forma abreviada:
1docker network create -d bridge red-clase
Después:
1docker network ls
debería mostrar:
1red-clase
9. Inspeccionar nuestra red #
Ejecutamos:
1docker network inspect red-clase
Entre la información podremos encontrar una configuración similar a:
1Subnet 2Gateway 3Containers
Docker asigna automáticamente una subred cuando no especificamos una.
10. Conectar un contenedor al crearlo #
Podemos indicar la red al ejecutar el contenedor mediante:
1--network
Por ejemplo:
1docker run -it --name debian1 --network red-clase debian bash
Ahora:
1debian1
está conectado a:
1red-clase
11. Crear un segundo contenedor #
Abrimos otra terminal y ejecutamos:
1docker run -it --name debian2 --network red-clase debian bash
Tenemos:
1red-clase 2 │ 3 ├── debian1 4 └── debian2
Los dos contenedores pertenecen a la misma red.
12. Comunicación utilizando el nombre #
Una ventaja importante de las redes creadas por el usuario es que Docker proporciona resolución de nombres entre los contenedores de la misma red.
Tenemos:
1debian1 2debian2
Desde debian1 podemos referirnos al otro contenedor mediante:
1debian2
en lugar de necesitar recordar su dirección IP.
Docker recomienda las redes bridge definidas por el usuario precisamente, entre otras razones, porque proporcionan resolución DNS automática entre contenedores.
13. Ejemplo conceptual #
Tenemos:
1RED: red-clase 2 3debian1 4 │ 5 │ nombre: debian2 6 ↓ 7debian2
Una aplicación podría utilizar como servidor:
1debian2
y Docker resolvería ese nombre dentro de la red.
14. Ejemplo con Nginx y Debian #
Creamos una red:
1docker network create red-web
Arrancamos Nginx:
1docker run -d --name servidor-web --network red-web nginx
Creamos otro contenedor:
1docker run -it --name cliente --network red-web debian bash
Ahora ambos están conectados:
1red-web 2 │ 3 ├── servidor-web 4 └── cliente
15. Comprobar la red #
Desde otra terminal podemos ejecutar:
1docker network inspect red-web
Dentro de:
1Containers
deberían aparecer:
1servidor-web 2cliente
16. Instalar herramientas de prueba #
Dentro del contenedor Debian podemos actualizar:
1apt update
Por ejemplo, podemos instalar:
1apt install -y curl
Después podremos comprobar el servidor:
1curl http://servidor-web
Deberíamos recibir el HTML de Nginx.
17. No hemos publicado ningún puerto #
Observa que hemos arrancado Nginx utilizando:
1docker run -d --name servidor-web --network red-web nginx
No hemos utilizado:
1-p
Sin embargo, cliente puede comunicarse con Nginx porque ambos están dentro de:
1red-web
Es importante distinguir:
1comunicación entre contenedores
de:
1acceso desde nuestro ordenador
18. Puertos y redes #
Si queremos acceder desde nuestro navegador tendremos que publicar el puerto.
Por ejemplo:
1docker run -d \ 2 --name servidor-web \ 3 --network red-web \ 4 -p 8080:80 \ 5 nginx
Entonces tendremos dos posibilidades:
1CONTENEDOR CLIENTE 2 │ 3 │ http://servidor-web 4 ↓ 5 NGINX
y desde nuestro ordenador:
1HOST 2http://localhost:8080 3 │ 4 ↓ 5 NGINX
19. Puerto publicado frente a puerto interno #
Podemos representarlo:
1Internet / Host 2 │ 3 │ 8080 4 ↓ 5CONTENEDOR NGINX 6 │ 7 │ 80 8 ↑ 9 │ 10OTROS CONTENEDORES
Los contenedores de la misma red pueden utilizar directamente:
1servidor-web:80
Mientras el host utiliza:
1localhost:8080
20. Conectar un contenedor que ya existe #
También podemos conectar un contenedor existente a una red.
Utilizamos:
1docker network connect <red> <contenedor>
Por ejemplo:
1docker network connect red-clase miDebian
Ahora:
1miDebian
pertenecerá también a:
1red-clase
21. Un contenedor puede tener varias redes #
Un mismo contenedor puede estar conectado a más de una red.
Por ejemplo:
1 red-frontend 2 │ 3 │ 4 APLICACIÓN 5 │ 6 │ 7 red-backend 8 │ 9 ↓ 10 MYSQL
Una aplicación puede comunicarse con diferentes grupos de servicios.
Docker permite conectar un contenedor simultáneamente a varias redes.
22. Desconectar un contenedor #
Para desconectar utilizamos:
1docker network disconnect <red> <contenedor>
Ejemplo:
1docker network disconnect red-clase miDebian
Después podemos comprobar:
1docker network inspect red-clase
23. Eliminar una red #
Para eliminar utilizamos:
1docker network rm <red>
Ejemplo:
1docker network rm red-clase
Una red que está siendo utilizada por contenedores normalmente no puede eliminarse hasta que estos hayan sido desconectados o eliminados.
24. Ejemplo de aislamiento #
Podemos crear:
1docker network create frontend
y:
1docker network create backend
Tenemos:
1frontend 2 3web1 4web2 5 6 7backend 8 9mysql 10redis
Los contenedores pertenecientes únicamente a redes diferentes están aislados entre sí.
25. Conectar una aplicación a dos redes #
Podríamos crear:
1docker run -d \ 2 --name app \ 3 --network frontend \ 4 nginx
Después:
1docker network connect backend app
Ahora:
1 frontend 2 │ 3 ↓ 4 app 5 ↑ 6 │ 7 backend 8 ┌───┴────┐ 9 ↓ ↓ 10 mysql redis
La aplicación puede comunicarse con servicios de ambas redes.
26. Red none #
Docker dispone de una red:
1none
Podemos ejecutar:
1docker run -it --network none debian bash
Este contenedor queda sin conectividad de red normal con otros contenedores o con el exterior.
Puede resultar útil cuando queremos un aislamiento de red máximo.
27. Red host #
También existe el driver:
1host
Con este modo el contenedor comparte directamente la pila de red del host, eliminando parte del aislamiento de red.
Es una opción específica que no suele ser necesaria para nuestras primeras prácticas.
Para el curso inicial, la red más importante será:
1bridge
28. Principales tipos de red #
Podemos resumir:
1bridge 2 ↓ 3contenedores en un mismo host 4 5host 6 ↓ 7usa directamente la red del host 8 9none 10 ↓ 11sin conectividad de red 12 13overlay 14 ↓ 15comunicación entre varios hosts Docker
Para este curso trabajaremos principalmente con:
1bridge
29. Redes y MySQL #
Vamos a crear una aplicación formada por:
1Debian 2+ 3MySQL
Primero:
1docker network create red-bd
Creamos MySQL:
1docker run -d \ 2 --name mysql \ 3 --network red-bd \ 4 -e MYSQL_ROOT_PASSWORD=Ad1234 \ 5 mysql
No hemos publicado:
13306:3306
porque queremos utilizar MySQL únicamente desde otros contenedores.
30. Crear un cliente MySQL #
Podemos arrancar otro contenedor que disponga del cliente MySQL o utilizar la propia imagen de MySQL.
Por ejemplo:
1docker run -it --rm \ 2 --network red-bd \ 3 mysql \ 4 mysql -hmysql -uroot -p
Observa:
1-hmysql
Estamos indicando como servidor:
1mysql
que es el nombre del contenedor.
31. ¿Por qué funciona mysql como servidor? #
Tenemos:
1red-bd 2 │ 3 ├── mysql 4 │ 5 └── cliente
Docker puede resolver:
1mysql
hacia el contenedor correspondiente dentro de la red definida por el usuario.
No necesitamos escribir:
1172.x.x.x
32. No utilizar IPs internas cuando no sea necesario #
Podríamos obtener una IP utilizando:
1docker inspect mysql
Pero normalmente es preferible utilizar nombres:
1mysql
en lugar de una dirección como:
1172.19.0.2
La dirección podría cambiar si eliminamos y volvemos a crear el contenedor.
El nombre del servicio o contenedor es más cómodo y mantenible.
33. Redes en Docker Compose #
En el bloque anterior vimos Docker Compose.
Una característica importante es que Compose crea por defecto una red para los servicios de un proyecto.
Por ejemplo:
1services: 2 3 web: 4 image: nginx 5 6 mysql: 7 image: mysql 8 environment: 9 MYSQL_ROOT_PASSWORD: Ad1234
Compose conecta ambos servicios a una red del proyecto.
34. Comunicación en Compose #
Desde:
1web
podemos utilizar:
1mysql
como nombre del servidor de base de datos.
Por ejemplo:
1DB_HOST=mysql 2DB_PORT=3306
Esto evita tener que conocer la IP interna.
35. Definir redes en Compose #
También podemos crear nuestras propias redes dentro del archivo.
Por ejemplo:
1services: 2 3 web: 4 image: nginx 5 networks: 6 - frontend 7 8 mysql: 9 image: mysql 10 environment: 11 MYSQL_ROOT_PASSWORD: Ad1234 12 networks: 13 - backend 14 15networks: 16 frontend: 17 backend:
En este ejemplo los servicios están separados.
36. Aplicación conectada a dos redes #
Podemos escribir:
1services: 2 3 web: 4 image: nginx 5 networks: 6 - frontend 7 - backend 8 9 mysql: 10 image: mysql 11 environment: 12 MYSQL_ROOT_PASSWORD: Ad1234 13 networks: 14 - backend 15 16networks: 17 frontend: 18 backend:
Tenemos:
1frontend 2 │ 3 ↓ 4 web 5 │ 6 ↓ 7backend 8 │ 9 ↓ 10 mysql
37. Ver las redes creadas por Compose #
Después:
1docker compose up -d
podemos ejecutar:
1docker network ls
Compose suele crear nombres relacionados con el proyecto.
También podemos inspeccionar cualquiera de esas redes:
1docker network inspect <nombre>
38. Crear una red con una subred concreta #
Docker permite especificar una subred.
Por ejemplo:
1docker network create \ 2 --subnet 172.30.0.0/16 \ 3 red-clase
Esto indica que la red utilizará direcciones de:
1172.30.0.0/16
Docker permite definir explícitamente subredes al crear redes.
39. Ejemplo de direccionamiento #
Podríamos tener:
1Red: 172.30.0.0/16 2 3Gateway: 4172.30.0.1 5 6Contenedor 1: 7172.30.0.2 8 9Contenedor 2: 10172.30.0.3
Las direcciones concretas dependerán de la asignación realizada por Docker.
40. IP fija #
También es posible trabajar con direcciones IP estáticas.
Por ejemplo, tras crear una red adecuada:
1docker run -d \ 2 --name servidor \ 3 --network red-clase \ 4 --ip 172.30.0.10 \ 5 nginx
Sin embargo, en aplicaciones normales es mejor aprovechar la resolución de nombres de Docker siempre que sea posible.
41. Práctica guiada #
Paso 1. Crear la red #
1docker network create red-practica
Paso 2. Comprobar #
1docker network ls
Paso 3. Inspeccionar #
1docker network inspect red-practica
Paso 4. Crear Nginx #
1docker run -d \ 2 --name web-practica \ 3 --network red-practica \ 4 nginx
Paso 5. Crear un Debian #
1docker run -it \ 2 --name cliente-practica \ 3 --network red-practica \ 4 debian bash
42. Probar la comunicación #
Dentro de Debian:
1apt update
Instalamos:
1apt install -y curl
Después:
1curl http://web-practica
Deberíamos obtener la página de Nginx.
43. Comprobar desde Docker #
Desde otra consola:
1docker network inspect red-practica
Deberíamos encontrar los dos contenedores conectados.
44. Salir y limpiar #
Salimos de Debian:
1exit
Eliminamos:
1docker rm cliente-practica
Detenemos Nginx:
1docker stop web-practica
Eliminamos:
1docker rm web-practica
Por último:
1docker network rm red-practica