virli/tutorial/4/networkns.md

7.4 KiB

\newpage

Le namespace network

Introduction

L'espace de noms network, comme son nom l'indique permet de virtualiser tout ce qui est en lien avec le réseau : les interfaces, les ports, les routes, les règles de filtrage, etc.

En entrant dans un nouvel espace de noms network, on se retrouve dans un environnement qui n'a plus qu'une interface de loopback :

``` 42sh# unshare -n ip a 1: lo: mtu 65536 qdisc noop state DOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 ```

Bien que portant le même nom que l'interface de loopback de notre environnement principal, il s'agit bien de deux interfaces isolées l'une de l'autre.

Qui dit nouvelle pile réseau, dit également que les ports qui sont assignés dans l'espace principal, ne le sont plus dans le conteneur : il est donc possible de lancer un serveur web sans qu'il n'entre en conflit avec celui d'un autre espace de noms.

Premiers pas avec ip netns

La suite d'outils iproute2 propose une interface simplifiée pour utiliser le namespace network : ip netns.

Nous pouvons tout d'abord créer un nouvel espace de noms :

```bash 42sh# ip netns add virli ```

La technique utilisée ici pour avoir des namespaces nommés est la même que celle que nous avons vue dans la première partie sur les namespaces : via un mount --bind dans le dossier /var/run/netns/. Cela permet de faire persister le namespace malgré le fait que plus aucun processus ne s'y exécute.

Maintenant que notre namespace est créé, nous pouvons regarder s'il contient des interfaces :

``` 42sh# ip netns exec virli ip link 1: lo: mut 65536 qdisc noop state DOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 ```

Cette commande ne nous montre que l'interface de loopback, car nous n'avons pour l'instant pas encore attaché la moindre interface.

D'ailleurs, cette interface est rapportée comme étant désactivée, activons-la via la commande :

```bash 42sh# ip netns exec virli ip link set dev lo up ```

À ce stade, nous pouvons déjà commencer à lancer un ping sur cette interface :

``` 42sh# ip netns exec virli ping 127.0.0.1 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.038 ms ... ```

Virtual Ethernet

Étant donné qu'une interface réseau ne peut être présente que dans un seul espace de noms à la fois, il n'est pas bien pratique d'imposer d'avoir une interface physique par conteneur, d'autant plus si l'on a plusieurs centaines de conteneurs à gérer.

Une technique couramment employée consiste à créer une interface virtuelle de type veth :

``` 42sh# ip link add veth0 type veth peer name veth1 ```

Une interface veth se comporte comme un tube bidirectionnel : tout ce qui entre d'un côté sort de l'autre et inversement. La commande précédente a donc créé deux interfaces veth0 et veth1 : les paquets envoyés sur veth0 sont donc reçus par veth1 et les paquets envoyés à veth1 sont reçus par veth0.

Dans cette configuration, ces deux interfaces ne sont pas très utiles, mais si l'on place l'une des deux extrémités dans un autre namespace network, il devient alors possible de réaliser un échange de paquets entre les deux.

Pour déplacer veth1 dans notre namespace virli :

```bash 42sh# ip link set veth1 netns virli ```

Il ne reste maintenant plus qu'à assigner une IP à chacune des interfaces :

```bash 42sh# ip netns exec virli ip a add 10.10.10.42/24 dev veth1 42sh# ip a add 10.10.10.41/24 dev veth0 ```

Dès lors1, nous pouvons pinger chaque extrêmité :

``` 42sh# ping 10.10.10.42 - et - 42sh# ip netns exec virli ping 10.10.10.41 ```

Il ne reste donc pas grand chose à faire pour fournir Internet à notre conteneur : via un peu de NAT ou grâce à un pont Ethernet.

Les autres types d'interfaces

Le bridge ou le NAT obligera tous les paquets à passer à travers de nombreuses couches du noyau. Utiliser les interfaces veth est plutôt simple et disponible partout, mais c'est loin d'être la technique la plus rapide ou la moins gourmande.

VLAN

Il est possible d'attribuer juste une interface de VLAN, si l'on a un switch supportant la technologie 802.1q derrière notre machine.

``` 42sh# ip link add link eth0 name eth0.100 type vlan id 100 42sh# ip link set dev eth0.100 up 42sh# ip link set eth0.100 netns virli ```

MACVLAN

Lorsque l'on n'a pas assez de carte ethernet et que le switch ne supporte pas les VLAN, le noyau met à disposition un routage basé sur les adresses MAC : le MACVLAN. S'il est activé dans votre noyau, vous allez avoir le choix entre l'un des quatre modes : private, VEPA, bridge ou passthru.

Quel que soit le mode choisi, les paquets en provenance d'autres machines et à destination d'un MAC seront délivrés à l'interface possédant la MAC. Les différences entre les modes se trouvent au niveau de la communication entre les interfaces.

VEPA

Dans ce mode, tous les paquets sortants sont directement envoyés sur l'interface Ethernet de sortie, sans qu'aucun routage préalable n'ait été effectué. Ainsi, si un paquet est à destination d'un des autres conteneurs de la machine, c'est à l'équipement réseau derrière la machine de rerouter le paquet vers la machine émettrice (par exemple un switch 802.1Qbg).

Pour construire une nouvelle interface de ce type :

``` 42sh# ip link add link eth0 mac0 type macvlan mode vepa ```
Private

À la différence du mode VEPA, si un paquet émis par un conteneur à destination d'un autre conteneur est réfléchi par un switch, le paquet ne sera pas délivré.

Dans ce mode, on est donc assuré qu'aucun conteneur ne pourra parler à un autre conteneur de la même machine.

``` 42sh# ip link add link eth0 mac1 type macvlan mode private ```
Bridge

À l'inverse des modes VEPA et private, les paquets sont routés selon leur adresse MAC : si jamais une adresse MAC est connue, le paquet est délivré à l'interface MACVLAN correspondante ; dans le cas contraire, le paquet est envoyé sur l'interface de sortie.

Pour construire une nouvelle interface de ce type :

``` 42sh# ip link add link eth0 mac2 type macvlan mode bridge ```

Aller plus loin {-}

Pour approfondir les différentes techniques de routage, je vous recommande cet article : Linux Containers and Networking2.

Appliqué à Docker, vous apprécierez cet article : Understanding Docker Networking Drivers and their use cases3.