NOPE LinkedIn

Catégories:
Docker

Multi-Host Overlay Networking

Mise en réseau overlay multi-hôtes avec Etcd

=======================================

Docker dispose d’un pilote de réseau “overlay” intégré, et il est utilisé par défaut lorsque Docker s’exécute en mode swarm 1.

** Note** Le pilote Docker Overlay existe depuis Docker Engine 1.9 et un magasin K/V externe était nécessaire pour gérer l’état du réseau. Docker Engine 1.12 a intégré l’état du plan de contrôle dans Docker Engine afin qu’un magasin externe ne soit plus nécessaire. La version 1.12 a également introduit plusieurs nouvelles fonctionnalités, notamment le chiffrement et l’équilibrage de charge des services. Les fonctionnalités de mise en réseau qui sont introduites nécessitent une version de Docker Engine qui les prend en charge, et l’utilisation de ces fonctionnalités avec des versions plus anciennes de Docker Engine n’est pas prise en charge.

Dans ce lab, nous n’exécuterons pas docker en mode swarm, mais utiliserons le moteur docker avec un magasin clé-valeur externe pour créer une mise en réseau overlay multi-hôte. Nous avons choisi etcd 2 comme magasin clé-valeur externe. Vous pouvez changer le cluster etcd comme plan de gestion dans ce réseau multi-hôtes.

Le réseau overlay de Docker encapsule le trafic des conteneur dans un en-tête VXLAN qui permet au trafic de traverser le réseau physique de couche 2 ou de couche 3.

VXLAN fait partie du noyau Linux depuis la version 3.7 et Docker utilise les fonctionnalités VXLAN natives du noyau pour créer des réseaux overlay. Les données transitant par le drivers overlay Docker restent entièrement dans l’espace du noyau. Cela se traduit par moins de changements de contexte, moins de charge CPU, moins de latence, un accès direct entre les applications et la carte réseau physique.

Préparation de l’environnement


Création d’un cluster de deux noeuds etcd 3

Sur docker-node1:

  ubuntu@docker-node1:~$ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
  ubuntu@docker-node1:~$ tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
  ubuntu@docker-node1:~$ cd etcd-v3.0.12-linux-amd64
  ubuntu@docker-node1:~$ nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.205.10:2380 \
  --listen-peer-urls http://192.168.205.10:2380 \
  --listen-client-urls http://192.168.205.10:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://192.168.205.10:2379 \
  --initial-cluster-token etcd-cluster \
  --initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
  --initial-cluster-state new&

Sur docker-node2:

On lance etcd et on vérifie l’état du cluster avec la commande ./etcdctl cluster-health.

  ubuntu@docker-node2:~$ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
  ubuntu@docker-node2:~$ tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
  ubuntu@docker-node2:~$ cd etcd-v3.0.12-linux-amd64/
  ubuntu@docker-node2:~$ nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.205.11:2380 \
  --listen-peer-urls http://192.168.205.11:2380 \
  --listen-client-urls http://192.168.205.11:2379,http://127.0.0.1:2379 \
  --advertise-client-urls http://192.168.205.11:2379 \
  --initial-cluster-token etcd-cluster \
  --initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
  --initial-cluster-state new&
  ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl cluster-health
  member 21eca106efe4caee is healthy: got healthy result from http://192.168.205.10:2379
  member 8614974c83d1cc6d is healthy: got healthy result from http://192.168.205.11:2379
  cluster is healthy

Redémarrer le Docker engine avec la configuration du cluster


Sur docker-node1

  • avec une version de docker < 17.09
  ubuntu@docker-node1:~$ sudo service docker stop
  ubuntu@docker-node1:~$ sudo /usr/bin/docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.10:2379 --cluster-advertise=192.168.205.10:2375
  • avec une version de docker >= 17.09
  ubuntu@docker-node1:~$ sudo service docker stop
  ubuntu@docker-node1:~$ sudo /usr/bin/dockerd  -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.10:2379 --cluster-advertise=192.168.205.10:2375

Sur docker-node2

  ubuntu@docker-node2:~$ sudo service docker stop
  ubuntu@docker-node2:~$ sudo /usr/bin/docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.11:2379 --cluster-advertise=192.168.205.11:2375

Créer le réseau Overlay


  • Sur docker-node1, on créé un nouveau réseau avec le drivers overlay.
  ubuntu@docker-node1:~$ sudo docker network ls
  NETWORK ID          NAME                DRIVER              SCOPE
  0e7bef3f143a        bridge              bridge              local
  a5c7daf62325        host                host                local
  3198cae88ab4        none                null                local
ubuntu@docker-node1:~$ sudo docker network create -d overlay demo
3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9
ubuntu@docker-node1:~$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
0e7bef3f143a        bridge              bridge              local
3d430f3338a2        demo                overlay             global
a5c7daf62325        host                host                local
3198cae88ab4        none                null                local
ubuntu@docker-node1:~$ sudo docker network inspect demo
[
    {
        "Name": "demo",
        "Id": "3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9",
        "Scope": "global",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1/24"
                }
            ]
        },
        "Internal": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
  • Sur le noeud docker-node2, on constate que le réseau demo est ajouté automatiquement.
  ubuntu@docker-node2:~$ sudo docker network ls
  NETWORK ID          NAME                DRIVER              SCOPE
  c9947d4c3669        bridge              bridge              local
  3d430f3338a2        demo                overlay             global
  fa5168034de1        host                host                local
  c2ca34abec2a        none                null                local

Que s’est-il passé ? etcd a fait l’ajout automatiquement. On vérifie les valeurs des clefs etcd sur node2

  ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl ls /docker
  /docker/network
  /docker/nodes
  ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl ls /docker/nodes
  /docker/nodes/192.168.205.11:2375
  /docker/nodes/192.168.205.10:2375
  ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl ls /docker/network/v1.0/network
  /docker/network/v1.0/network/3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9
  ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl get /docker/network/v1.0/network/3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9 | jq .
  {
    "addrSpace": "GlobalDefault",
    "enableIPv6": false,
    "generic": {
      "com.docker.network.enable_ipv6": false,
      "com.docker.network.generic": {}
    },
    "id": "3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9",
    "inDelete": false,
    "ingress": false,
    "internal": false,
    "ipamOptions": {},
    "ipamType": "default",
    "ipamV4Config": "[{\"PreferredPool\":\"\",\"SubPool\":\"\",\"Gateway\":\"\",\"AuxAddresses\":null}]",
    "ipamV4Info": "[{\"IPAMData\":\"{\\\"AddressSpace\\\":\\\"GlobalDefault\\\",\\\"Gateway\\\":\\\"10.0.0.1/24\\\",\\\"Pool\\\":\\\"10.0.0.0/24\\\"}\",\"PoolID\":\"GlobalDefault/10.0.0.0/24\"}]",
    "labels": {},
    "name": "demo",
    "networkType": "overlay",
    "persist": true,
    "postIPv6": false,
    "scope": "global"
  }

Le network ID 3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9 est exactement le même ID que l’on peut voir avec la commande docker network ls. Toutes les informations sont synchrnisées par etcd.

  ubuntu@docker-node1:~$ sudo docker exec test1 ip link
  1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
      link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  53: eth0@if54: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue
      link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff
  55: eth1@if56: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
      link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff

Lancement de Containers sur le réseau Overlay


SUr docker-node1:

  ubuntu@docker-node1:~$ sudo docker run -d --name test1 --net demo busybox sh -c "while true; do sleep 3600; done"
  Unable to find image 'busybox:latest' locally
  latest: Pulling from library/busybox
  56bec22e3559: Pull complete
  Digest: sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912
  Status: Downloaded newer image for busybox:latest
  a95a9466331dd9305f9f3c30e7330b5a41aae64afda78f038fc9e04900fcac54
  ubuntu@docker-node1:~$ sudo docker ps
  CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
  a95a9466331d        busybox             "sh -c 'while true; d"   4 seconds ago       Up 3 seconds                            test1
  ubuntu@docker-node1:~$ sudo docker exec test1 ifconfig
  eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02
            inet addr:10.0.0.2  Bcast:0.0.0.0  Mask:255.255.255.0
            inet6 addr: fe80::42:aff:fe00:2/64 Scope:Link
            UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
            RX packets:15 errors:0 dropped:0 overruns:0 frame:0
            TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:0
            RX bytes:1206 (1.1 KiB)  TX bytes:648 (648.0 B)

  eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02
            inet addr:172.18.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
            inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
            UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
            RX packets:8 errors:0 dropped:0 overruns:0 frame:0
            TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:0
            RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

  lo        Link encap:Local Loopback
            inet addr:127.0.0.1  Mask:255.0.0.0
            inet6 addr: ::1/128 Scope:Host
            UP LOOPBACK RUNNING  MTU:65536  Metric:1
            RX packets:0 errors:0 dropped:0 overruns:0 frame:0
            TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:1
            RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

  ubuntu@docker-node1:~$

Sur docker-node2:

  ubuntu@docker-node2:~$ sudo docker run -d --name test1 --net demo busybox sh -c "while true; do sleep 3600; done"
  Unable to find image 'busybox:latest' locally
  latest: Pulling from library/busybox
  56bec22e3559: Pull complete
  Digest: sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912
  Status: Downloaded newer image for busybox:latest
  fad6dc6538a85d3dcc958e8ed7b1ec3810feee3e454c1d3f4e53ba25429b290b
  docker: Error response from daemon: service endpoint with name test1 already exists.
  ubuntu@docker-node2:~$ sudo docker run -d --name test2 --net demo busybox sh -c "while true; do sleep 3600; done"
  9d494a2f66a69e6b861961d0c6af2446265bec9b1d273d7e70d0e46eb2e98d20

On constate que si nous essayons de créer un container test1, on a une erreur : test1 already exist. C’est tout simplement parce que les deux noeuds partagent leur configuration au travers de etcd.

Contenu de etcd

  ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl get /docker/network/v1.0/endpoint/3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9/
  57aec8a581a7f664faad9bae6c48437289b0376512bbfe9a9ecb9d18496b3c61 | jq .
  {
    "anonymous": false,
    "disableResolution": false,
    "ep_iface": {
      "addr": "10.0.0.2/24",
      "dstPrefix": "eth",
      "mac": "02:42:0a:00:00:02",
      "routes": null,
      "srcName": "veth9337a4a",
      "v4PoolID": "GlobalDefault/10.0.0.0/24",
      "v6PoolID": ""
    },
    "exposed_ports": [],
    "generic": {
      "com.docker.network.endpoint.exposedports": [],
      "com.docker.network.portmap": []
    },
    "id": "57aec8a581a7f664faad9bae6c48437289b0376512bbfe9a9ecb9d18496b3c61",
    "ingressPorts": null,
    "joinInfo": {
      "StaticRoutes": null,
      "disableGatewayService": false
    },
    "locator": "192.168.205.10",
    "myAliases": [
      "a95a9466331d"
    ],
    "name": "test1",
    "sandbox": "fb8288acaf2169ff12230293dea6ec508387c3fb06ade120ba2c4283b3e88a6b",
    "svcAliases": null,
    "svcID": "",
    "svcName": "",
    "virtualIP": "<nil>"
  }
    ubuntu@docker-node2:~/etcd-v3.0.12-linux-amd64$

L’ip et l’adresse mac sont celles du container test1.

Testons la connectivitée:

  ubuntu@docker-node2:~$ sudo docker exec -it test2 ifconfig
  eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03
            inet addr:10.0.0.3  Bcast:0.0.0.0  Mask:255.255.255.0
            inet6 addr: fe80::42:aff:fe00:3/64 Scope:Link
            UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
            RX packets:208 errors:0 dropped:0 overruns:0 frame:0
            TX packets:201 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:0
            RX bytes:20008 (19.5 KiB)  TX bytes:19450 (18.9 KiB)

  eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02
            inet addr:172.18.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
            inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
            UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
            RX packets:8 errors:0 dropped:0 overruns:0 frame:0
            TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:0
            RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

  lo        Link encap:Local Loopback
            inet addr:127.0.0.1  Mask:255.0.0.0
            inet6 addr: ::1/128 Scope:Host
            UP LOOPBACK RUNNING  MTU:65536  Metric:1
            RX packets:0 errors:0 dropped:0 overruns:0 frame:0
            TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
            collisions:0 txqueuelen:1
            RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    ubuntu@docker-node1:~$ sudo docker exec test1 sh -c "ping 10.0.0.3"
    PING 10.0.0.3 (10.0.0.3): 56 data bytes
    64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.579 ms
    64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.411 ms
    64 bytes from 10.0.0.3: seq=2 ttl=64 time=0.483 ms
    ^C
    ubuntu@docker-node1:~$

Analyse 45


Docker Overlay Lors de la création du réseau overlay, Docker Engine crée l’infrastructure réseau requise pour les overlay sur chaque hôte (créer sur un hôte, et via la synchronisation etcd vers l’autre hôte). Un bridge Linux est créé par superposition avec ses interfaces VXLAN associées. Le moteur Docker instancie intelligemment les réseaux overlay sur les hôtes uniquement lorsqu’un conteneur est rattaché à ce réseau sur l’hôte. Cela empêche la créaation inutile des réseaux overlay où des conteneurs connectés n’existent pas.

Ils y a deux interfaces réseau sur chaque container, une pour le réseau docker_gwbridge, et l’autre pour le réseau overlay demo.

Références