¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Networking y Service Discovery (Docker avanzado)
Contenido perteneciente al curso Docker avanzado.
Network
Docker crea una interfaz de red propia con el nombre de docker0. Esta red tiene un rango típico: 174.17.0.1/24
Al principio, solo se podía manejar esta red. Eso generaba problemas de seguridad (confiabilidad y aislamiento).
Esto se mejoró con el avance de Docker
Con el comando docker network ls podemos ver las redes que tenemos configuradas por defecto:
- host representa la red del propio equipo y haría referencia a
eth0/enp0s3, etc. Un contenedor con esta red tendrá una IP local (192.168.0.12) - bridge representa la red
docker0y a ella se conectan todos los contenedores por defecto. Vincula los contenedores con nuestro equipo. - none significa que el contenedor no se incluye en ninguna red y si verificamos esto con el comando ifconfig dentro del contenedor veríamos que solo tiene la interfaz de loopback lo.
Podemos obtener más información de las redes con inspect:
docker network inspect bridge
Ejemplo de salida:
[
{
"Name": "bridge",
"Id": "66ed3ed28d43f355bd4d79e01e58d571154d5a16cc33e5c2a0d7836cc4ee039e",
"Created": "2023-10-13T18:45:27.937713085Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
Si queremos aislar un contenedor o un grupo de contenedores, simplemente tenemos que crear una red:
docker network create --driver bridge red_aislada
y asociársela a los contenedores que queramos:
docker run --net=red_aislada -itd --name=container3 busybox
Podemos indicar que un contenedor tenga acceso a distintas redes.
Existe un comando para conectar un contenedor a cierta red:
docker network connect red_aislada contenedor
Y para desconectarlo:
docker network disconnect red_aislada contenedor
Para crear un sandbox sería útil la opción de desconectar de la red.
Overlay Network
Cuando necesitamos manejar una infraestructura compleja y grande puede ser necesario usar varios hosts en conjunto como si solo fuera uno.
Para ello necesitamos poder generar redes suprahost o superpuestas. Son redes para conectar nodos.
Para ese fin Docker hace uso de la librería VXLAN
Es imprescindible disponer de un servicio de almacenamiento key-value como Consul , Etcd , o ZooKeeper
El servicio se instala en un nodo, y en el resto se instala Docker.
Service Discovery
Un service discovery es un proceso de detección automática de dispositivos y servicios en una red.
Es un estándar de red que logra la detección de redes mediante la identificación de recursos.
Tradicionalmente, la detección de servicios ayuda a reducir los esfuerzos de configuración de los usuarios a los que se les presentan recursos compatibles, como una impresora o un servidor habilitado para Bluetooth
Más recientemente, el concepto se ha ampliado a los recursos de red o de contenedores distribuidos como “servicios”, que se descubren y a los que se accede.
Cuando trabajamos con Docker Compose, ya vemos esta característica ya que los contenedores pueden verse y podemos acceder a ellos desde el nombre de host.
El service provider tiene el service discovery. Al aparecer un nuevo servicio, se guarda en el service registry.
Service Discovery con Spring Boot
Ejemplos de implementación de un Service Discovery usando Eureka Service Discovery en Spring Boot:
Ejercicios
Ejercicio 1
Crear un contenedor con el comando docker run de cualquier imagen. Podemos usar por ejemplo la imagen busybox
docker run -d --name container1 busybox sleep infinity
1. ¿Qué redes tiene disponibles el container?
docker inspect container1
Salida:
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "66ed3ed28d43f355bd4d79e01e58d571154d5a16cc33e5c2a0d7836cc4ee039e",
"EndpointID": "2d5086c60d536dd9848015a736884bfb8d78e08ee8086eb2f094cd1989a6ce6f",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
Tiene disponible la red bridge.
2. ¿Mostrar solo las IPs del containter con el comando inspect?
docker inspect --format='{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container1
3. ¿Qué otros contenedores hay en esa misma red?
docker network inspect bridge
Podemos verlo en la sección “Containers”:
"Containers": {
"422af392e56a5c8dde4941fdce10e8b9618c17b8a2040f78f764cd88421032e5": {
"Name": "container1",
"EndpointID": "2d5086c60d536dd9848015a736884bfb8d78e08ee8086eb2f094cd1989a6ce6f",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
Ejercicio 2
1. Crear una red de tipo bridge llamada net1 para la subred 172.60.0.0/16
docker network create --driver=bridge --subnet=172.60.0.0/16 net1
2. Vincular el contenedor del ejercicio1 con esta nueva red
docker network connect net1 container1
3. Lista las IPs del contenedor1
Podemos verlas en la sección “Networks” al hacer:
docker inspect container1
Salida:
(...)
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "66ed3ed28d43f355bd4d79e01e58d571154d5a16cc33e5c2a0d7836cc4ee039e",
"EndpointID": "2d5086c60d536dd9848015a736884bfb8d78e08ee8086eb2f094cd1989a6ce6f",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
},
"net1": {
"IPAMConfig": {},
"Links": null,
"Aliases": [
"422af392e56a"
],
"NetworkID": "7e2ba91752dfc88d29ceec5a0783c445ad9802c97cbc41a88c89445020c91f66",
"EndpointID": "f0e49b9bea8dfd49163e7a29e0657b7a191a1f9ecdc27fa9471e5b8c8ff380da",
"Gateway": "172.60.0.1",
"IPAddress": "172.60.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:3c:00:02",
"DriverOpts": {}
}
(...)
También podríamos entrar en el contenedor y hacer un ifconfig:
docker exec -it container1 ifconfig
4. Crea un container2 que se vincule solo a la red net1
docker run -d --name container2 --network=net1 busybox sleep infinity
5. Verifica que desde container1 tenemos acceso a container2 y viceversa. Para ello puedes usar docker exec para ejecutar el comando ping entre los contenedores
Ping desde el container1 a container2:
docker exec container1 ping -c 3 container2 PING container2 (172.60.0.3): 56 data bytes 64 bytes from 172.60.0.3: seq=0 ttl=64 time=0.205 ms 64 bytes from 172.60.0.3: seq=1 ttl=64 time=0.081 ms 64 bytes from 172.60.0.3: seq=2 ttl=64 time=0.410 ms --- container2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.081/0.232/0.410 ms
Ping desde el container2 a container1:
docker exec container2 ping -c 3 container1 PING container1 (172.60.0.2): 56 data bytes 64 bytes from 172.60.0.2: seq=0 ttl=64 time=0.178 ms 64 bytes from 172.60.0.2: seq=1 ttl=64 time=0.454 ms 64 bytes from 172.60.0.2: seq=2 ttl=64 time=0.163 ms --- container1 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.163/0.265/0.454 ms
6. Desconecta todas las redes del container1
docker network disconnect bridge container1 docker network disconnect net1 container1
7. Lista las IPs del container1
Mediante:
docker inspect --format={{.NetworkSettings.IPA
ddress}} container1
No obtenemos ningún resultado.
Si ejecutamos ifconfig en el contenedor:
docker exec container1 ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:12 errors:0 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:750 (750.0 B) TX bytes:750 (750.0 B)
8. Prueba a hace un ping al container2 y a google.es
Ping a container2 desde container1:
docker exec container1 ping -c 3 container2 ping: bad address 'container2'
Ping a google.es desde container1:
docker exec container1 ping -c 3 google.es ping: bad address 'google.es'
Ejercicio redes y Compose
1. Crear un docker compose que levante una instancia de busybox
services: contenedor1: image: busybox # Añadimos lo siguiente para que no se detenga el contenedor command: sleep infinity
2. Listar las redes del contenedor
docker inspect network-compose-bb-1
3. Modificar el yaml para crear una red personalizada llamada net2 en la subnet 172.80.0.0/16 (la configuración de la subnet se hace en el path de propiedades ipam > config > subnet)
services: contenedor1: image: busybox command: sleep infinity networks: - net2 networks: net2: ipam: config: - subnet: 172.80.0.0/16
4. Tirar y levantar de nuevo el compose y verificar que la red creada es correcta y que el contenedor hace uso de esa red
Detenemos y eliminamos:
docker compose down -v
Después de hacer los cambios levantamos todo de nuevo:
docker compose up -d
Verificamos qué red usa ahora el contenedor:
docker inspect network-compose-contenedor1-1
También podemos hacer:
docker exec network-compose-contenedor1-1 ifconfig
Salida:
eth0 Link encap:Ethernet HWaddr 02:42:AC:50:00:02
inet addr:172.80.0.2 Bcast:172.80.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:33 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:11999 (11.7 KiB) TX bytes:0 (0.0 B)
5. Modificar el yaml para crear otro contenedor que hará uso de la misma red net2
services: contenedor1: image: busybox command: sleep infinity restart: always networks: - net2 contenedor2: image: busybox command: sleep infinity restart: always networks: - net2 networks: net2: ipam: config: - subnet: 172.80.0.0/16
6. Tirar y levantar de nuevo compose. Comprobar que los contenedores están en la misma red y son accesible entre ellos
Detenemos y eliminamos:
docker compose down -v
Después de hacer los cambios levantamos todo de nuevo:
docker compose up -d
Hacemos ping de un contenedor a otro:
$ docker exec network-compose-contenedor1-1 ping -c 3 contenedor2 PING bb2 (172.80.0.3): 56 data bytes 64 bytes from 172.80.0.3: seq=0 ttl=64 time=0.185 ms 64 bytes from 172.80.0.3: seq=1 ttl=64 time=0.088 ms 64 bytes from 172.80.0.3: seq=2 ttl=64 time=0.101 ms --- bb2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.088/0.124/0.185 ms
Hacemos ping desde el otro contenedor al primero:
$ docker exec network-compose-contenedor2-1 ping -c 3 contenedor1 PING bb (172.80.0.2): 56 data bytes 64 bytes from 172.80.0.2: seq=0 ttl=64 time=0.142 ms 64 bytes from 172.80.0.2: seq=1 ttl=64 time=0.090 ms 64 bytes from 172.80.0.2: seq=2 ttl=64 time=0.099 ms --- bb ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.090/0.110/0.142 ms
7. Modifica el yaml para que el segundo contenedor se conecte a otra red diferente de net2
Creamos antes una red:
docker network create netx
services: contenedor1: image: busybox command: sleep infinity restart: always networks: - net2 contenedor2: image: busybox command: sleep infinity restart: always networks: - netx networks: netx: net2: ipam: config: - subnet: 172.80.0.0/16
8. Tirar y levantar de nuevo compose. Comprobar que efectivamente los contenedores no están en la misma red
Al hacer un ping de un contenedor a otro, vemos que no se encuentran:
docker exec network-compose-contenedor1-1 ping -c3 contenedor2 ping: bad address 'bb2'
9. Modifica el yaml para que el segundo contenedor ahora se conecte a la net2 donde está el contenedor1 y además a la net1 externa (la que usamos en el ejercicio de redes básico). Para ello tendremos que configurarla como external:true y si el nombre no coincide con el nombre externo cambiarlo con name: net1
Debemos crear la red externa net1:
docker network create net1
Y el compose.yml:
services:
contenedor1:
image: busybox
command: sleep infinity
restart: always
networks:
- net2
contenedor2:
image: busybox
command: sleep infinity
restart: always
networks:
- net1
- net2
networks:
net1:
# name: net1
# Al indicar como externa, Compose ya no creará la red sino
# que la buscará externamente
external: true
net2:
ipam:
config:
- subnet: 172.80.0.0/16
10. Tirar y levantar de nuevo compose. Comprobar que los contenedores tienen las redes correctas y que tenemos acceso a los contenedores de la net1 levantados de forma externa a Compose
11. Modifica el yaml elimina todas las redes personalizadas y la asignación de redes en los contenedores. Pon en el contenedor1 la propiedad network_mode: bridge
services: contenedor1: image: busybox command: sleep infinity restart: always network_mode: bridge contenedor2: image: busybox command: sleep infinity restart: always
12. Tirar y levantar de nuevo compose. ¿qué configuración de red tienen los contenedores?
docker inspect network-compose-contenedor1-1
Resultado:
(...)
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "ca2555f0ebdc8ec786d99f4911b2dc17151ca8955c826345291199ec0bda559c",
"EndpointID": "7d467005b795e9ae7895b94458f22c9ecf3789c6c9160a37bbe6373626843c25",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
En el segundo contenedor:
docker inspect network-compose-contenedor2-1
Resultado:
(...)
"Networks": {
"network-compose_default": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"network-compose-bb2-1",
"bb2",
"95dca5a4e30e"
],
"NetworkID": "73471d80a0b4127dc6856c93a17bb3b7f34a1be2ebb286e6a9969a0098d740dd",
"EndpointID": "9c8f4cee41e8016a1c04cbb8d3b4013ada5906f6b8f2834ca0fb213a7e14542a",
"Gateway": "172.25.0.1",
"IPAddress": "172.25.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:19:00:02",
"DriverOpts": null
}
13. Modificar el yaml para que el container2 no tenga servicio de red. Usar network_mode
services: contenedor1: image: busybox command: sleep infinity restart: always network_mode: bridge contenedor2: image: busybox command: sleep infinity restart: always network_mode: none
Si ahora inspeccionamos el segundo contenedor:
docker inspect network-compose-contenedor2-1
Resultado:
(...)
"Networks": {
"none": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "5aabf5bab278005297359d26991878dab65725bb051ffb98e6a83780ab5e1e6c",
"EndpointID": "09e574cb240da878d71828f43c6bb6f1bff9706f06696964532bf6fcb86f751a",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
Ejercicio extra Compose y redes
Generar en el mismo directorio lo siguiente:
compose1.ymlque configure un serviciowp1(WordPress) ydb1(MySQL)compose2.ymlque configure un serviciowp2(WordPress) ydb2(MySQL)compose3.ymlque configure un phpMyAdminwp1deberá ser accesible desde localhost:8881wp1debe tener acceso adb1pero no adb2wp2deberá ser accesible desde localhost:8882wp2debe tener acceso adb2pero no adb1- phpMyAdmin deberá tener acceso a
db1ydb2que deberán estar configurados en suPMA_HOSTS
docker compose -f compose1.yml -f compose2.yml -f compose3.yml up -d
Esta técnica se suele usar para levantar las herramientas administrativas o nuevos servicios.
Solución:
Fichero compose1.yml:
services: db1: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress MYSQL_RANDOM_ROOT_PASSWORD: '1' networks: - db_net - default wp1: image: wordpress ports: - 8881:80 restart: always environment: WORDPRESS_DB_HOST: db1 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress networks: db_net: external: true
Fichero compose2.yml:
services: db2: image: mysql:5.7 restart: always environment: MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress MYSQL_RANDOM_ROOT_PASSWORD: '1' networks: - db_net - default wp2: image: wordpress ports: - 8882:80 restart: always environment: WORDPRESS_DB_HOST: db2 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress networks: db_net: external: true
Fichero compose3.yml:
services: phpmyadmin: environment: - PMA_HOSTS=db1,db2 image: phpmyadmin networks: - db_net ports: - 8880:80 restart: always networks: db_net: external: true
Extras:
Si queremos hacer algo como editar el /etc/hosts de un contenedor:
services: container1: extra_hosts: - miapp.local=192.168.0.13
