Autoriser le conteneur Docker à se connecter à une base de données postgres locale / hôte

143

J'ai récemment joué avec Docker et QGIS et j'ai installé un conteneur en suivant les instructions de ce tutoriel .

Tout fonctionne très bien, bien que je ne puisse pas me connecter à une base de données postgres localhost qui contient toutes mes données SIG. Je suppose que cela est dû au fait que ma base de données postgres n'est pas configurée pour accepter les connexions à distance et que j'ai modifié les fichiers conf postgres pour autoriser les connexions à distance à l'aide des instructions de cet article .

Je reçois toujours un message d'erreur lorsque j'essaye de me connecter à ma base de données exécutant QGIS dans Docker: impossible de se connecter au serveur: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? le serveur postgres est en cours d'exécution et j'ai modifié mon fichier pg_hba.conf pour permettre les connexions à partir d'une plage de Adresses IP (172.17.0.0/32). J'avais précédemment interrogé l'adresse IP du conteneur docker en utilisant docker pset bien que l'adresse IP change, elle a jusqu'à présent toujours été dans la plage 172.17.0.x

Des idées pourquoi je ne peux pas me connecter à cette base de données? Probablement quelque chose de très simple j'imagine!

J'utilise Ubuntu 14.04; Postgres 9.3

marty_c
la source

Réponses:

149

TL; DR

  1. Utiliser 172.17.0.0/16comme plage d'adresses IP, non 172.17.0.0/32.
  2. Ne l'utilisez pas localhostpour vous connecter à la base de données PostgreSQL sur votre hôte, mais plutôt à l'adresse IP de l'hôte. Pour garder le conteneur portable, démarrez le conteneur avec l' --add-host=database:<host-ip>indicateur et utilisez-le databasecomme nom d'hôte pour vous connecter à PostgreSQL.
  3. Assurez-vous que PostreSQL est configuré pour écouter les connexions sur toutes les adresses IP, pas seulement sur localhost. Recherchez le paramètre listen_addressesdans le fichier de configuration de PostgreSQL, généralement trouvé dans /etc/postgresql/9.3/main/postgresql.conf(crédits à @DazmoNorton).

Version longue

172.17.0.0/32n'est pas une plage d'adresses IP, mais une seule adresse (nommée 172.17.0.0). Aucun conteneur Docker n'obtiendra jamais cette adresse attribuée, car c'est l'adresse réseau de l' docker0interface Docker bridge ( ).

Lorsque Docker démarre, il crée une nouvelle interface réseau de pont, que vous pouvez facilement voir lors de l'appel ip a:

$ ip a
...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever

Comme vous pouvez le voir, dans mon cas, l' docker0interface a l'adresse IP 172.17.42.1avec un masque de réseau de /16(ou 255.255.0.0). Cela signifie que l'adresse réseau est 172.17.0.0/16.

L'adresse IP est attribuée au hasard, mais sans aucune configuration supplémentaire, elle sera toujours dans le 172.17.0.0/16réseau. Pour chaque conteneur Docker, une adresse aléatoire de cette plage sera attribuée.

Cela signifie que si vous souhaitez accorder l'accès de tous les conteneurs possibles à votre base de données, utilisez 172.17.0.0/16.

Helmbert
la source
1
hé merci pour vos commentaires. J'ai changé mon pg_hba.confà l'adresse que vous avez suggérée, mais je reçois toujours le même message d'erreur de connexion après l'arrêt et le redémarrage du service postgres. J'ai ajouté la ligne sous mes connexions ipv4 - y a-t-il un autre endroit où je suis censé ajouter l'adresse que vous suggérez? Sinon, dans mon application QGIS exécutée dans Docker, dois-je modifier les informations de connexion postgres? Par exemple, si je me connecte depuis un conteneur docker, l'hôte est-il toujours «localhost»?
marty_c
Ah, c'est un point important. Non, localhostle système hôte n'est pas à l'intérieur de votre conteneur Docker. Essayez de vous connecter à l'adresse IP publique du système hôte. Pour garder le conteneur portable, vous pouvez également démarrer le conteneur avec le --add-host=database:<host-ip>et simplement l'utiliser databasecomme nom d'hôte pour vous connecter à votre hôte PostgreSQL à partir du conteneur Docker.
helmbert
6
J'avais besoin d'un morceau de plus. J'ai également dû modifier /etc/postgresql/9.3/main/postgresql.confet ajouter l' eth0adresse IP de mon serveur listen_addresses. Par défaut, listen_addressespostgres est lié localhostuniquement à.
Dzamo Norton
@DzamoNorton, merci pour l'indice! J'ai mis à jour ma réponse en conséquence.
helmbert
@helmbert host-ipest l'adresse IP de la machine virtuelle ou du conteneur docker?
Mr.D
56

Solution Docker pour Mac

À partir du 17.06

Grâce au commentaire de @Birchlabs, c'est maintenant beaucoup plus facile avec ce nom DNS spécial disponible uniquement pour Mac :

docker run -e DB_PORT=5432 -e DB_HOST=docker.for.mac.host.internal

Depuis 17.12.0-cd-mac46, docker.for.mac.host.internaldoit être utilisé à la place de docker.for.mac.localhost. Voir la note de publication pour plus de détails.

Ancienne version

La réponse de @ helmbert explique bien le problème. Mais Docker pour Mac n'expose pas le réseau de pont , j'ai donc dû faire cette astuce pour contourner la limitation:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Ouvrez /usr/local/var/postgres/pg_hba.confet ajoutez cette ligne:

host    all             all             10.200.10.1/24            trust

Ouvrir /usr/local/var/postgres/postgresql.confet modifier les modifications listen_addresses:

listen_addresses = '*'

Rechargez le service et lancez votre conteneur:

$ PGDATA=/usr/local/var/postgres pg_ctl reload
$ docker run -e DB_PORT=5432 -e DB_HOST=10.200.10.1 my_app 

Ce que cette solution de contournement fait est fondamentalement la même chose avec la réponse de @ helmbert, mais utilise une adresse IP qui est attachée à la lo0place de l' docker0interface réseau.

baxang
la source
3
Est-ce toujours d'actualité au 4 avril 2017?
Petrus Theron
J'aime cette façon qui n'exposera pas la base de données. BTW, puis-je l'utiliser sur CentOS? J'ai eu l'erreur: alias: hôte inconnu lorsque j'ai essayé d'utiliser la commande d'alias que vous fournissez.
Tsung Goh
6
Il existe un meilleur moyen sur macOS, à partir de Docker 17.06.0-rc1-ce-mac13 (1er juin 2017). les conteneurs reconnaissent l'hôte docker.for.mac.localhost. c'est l'adresse IP de votre machine hôte. recherchez son entrée dans la base de données des hôtes du conteneur comme ceci: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs
@Birchlabs C'est tellement génial!
qqilihq
5
On dirait que cela a changé host.docker.internaldepuis 18.03, d'autres options sont toujours disponibles mais obsolètes ( Source ).
gseva
44

Solution simple pour Mac:

La dernière version de docker (18.03) offre une solution de transfert de port intégrée. À l'intérieur de votre conteneur Docker, définissez simplement l'hôte db sur host.docker.internal. Celui-ci sera transmis à l'hôte sur lequel le conteneur Docker s'exécute.

La documentation pour cela est ici: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Chris
la source
3
C'est de loin la meilleure réponse maintenant! beaucoup plus facile et comment cela devrait être.
bjm88
2
est host.docker.internallimité aux macs uniquement?
Dragas
@Dragas selon la documentation cela "ne fonctionnera pas en dehors du Mac", mais le même nom DNS est mentionné dans la documentation pour Docker pour Windows, donc je pense qu'il est limité à "Docker pour ...". Quoi qu'il en soit, c'est uniquement pour le développement: vous n'êtes pas censé envoyer une image docker qui l'utilise.
Rhubarb
Travaille uniquement avec Windows et Mac. Sur mon cas, ubuntu ne fonctionne pas
Azri Zakaria
17

Solution simple

Ajoutez simplement --network=hostà docker run. C'est tout!

De cette façon, le conteneur utilisera le réseau de l'hôte, donc localhostet 127.0.0.1pointera vers l'hôte (par défaut, il pointe vers un conteneur). Exemple:

docker run -d --network=host \
  -e "DB_DBNAME=your_db" \
  -e "DB_PORT=5432" \
  -e "DB_USER=your_db_user" \
  -e "DB_PASS=your_db_password" \
  -e "DB_HOST=127.0.0.1" \
  --name foobar foo/bar
Max Malysh
la source
1
Faites attention! Cette solution, qui est la bonne à mon avis, ne fonctionne pas pour macOS. Ne perdez pas votre temps à essayer de comprendre pourquoi cela ne fonctionne pas. Jetez un oeil à: github.com/docker/for-mac/issues/2716
jfcorugedo
1
Fonctionne sur Debian. J'ai essayé de changer postgresql.conf et pg_hba.conf mais c'est plus simple et plus rapide.
frmbelz le
2

Dans Ubuntu:

Vous devez d'abord vérifier que le port de la base de données Docker est disponible dans votre système en suivant la commande -

sudo iptables -L -n

Exemple de SORTIE:

Chain DOCKER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:3306
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:22

Ici 3306est utilisé comme port de base de données Docker sur IP 172.17.0.2, si ce port n'est pas disponible Exécutez la commande suivante -

sudo iptables -A INPUT -p tcp --dport 3306 -j ACCEPT

Maintenant, vous pouvez facilement accéder à la base de données Docker à partir de votre système local en suivant la configuration

  host: 172.17.0.2 
  adapter: mysql
  database: DATABASE_NAME
  port: 3307
  username: DATABASE_USER
  password: DATABASE_PASSWORD
  encoding: utf8

Dans CentOS:

Vous devez d'abord vérifier que le port de la base de données Docker est disponible dans votre pare-feu en suivant la commande -

sudo firewall-cmd --list-all

Exemple de SORTIE:

  target: default
  icmp-block-inversion: no
  interfaces: eno79841677
  sources: 
  services: dhcpv6-client ssh
  **ports: 3307/tcp**
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules:

Ici 3307est utilisé comme port de base de données Docker sur IP 172.17.0.2, si ce port n'est pas disponible Exécutez la commande suivante -

sudo firewall-cmd --zone=public --add-port=3307/tcp

Dans le serveur, vous pouvez ajouter le port en permanence

sudo firewall-cmd --permanent --add-port=3307/tcp
sudo firewall-cmd --reload

Maintenant, vous pouvez facilement accéder à la base de données Docker à partir de votre système local grâce à la configuration ci-dessus.

Sanaulla
la source
Je sais que c'est vieux mais maintenant, vous pouvez facilement accéder à la base de données Docker à partir de votre système local en suivant la configuration - vous avez cela dans le mauvais sens. Il a une base de données locale et une application docker essayant de se connecter à cette base de données locale, pas l'inverse
Craicerjack
2

La solution affichée ici ne fonctionne pas pour moi. Par conséquent, je publie cette réponse pour aider quelqu'un confronté à un problème similaire.

OS: Ubuntu 18
PostgreSQL: 9.5 (hébergé sur Ubuntu)
Docker: Application serveur (qui se connecte à PostgreSQL)

J'utilise docker-compose.yml pour créer une application.

ÉTAPE 1: Veuillez ajouterhost.docker.internal:<docker0 IP>

version: '3'
services:
  bank-server:
    ...
    depends_on:
      ....
    restart: on-failure
    ports:
      - 9090:9090
    extra_hosts:
      - "host.docker.internal:172.17.0.1"

Pour trouver l'adresse IP du docker, i.e. 172.17.0.1 (in my case)vous pouvez utiliser:

$> ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255

OU

$> ip a
1: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

ÉTAPE 2: Dans postgresql.conf, remplacez listen_addresses parlisten_addresses = '*'

ÉTAPE 3: Dans pg_hba.conf, ajoutez cette ligne

host    all             all             0.0.0.0/0               md5

ÉTAPE 4: Maintenant, redémarrez le service postgresql en utilisant,sudo service postgresql restart

ÉTAPE 5: Veuillez utiliser le host.docker.internalnom d'hôte pour connecter la base de données à partir de l'application serveur.
Ex:jdbc:postgresql://host.docker.internal:5432/bankDB

Prendre plaisir!!

singhpradeep
la source
1

pour docker-compose, vous pouvez essayer d'ajouter simplement

network_mode: "host"

exemple :

version: '2'
services:
  feedx:
    build: web
    ports:
    - "127.0.0.1:8000:8000"
    network_mode: "host"

https://docs.docker.com/compose/compose-file/#network_mode

Sarath Ak
la source
4
l'ajout de networkd_mode à l'hôte interrompre la connexion entre un autre conteneur
Bawantha
1

Pour configurer quelque chose de simple qui permet une connexion Postgresql du conteneur docker à mon hôte local, j'ai utilisé ceci dans postgresql.conf:

listen_addresses = '*'

Et a ajouté ce pg_hba.conf:

host    all             all             172.17.0.0/16           password

Faites ensuite un redémarrage. Mon client du conteneur docker (qui était à 172.17.0.2) pouvait alors se connecter à Postgresql en cours d'exécution sur mon hôte local en utilisant l'hôte: mot de passe, base de données, nom d'utilisateur et mot de passe.

Harlin
la source
0

Une autre chose nécessaire pour ma configuration était d'ajouter

172.17.0.1  localhost

à /etc/hosts

de sorte que Docker pointe 172.17.0.1comme le nom d'hôte de la base de données et ne se fie pas à une adresse IP externe changeante pour trouver la base de données. J'espère que cela aide quelqu'un d'autre avec ce problème!

Mikko Pöri
la source
14
C'est une mauvaise solution. Localhost doit généralement pointer vers 127.0.0.1. Le modifier peut avoir des conséquences indésirables, même si dans ce cas particulier cela fonctionne.
Alex
2
Une meilleure façon est de configurer un databasehôte avec --add-host=database:172.17.0.1lors de l'exécution du conteneur. Puis pointez votre application vers cet hôte. Cela évite de coder en dur une adresse IP à l'intérieur d'un conteneur.
jaredsk
1
le --add-host=database:172.17.0.1est préférable
Luis Martins
-3

L'autre solution est le volume de service. Vous pouvez définir un volume de service et monter le répertoire de données PostgreSQL de l'hôte dans ce volume. Consultez le fichier de composition donné pour plus de détails.

version: '2'
services:
  db:   
    image: postgres:9.6.1
    volumes:
      - "/var/lib/postgresql/data:/var/lib/postgresql/data" 
    ports:
      - "5432:5432"

En faisant cela, un autre service PostgreSQL fonctionnera sous le conteneur mais utilisera le même répertoire de données que celui utilisé par le service PostgreSQL hôte.

Hrishi
la source
1
Cela entraînera probablement des conflits d'écriture avec un service PostgreSQL hôte en cours d'exécution
Petrus Theron
Je pense que l'arrêt du service hôte résoudra le problème dans ce cas.
Hrishi