Outils pour utilisateurs

Outils du site


tutoriaux:docker-related:docker-ipv6-nat

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
tutoriaux:docker-related:docker-ipv6-nat [2024/12/20 16:33] – supprimée - modification externe (Date inconnue) 127.0.0.1tutoriaux:docker-related:docker-ipv6-nat [2024/12/20 16:33] (Version actuelle) – ↷ Page déplacée de articles:docker-ipv6-nat à tutoriaux:docker-related:docker-ipv6-nat frater
Ligne 1: Ligne 1:
 +====== Docker: activer IPv6 sur un réseau interne docker ======
 +
 +Sur l'un de mes hosts tourne docker, et pour accéder aux applications j'utilise un reverse proxy ([[https://nginxproxymanager.com/|NPM]]), dans sa version [[https://hub.docker.com/r/jc21/nginx-proxy-manager|jc21]].
 +
 +Je m'assure, dans les paramètres du NPM que l'application reçoive bien l'adresse IP du client (et pas celle du proxy); je valide l'IP du client (au niveau de l'application) notamment pour limiter l'accès depuis certains pays au niveau de l'application (même si j'aurais pu le faire au niveau du NPM, ça sera pour un futur article).
 +
 +Si le passage de l'IPv4 du client vers l'application ne pose aucun problème avec les bon paramètres, l'IPv6 ne fonctionne pas bien, je capte l'IP du gateway à la place de l'IP du client, mais pourquoi...
 +
 +La faute à Docker... ou plutôt au NAT IPv6 -> application.
 +
 +===== un petit schéma =====
 +
 +{{drawio>articles:npm-architecture.png}}
 +
 +dans ce schémas, j'ai un seul réseau défini ''mybridged_net'', ce réseau est souvent créer avec une commande simple, sans précisions:
 +
 +<cli bash>
 +frater@host:~$ sudo docker network create --driver bridge mybridged_net
 +</cli>
 +
 +Docker attribuera automatiquement le premier subnet ''172.x.0.0/16'' libre (en général ''172.18.0.0/16'' et avec le gateway ''172.18.0.1'')
 +
 +{{drawio>articles:npm-architecture-complexe.png}}
 +
 + mais on peut imaginer un design plus complexe, avec 3 réseaux "définis"; ''public_net'', ''frontend_net'' et ''backend_net'':
 +
 +<cli bash>
 +frater@host:~$ sudo docker network create --driver bridge public_net
 +frater@host:~$ sudo docker network create --driver bridge frontend_net
 +frater@host:~$ sudo docker network create --driver host backend_net
 +</cli>
 +
 +Ces commandes créeront 3 réseaux avec probablement des ip : ''172.18.0.0/16'', ''172.19.0.0/16'' et ''172.20.0.0/16'' et le routage sera natif entre les différents réseaux... en IPv4, par défaut Docker utilisera le NAT pour convertir les packets IPv6 en IPv4.
 +===== Un peu de théorie =====
 +
 +
 +==== Docker et NAT ====
 +
 +Docker utilise un système de réseau virtuel pour isoler les conteneurs, ce qui permet à chaque conteneur d'avoir une adresse IP unique. Il existe quelques drivers (bridge, ipvlan, macvlan, overlay, null) mais soyons réaliste, 99.99% des gens vont utiliser un réseau ''bridge'' ou ''host'' (dans certains cas précis). 
 +
 +Du coup un réseau ''bridge'' va réaliser du NATing (Network Address Translation) entre les différents interfaces (physiques ou virtuels) pour communiquer en dehors du réseau.
 +
 +
 +==== NAT ???? ====
 +Le NAT est utilisé par Docker pour permettre aux conteneurs de communiquer sur Internet. 
 +
 +Le NAT est utilisé si le client est en IPv6 et que le conteneur n'est pas "publié" sur l'interface internet, il sera probablement uniquement en IPv4 (les reseaux interne de Docker n'ont pas d'adresse IPv6 activée par défaut), Docker utilise le NAT pour convertir de l'IPv6 vers l'IPv4 (utiliser dans les conteneurs non publiés).
 +
 +Comme je l'ai dit, nous allons principalement (et quasi uniquement utiliser) un réseau de type ''bridge'' (oui, il est <color #ed1c24>**fortement**</color> conseillé de créer son propre réseau).
 +
 +Lors de son installation, Docker crée un réseau de pont ''bridge'', qui connecte les conteneurs entre eux et avec l'interface réseau principale de l'hôte. 
 +
 +Les conteneurs qui sont sur le même réseau peuvent communiquer entre eux directement via leur adresse IP locale (dans le sous-réseau ''bridge'' ou ''host''), dans la mesure du possible, Docker routera les paquets entre les réseaux privés, sans NAT sauf si il y a changement de type d'adressage (par exemple IPv4 <-> IPv6).
 +
 +Docker applique une table NAT pour chaque paquet sortant du réseau ''bridge'' vers l'internet ou pour un changement de type d'adressage, Docker utilise le NAT pour modifier la source de l'adresse IP au niveau IP (source) pour qu'elle corresponde à l'adresse IP de l'interface réseau de l'hôte (''eth0'' ou ''ens33'', par exemple). 
 +
 +Le destinataire verra donc que les paquets proviennent de cette adresse IP plutôt que de celle du conteneur, et ce même dans le cas d'un échange conteneur à conteneur si l'on change de type d'adressage.
 +
 +Lorsqu'un conteneur doit envoyer un paquet vers Internet, le une table NAT est utilisée pour modifier la source de l'adresse IP du paquet. Le paquet est ensuite envoyé via l'interface réseau principale de l'hôte. 
 +
 +Les réponses arrivent à l'hôte via son interface réseau et sont ensuite redirigées vers le conteneur approprié grâce au NAT inversé (Reverse NAT). 
 +
 +==== La solution ====
 +
 +le conteneur cible (en IPv4 "voit" l'IP client du NAT (en général le gateway) quand il y a changement de réseau ou de type d'adressage, cela peut poser problème.
 +
 +Pour résoudre ce problème il faut que les réseaux privés de Docker soient capable de router, sans NAT autant l'IPv4 que l'IPv6; hors IPv6 reste difficile à comprendre et à implémenter.
 +
 +Après de longue recherche sur le net, j'ai finalement trouver une solution:
 +
 +<cli bash>
 +frater@docker network create --driver bridge server_ipv4v6 --subnet=172.21.0.0/16 --gateway=172.21.0.1 --ipv6 --subnet=fc00:db8:0021::/112 --gateway=fc00:db8:0021::1
 +</cli>
 +
 +Cette commande va créer un réseau, avec comme IP ''172.21.0.0/16 - GW 172.21.0.1'' et comme IPv6 ''fc00:db8:0021::/112'' et comme gateway ''fc00:db8:0021::1'', il est facile avec cette IPv6 'locale' de créer de multiple sous réseaux en changeant le ''0021'' en autre chose...