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
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.
Comentarios recientes