Journal Pihole et les conteneurs Docker

Posté par  . Licence CC By‑SA.
Étiquettes :
11
15
juin
2021

J’ai récemment rencontré un problème en combinant l’utilisation de Pihole et de conteneurs Docker. Je vais détailler ce qui se passe et donner une manière de résoudre ça.

Contexte et problème

   ┌──────────────────────── Hôte ────────────────────────┐
   │                                                      │
   │                                                      │
   │    ┌─────────────────────────┐                       │
   │    │                         │                       │
   │    │                      ┌──┴───┐                ┌──┴───┐
   │    │                      │ Ports◄────────────────► Ports│
   │    │                      │ DNS  │                │ DNS  │
   │    │  Conteneur Pihole    └──┬───┘                └──┬───┘
   │    │                         │                       │
   │    │                         ├───────┐               │
   │    └─────────────────────────┘       │               │
   │                                      │               │
   │    ┌────────────────────┐            │               │
   │    │  Conteneur Docker  ├────────────┤               │
   │    └────────────────────┘            │               │
   │                                   Réseau             │
   │                                   Docker             │
   │    ┌────────────────────┐            │               │
   │    │  Conteneur Docker  ├────────────┘               │
   │    └────────────────────┘                            │
   │                                                      │
   └──────────────────────────────────────────────────────┘

Il s’agit d’un cas de figure où plusieurs conteneurs tournent sur un seul hôte, et l’un de ces conteneurs est le serveur Pihole. Ce serveur DNS est utilisé par d'autres machines, l’hôte lui-même, et les autres conteneurs.

Ce qui se passe si on laisse une configuration par défaut, c’est que les autres conteneurs n’arrivent pas à effectuer de requêtes DNS. Je ne sais pas l’expliquer, il faudrait faire une analyse de paquets pour voir ce qu’il se passe réellement. Quoi qu’il en soit moi ça me pose problème par exemple parce que l’un de mes conteneurs est un serveur Nextcloud qui fait des requêtes vers l’extérieur.

Cette issue sur le Github de Pihole traite de ce problème.

Solution

Une solution est d’héberger Pihole sur un autre hôte. Mais moi je n’ai qu’une seule machine pour tout ça, alors non.

C’est pas idéale, mais il faut indiquer l’adresse IP du DNS à chaque conteneur qui en a besoin. Cela implique déjà de donner une adresse statique à Pihole. Moi j’utilise docker-compose pour tous mes conteneurs alors je vais vous donner de la configuration pour ça.

1. Connecter tous les conteneurs sur un même réseau docker (il y a plusieurs solutions, moi j’ai créé un réseau manuellement en ligne de commandes). Dans chaque docker-compose.yml je déclare ce réseau externe et j’indique aux conteneurs de l’utiliser :

version: '3'
networks:
  my_network:
    external:
      name: my-external-network
services:
  my_app:
    # d’autres lignes que je ne mets pas ici…
    networks:
      - my_network

2. Mais ça tout seul, ça ne fonctionne pas (comme dit plus haut). Il faut déjà
donner une adresse statique à Pihole (votre adresse dépend de votre réseau,
moi j’ai un réseau en 172.23.0.0/16. Voici donc le morceau de
configuration modifié :

services:
  pihole:
    networks:
         my_network:
           ipv4_address: 172.23.0.200

3. Ensuite, il faut indiquer aux autres conteneurs d’utiliser ce DNS :

   # Bien sûr je ne vous remets pas tout le fichier
   services:
     my_app:
       dns: 172.23.0.200

Et voilà, les conteneurs utiliseront directement l’adresse du conteneur Pihole pour leurs requêtes DNS.

C’est clairement moche cette adresse IP statique. Si vous avez des suggestions pour rendre ça plus propre, je suis preneur !

  • # IP

    Posté par  . Évalué à 5 (+3/-0).

    Retour sympa.

    Il me semble que tu peux ne pas te baser sur les IP, mais utiliser les noms de service. Si tu mets :

    version: '3'
    networks:
      my_network:
        external:
          name: my-external-network
    services:
      pihole:
        networks:
          - my_network
      my_app:
        dns: pihole
        networks:
          - my_network

    compose modifie les fichiers /etc/hosts des containers pour leur donner une correspondance nom de service/IP et id des containers/IP.

    Si ça fonctionne ce sera un chouia plus élégant

    • [^] # Re: IP

      Posté par  (site Web personnel) . Évalué à 3 (+1/-0).

      Oui, ça marche avec les noms et c'est tout de suite mieux :-)

      Petit exemple :

      docker-compose.echo.yaml:

      version: '3'
      networks:
              my_network:
                      name: my-external-network
      services:
              http_echo:
                      image: hashicorp/http-echo
                      command: '-text hello'
                      networks:
                              - my_network

      docker-compose.shell.yaml:

      version: '3'
      networks:
              my_network:
                      name: my-external-network
      services:
              shell:
                      image: alpine
                      networks:
                              - my_network

      Créer le réseau :

      /tmp/linuxfr
      ❯ docker network create my-external-network
      420c3fabac29f5526a69961dc723386903fcab555d3ad7aa05560087f35a7ac3
      

      Ensuite, démarrage de la première stack :

      /tmp/linuxfr
      ❯ docker compose -f docker-compose.echo.yaml up -d
      [+] Running 2/2
       ⠿ Network linuxfr_default        Created
       ⠿ Container linuxfr_http_echo_1  Started
      

      Enfin, ouverture d'un shell dans la deuxième stack, sur le même network et accès au conteneur de la première par le nom (c'est juste un conteneur qui print ce qu'on lui demande) :

      /tmp/linuxfr
      ❯ docker compose -f docker-compose.shell.yaml run shell sh
      / # wget -O- -q http_echo:5678
      hello
      / #
      
    • [^] # Re: IP

      Posté par  . Évalué à 1 (+1/-0).

      Étonnement, ça ne fonctionne pas :(

      En mettant dns: pihole, j’ai le comportement suivant :

      • Je peux accéder à Pihole avec curl (curl pihole me renvoie une réponse correcte), donc la résolution de nom de conteneur fonctionne bel et bien.
      • Les autres résolutions ne fonctionnent pas (par exemple curl linuxfr.org me renvoie un could not resolve host). Donc la résolution de pihole n’est pas utilisée pour les autres requêtes DNS il semblerait ?

      Je n’arrive pas à trouver de documentation qui explique cela. Cet article ou ce commentaire Github expliquent un peu comment le DNS fonctionne dans les conteneurs, mais il n’y a pas assez de détails.

      • [^] # Re: IP

        Posté par  (site Web personnel) . Évalué à 2 (+0/-0).

        ho, j'avais pas fait assez attention à cette histoire de dns :-(

        Le DNS doit pointer vers une adresse IP: https://docs.docker.com/config/containers/container-networking/#dns-services

        Je sais pas si c'est possible de faire autrement, faudrait regarder comment est implémenté la couche de DNS.

        • [^] # Re: IP

          Posté par  . Évalué à 2 (+0/-0). Dernière modification le 23/06/21 à 07:38.

          Si tu mets un nom comme serveur DNS, comment pourrait-il s'en servir, puisqu'il lui faut un serveur DNS pour en obtenir l'IP et s'y connecter ? (la poule, l'oeuf, toussa…)

          Le pihole doit être en IP fixe, pas d'autre alternative (regarde les DNS des FAIs, de Google, de Clouflare… on nous communique une IP, pas un nom).

          En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.

          • [^] # Re: IP

            Posté par  . Évalué à 2 (+0/-0).

            docker compose manipule le fichier /etc/hosts au démarrage.

            • [^] # Re: IP

              Posté par  (site Web personnel) . Évalué à 2 (+0/-0).

              hum, c'est pas fait dans /etc/hosts.
              Et surtout ça ne peut pas être fait au démarrage.
              Test avec l'exemple que j'ai mis au dessus. Si c'était fait au démarrage ça ne pourrait pas fonctionner car il s'agit de deux stacks différentes dont l'une n'existe pas au démarrage de la première.
              C'est tout dynamique par la couche DNS de Docker.

          • [^] # Re: IP

            Posté par  (site Web personnel) . Évalué à 2 (+0/-0).

            Je dirais que oui mais non. Le conteneur est configuré par défaut pour utiliser un DNS fourni par l'engine.
            Donc on pourrait très bien imaginer que cette couche, qui peut d'une façon ou d'une autre avoir accès aux bonnes infos, soit capable de faire cette translation.
            Maintenant j'ai pas connaissance que ce soit possible.
            Je vais demander, on sait jamais.

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.