Herramientas de usuario

Herramientas del sitio


informatica:sistemas_operativos:cursos:docker_avanzado:networking_y_service_discovery

¡Esta es una revisión vieja del documento!


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 docker0 y 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.yml que configure un servicio wp1 (WordPress) y db1 (MySQL)
  • compose2.yml que configure un servicio wp2 (WordPress) y db2 (MySQL)
  • compose3.yml que configure un phpMyAdmin
  • wp1 deberá ser accesible desde localhost:8881
  • wp1 debe tener acceso a db1 pero no a db2
  • wp2 deberá ser accesible desde localhost:8882
  • wp2 debe tener acceso a db2 pero no a db1
  • phpMyAdmin deberá tener acceso a db1 y db2 que deberán estar configurados en su PMA_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.

Extras:

Si queremos hacer algo como editar el /etc/hosts de un contenedor:

services:
  container1:
    extra_hosts:
      - miapp.local=192.168.0.13
informatica/sistemas_operativos/cursos/docker_avanzado/networking_y_service_discovery.1697562011.txt.gz · Última modificación: por tempwin