7
votes

docker-compose avec deux conteneurs: le web ne peut pas se connecter à db

docker-compose ne parvient pas à créer le composant Web car il ne peut pas se connecter au composant db précédemment créé

Mac OSX 10.13.6, conda 4.5.11, Python 3.6.8, Docker version 18.09.1, docker-compose version 1.23.2

django 1.8.3 est installé avec requirements.txt depuis Dockerfile. Pas la liberté de mettre à jour.

Plusieurs discussions très similaires sur SO n'ont pas aidé (comme celle-ci: Docker-compose avec django n'a pas pu traduire le nom d'hôte" db "en adresse: nom ou service inconnu ).

J'ai un docker-compose.yml avec un réseau et deux composants:

docker build -t myapp-web .

Dans mes paramètres .py J'ai la section DATABASES:

$ docker container ps


CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
c110e8361cda        postgres:10         "docker-entrypoint.s…"   4 hours ago         Up 4 hours          0.0.0.0:5432->5432/tcp     myapp-db

Quand j'exécute $ docker-compose up -d , la première image (db) est créée et son conteneur démarre. Peut voir qu'il est en cours d'exécution et à l'écoute sur le port 5432 avec docker ps et lsof . La même chose se produit si je supprime le composant web: du fichier docker-compose.yml

Maintenant, le deuxième composant (web) a Dockerfile qui contient ces deux lignes (parmi beaucoup d'autres):

expose:
    - "5432"

Le "migrate" comme meurt avec cette erreur:

Traceback (most recent call last):
File "/usr/local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 130, in ensure_connection
    self.connect()
File "/usr/local/lib/python3.6/site-packages/django/db/backends/base/base.py", line 119, in connect
    self.connection = self.get_new_connection(conn_params)
File "/usr/local/lib/python3.6/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 176, in get_new_connection
    connection = Database.connect(**conn_params)
File "/usr/local/lib/python3.6/site-packages/psycopg2/__init__.py", line 130, in connect
    conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
psycopg2.OperationalError: could not connect to server: Connection refused
Is the server running on host "db" (37.34.32.51) and accepting TCP/IP connections on port 5432?

fatigué à plusieurs ajustements. * a changé la version '3.7' * ajouté à la section db

RUN python manage.py makemigrations myapp
RUN python manage.py migrate
  • ajouté au composant Web:

dépend de: - "db"

  • ajouté au composant Web:

liens: - "db"

  • définir PRODUCTION sur false

environnement: PRODUCTION: 'faux'

  • a changé HOST dans settings.py en nom de conteneur, en nom d'image, en balises, en identifiant de conteneur, en «localhost», en «127.0.0.1», etc. l'erreur est le idem, en mentionnant simplement le nouveau nom HOST au lieu de "db"
  • a fonctionné en dehors de l'environnement conda
  • exécuté avec le commutateur --build ( docker-compose up -d --build )
  • a élagué le système docker et exécuté à nouveau

C'est la même erreur.


MISE À JOUR: Après avoir suggéré que docker-compose ne fonctionne pas de cette façon, j'ai essayé de le diviser en deux tâches distinctes. Je construis d'abord mon conteneur myapp-db et je m'assure qu'il fonctionne sur le bon port:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': INSTANCE_NAME,
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': '5432'
    },

}

Ensuite, je construis myapp-web:

version: '3'
networks:
  bridge:
   driver: bridge
services:
  db:
    image: postgres:10
    container_name: myapp-db
    volumes:
      - ./postgres_data:/var/lib/postgresql/data/
    ports:
      - "5432:5432"
    environment:
     POSTGRES_DB: actionability-master
     POSTGRES_PASSWORD: postgres
     POSTGRES_USER: postgres
    networks:
      - bridge


  web:
    restart: unless-stopped
    container_name: myapp-web
    build: .
    command: /start_gunicorn.sh
    ports:
      - "8080:8080"
    environment:
      PRODUCTION: 'true'
    networks:
      - bridge


4 commentaires

le deuxième composant (web) a Dockerfile qui contient ces deux lignes , est-ce un Dockerfile dans le conteneur Web en cours d'exécution, ou le Dockerfile de le conteneur Web?


Vos commandes RUN sont toujours exécutées au moment de BUILD, pas au moment de l'exécution. Par conséquent, votre base de données n'existera pas lorsque vous créez l'image car il n'y a pas de base de données. Donc tu ne peux pas le faire de cette façon


Merci @SvenHakvoort, je pense que je l'ai compris. docker-compose ne fonctionne pas de cette façon, le fait que le composant db soit avant le conteneur Web dans le fichier docker-compose.yml ne signifie pas que son conteneur est déjà opérationnel lorsque le conteneur Web est en cours de construction, non?


@bluescores c'est Dockerfile du composant Web qui fait construire son image et démarrer son conteneur (si cela fonctionne :-)) par docker-compose


3 Réponses :


0
votes

Je sais que cela peut sembler très basique, mais pourquoi ne pas envisager une convention de dénomination légèrement plus sophistiquée, puis ajouter simplement ces noms à votre service DNS sur l'hôte, ou du moins aux enregistrements A?

Ensuite, le système peut accéder à la base de données par nom ou par IP. Juste une pensée.

Grands choix et combinaison de plate-forme et de langages btw, Django + PostgreSQL sont mes préférés. Je recommanderais également Bootstrap, surtout si vous recherchez des capacités de déploiement rapide d'outils.


3 commentaires

vous voulez dire au lieu de «db» et «web», appelez-les quelque chose de plus descriptif? Désolé, je n'ai pas compris comment cela va aider le fait que le Web ne voit pas la base de données? L'entrée 'HOST': 'db' dans le fichier settings.py doit pouvoir être résolue.


Les systèmes doivent encore pouvoir communiquer entre eux. C'est peut-être un problème IP, mais une approche basée sur le DNS peut le résoudre. J'ai vu cela auparavant à partir d'autres problèmes avec docker dans le passé, y compris d'autres messages ici.


Comme note supplémentaire, Id recommande de créer des nœuds physiques de vos bases de données au lieu de conteneurs docker. Les bases de données subissent une baisse des performances lorsqu'elles sont ancrées. Ce sera mieux pour eux en termes de performances à long terme si vous créez simplement des clusters physiques et que vous les exécutez Master-Slave ou Master-Master.



2
votes

J'utilise la liste depend_on pour démarrer le conteneur db avant le conteneur Web et les liens pour m'assurer que les noms d'hôte peuvent être résolus.

J'ajoute le suivant sur le Web:

services:
  db:
    # ...
  web:
    links:
    - "db:db" # resolve the hostname "db" with the ip of the db container
    depends_on:
    - db # start db before web

Exemple


0 commentaires

0
votes

Vous pouvez essayer cette configuration avec des alias de réseau.

version: '3.5'
services:

  db:
    image: postgres:10
    container_name: myapp-db
    volumes:
      - ./postgres_data:/var/lib/postgresql/data/
    expose:
      - "5432"
    environment:
       POSTGRES_DB: actionability-master
       POSTGRES_PASSWORD: postgres
       POSTGRES_USER: postgres
    networks:
      services-network:
        aliases:
         - db

  web:
    restart: unless-stopped
    container_name: myapp-web
    build: .
    command: /start_gunicorn.sh
    ports:
      - "8080:8080"
    environment:
      PRODUCTION: 'true'
    depends_on:
      - db
    networks:
      services-network:
        aliases:
         - web

networks:
   services-network:
     name: services-network
     driver: bridge


0 commentaires