Red Overlay DonDocker

Redes con varios host con Docker

En el post anterior Como hacer redes con Docker hablamos de como podemos gestionar y crear redes privadas para aislar contenedores. Al final del mismo post comentamos la forma de desplegar nuestros contenedores a través de multiples hosts usando una red overlay. Pues ahora vamos a proponer un ejemplo practico usando docker-machine con el driver de VirtuaBox. (Otros ejemplos de docker-machine http://dondocker.com/tag/docker-machine/).

Paso 1º. Crear el servicio key-value.

El primer paso va a ser la creación del servicio de key-value. Este servicio lo crearemos sobre una máquina virtual con un contenedor. Entre las distintas opciones que hay usaremos Consul

Creación de la máquina

>_ docker-machine create -d virtualbox mh-keystore

Una vez creada la máquina haremos que Docker se conecte a ella para usar contenedores. Simplemente, decimos a docker que en vez de usar el daemon local se conecte con tcp con la máquina virtual. Esto lo haremos simplemente así:

>_ eval "$( docker-machine  env mh-keystore )"

El siguiente paso será arrancar el contenedor de Consul dentro de la máquina mh-keystore.

>_ docker run -d \
-p "8500:8500" \
-h "consul" \
progrium/consul -server -bootstrap 

Esto arrancará consul en la máquina virtual haciendo que escuche el puerto 8500.

>_ docker logs consul
==> WARNING: Bootstrap mode enabled! Do not enable unless necessary
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
==> Starting raft data migration...
==> Starting Consul agent...
==> Starting Consul agent RPC...
==> Consul agent running!
         Node name: 'consul'
        Datacenter: 'dc1'
            Server: true (bootstrap: true)
       Client Addr: 0.0.0.0 (HTTP: 8500, HTTPS: -1, DNS: 53, RPC: 8400)
      Cluster Addr: 172.17.0.2 (LAN: 8301, WAN: 8302)
    Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false
             Atlas: <disabled>

==> Log data will now stream in as it occurs:

    2016/05/25 18:36:19 [INFO] serf: EventMemberJoin: consul 172.17.0.2
    2016/05/25 18:36:19 [INFO] serf: EventMemberJoin: consul.dc1 172.17.0.2
    2016/05/25 18:36:19 [INFO] raft: Node at 172.17.0.2:8300 [Follower] entering Follower state
    2016/05/25 18:36:19 [INFO] consul: adding server consul (Addr: 172.17.0.2:8300) (DC: dc1)
    2016/05/25 18:36:19 [INFO] consul: adding server consul.dc1 (Addr: 172.17.0.2:8300) (DC: dc1)
    2016/05/25 18:36:19 [ERR] agent: failed to sync remote state: No cluster leader
    2016/05/25 18:36:21 [WARN] raft: Heartbeat timeout reached, starting election
    2016/05/25 18:36:21 [INFO] raft: Node at 172.17.0.2:8300 [Candidate] entering Candidate state
    2016/05/25 18:36:21 [INFO] raft: Election won. Tally: 1
    2016/05/25 18:36:21 [INFO] raft: Node at 172.17.0.2:8300 [Leader] entering Leader state
    2016/05/25 18:36:21 [INFO] raft: Disabling EnableSingleNode (bootstrap)
    2016/05/25 18:36:21 [INFO] consul: cluster leadership acquired
    2016/05/25 18:36:21 [INFO] consul: New leader elected: consul
    2016/05/25 18:36:21 [INFO] consul: member 'consul' joined, marking health alive
    2016/05/25 18:36:21 [INFO] agent: Synced service 'consul'

Paso 2º. Creación del cluster.

Para este paso vamos a usar Swarm, que es la tecnología de Docker para crear clusters. Esta opción es bastante sencilla y simplifica bastante los pasos.

Por tanto, vamos a crear una máquina virtual como primer nodo del cluster de la siguiente forma:

>_ docker-machine create \
-d virtualbox \
--swarm --swarm-master \
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-advertise=eth1:2376" \
mhs-demo0 

Las opciones --swarm-* de docker-machine son opciones especificas para la definición del cluster. En este caso estamos diciendo que va a ser el nodo maestro y que la ip de búsqueda es la de la primera máquina que creamos mh-keystore.

A continuación crearemos un segundo nodo que formará parte del cluester.

>_  docker-machine create -d virtualbox \
--swarm \
--swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \
--engine-opt="cluster-advertise=eth1:2376" \
mhs-demo1 

Paso 3º. Creación de las redes.

En este paso vamos a crear las redes para hacer que los contenedores se comuniquen entre los distintos hosts. La red la crearemos en el nodo master. Antes tenemos que conectarnos a este nodo con docker-machine env

>_ eval "$( docker-machine env --swarm mhs-demo0 )"
>_ docker info 
Containers: 3
 Running: 3
 Paused: 0
 Stopped: 0
Images: 2
Server Version: swarm/1.2.2
Role: primary
Strategy: spread
Filters: health, port, containerslots, dependency, affinity, constraint
Nodes: 2
 mhs-demo0: 192.168.99.101:2376
  └ ID: N2W2:MVVQ:TZGG:WQOX:BA4Y:SPXS:F56B:Z5HV:CIWC:OUTD:WTJ5:3ORD
  └ Status: Healthy
  └ Containers: 2
  └ Reserved CPUs: 0 / 1
  └ Reserved Memory: 0 B / 1.021 GiB
  └ Labels: executiondriver=, kernelversion=4.4.8-boot2docker, operatingsystem=Boot2Docker 1.11.1 (TCL 7.0); HEAD : 7954f54 - Wed Apr 27 16:36:45 UTC 2016, provider=virtualbox, storagedriver=aufs
  └ Error: (none)
  └ UpdatedAt: 2016-05-25T18:54:01Z
  └ ServerVersion: 1.11.1
 mhs-demo1: 192.168.99.102:2376
  └ ID: B434:5PWY:YDE4:ONDV:B3OL:K7HG:UMK2:YP77:QE67:CHTU:RFX2:ZZDJ
  └ Status: Healthy
  └ Containers: 1
  └ Reserved CPUs: 0 / 1
  └ Reserved Memory: 0 B / 1.021 GiB
  └ Labels: executiondriver=, kernelversion=4.4.8-boot2docker, operatingsystem=Boot2Docker 1.11.1 (TCL 7.0); HEAD : 7954f54 - Wed Apr 27 16:36:45 UTC 2016, provider=virtualbox, storagedriver=aufs
  └ Error: (none)
  └ UpdatedAt: 2016-05-25T18:54:28Z
  └ ServerVersion: 1.11.1
Plugins: 
 Volume: 
 Network: 
Kernel Version: 4.4.8-boot2docker
Operating System: linux
Architecture: amd64
CPUs: 2
Total Memory: 2.042 GiB
Name: 8e1421ee1aa6
Docker Root Dir: 
Debug mode (client): false
Debug mode (server): false

Ahora creamos la red en el nodo master:

>_ docker network create --driver overlay --subnet=10.0.9.0/24 my-net

Hemos definido una red de tipo A con lo que vamos a poder disponer de 254 ips dentro del rango. Para verificar que la red se ha creado correctamente ejecutaremos el siguiene comando:

>_ docker network ls
NETWORK ID          NAME                DRIVER
8db83163da69        mhs-demo0/bridge    bridge 
dbc5916abeb4        mhs-demo0/host      host   
248d32990816        mhs-demo0/none      null   
755568abd038        mhs-demo1/bridge    bridge 
5c30ac1bb50a        mhs-demo1/host      host   
286298d5b51b        mhs-demo1/none      null   
7da91c4c6fed        my-net              overlay

Podemos verificar que la red es visible desde todos los nodos:

>_ # Selecionamos el otro nodo 
>_ eval $(docker-machine env mhs-demo1)
>_ docker network ls
NETWORK ID          NAME                DRIVER
755568abd038        bridge              bridge 
5c30ac1bb50a        host                host   
7da91c4c6fed        my-net              overlay
286298d5b51b        none                null   

Una vez que hemos visto que la red está disponible en todos los nodos podemos levantaremos un servidor Nginx con la página de prueba que tiene el propio servidor. El primer paso es seleccionar la máquina principal. A continuación ejecutaremos el comando que arrancará el Nginx con una variable de entorno:

>_ docker run -itd --name=web --net=my-net --env="constraint:node==mhs-demo0" nginx

Una vez que hemos levantado el servicio web vamos a comprobar como está disponible dentro de la red interna osea dentro de my-net. Para ello podemos levantar una máquina en el segundo nodo y hacer un curl o wget a web.

>_ docker run -it --rm --net=my-net --env="constraint:node==mhs-demo1" busybox wget -O- http://web
Connecting to web (10.0.9.2:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
\-                    100% |*******************************|   612   0:00:00 ETA

Con este comando wget verificamos que el servicio llamado web está disponible desde la red interna en este caso en la ip 10.0.9.2. Una vez terminado este punto vamos a verificar la conectividad con el exterior y así tenerla disponible para los usuarios.

>_ docker network ls
NETWORK ID          NAME                DRIVER
755568abd038        bridge              bridge 
9d1c91cacda1        docker_gwbridge     bridge 
5c30ac1bb50a        host                host   
7da91c4c6fed        my-net              overlay
286298d5b51b        none                null

Si hacemos ahora el listado de la redes nos vamos a encontrar con la red docker_gwbridge en cada uno de los nodos. Esta red conecta con la interfaz eth1 y tiene ips del rango 172.18.0.2/16. Esto lo podemos verificar de la siguiente forma:

>_ docker exec web ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:0a:00:09:02 brd ff:ff:ff:ff:ff:ff
    inet 10.0.9.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe00:902/64 scope link 
       valid_lft forever preferred_lft forever
16: eth1@if17: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:2/64 scope link 
       valid_lft forever preferred_lft forever

Dibujo de la interfaz final

Con estas indicaciones podrás crear redes de contenedores que puedan ser accedidas internamente desde los contenedores y en host separados. Esto explica como podemos crecer en horizontal incluyendo más nodos físicos (o virtuales) que estén en la misma o en diferente situación geográfica. Espero que te sea de ayuda.

One thought on “Redes con varios host con Docker

Leave a comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *