Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running Django app in docker-compose: connection to postgres db refuses the first time but works afterwards

I have this weird problem that can be reproduced with the simple tutorial from Docker.

If I follow the tutorial exactly, everything would work fine, i.e. after docker-compose up command, the web container would run and connect nicely to the db container.

However, if I choose to create the same Django project on the host, change its settings for the postgres db, and copy it over to the web image in its Dockerfile, instead of mounting the host directory to the container and doing those things there as shown in the tutorial (using the command docker-compose run web django-admin.py startproject composeexample . and then change the settings file generated and located in the mounted directory on the host), the first time I run docker-compose up, the web container would have problems connecting to the db, with the error as below

web_1 | psycopg2.OperationalError: could not connect to server: Connection refused web_1 | Is the server running on host "db" (172.18.0.2) and accepting web_1 | TCP/IP connections on port 5432?

However, if I stop the compose with docker-compose down and then run it again with docker-compose up, the web container would connect to the db successfully with no problems.

'Connection refused' seems to be not an uncommon problem here but I have checked and verified that all the settings are correct and the usual causes like wrong port number, port not exposed or setting host as 'local' instead of 'db', etc. are not the problems in this case.

Note: FWIW, I use CNTLM as the system proxy in the host and have to set the environment variables for the web image, and it works fine for other scenarios.

EDIT: Please find additional info as below.

In the host directory I have the following files and directories

  • composeexample (generated by another container following the same tutorial and copied over to here)
  • manage.py (generated by another container and copied over to here)
  • requirements.txt (exactly as the one in the tutorial)
  • Dockerfile (slightly modified from the one in the tutorial)
  • docker-compose.yml (slightly modified from the one in the tutorial)

composeexample/settings.py:

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

Dockerfile (mostly the same, with the added env vars):

FROM python:3.5
ENV PYTHONUNBUFFERED 1
ENV http_proxy "http://172.17.0.1:3128"
ENV https_proxy "http://172.17.0.1:3128"
ENV HTTP_PROXY "http://172.17.0.1:3128"
ENV HTTPS_PROXY "http://172.17.0.1:3128"

RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/

docker-compose (I removed the mounted volume .:/code as the project files have already been copied to the web image when it's built. I tested with leaving it as in the original file and it made no difference):

version: '3'

services:
  db:
    image: postgres
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    ports:
      - "8000:8000"
    depends_on:
      - db
like image 360
ptrgreen Avatar asked Jul 12 '17 00:07

ptrgreen


2 Answers

Use wait-for-it.sh to wait for Postgres to be ready:

Download this well known script: https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh

version: '3'

services:
  db:
    image: postgres
  web:
    build: .
    command: /wait-for-it.sh db:5432 -- python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - ./wait-for-it.sh:/wait-for-it.sh
    ports:
      - "8000:8000"
    depends_on:
      - db

It will wait until the db port is open and won't waste any further.

like image 181
Robert Avatar answered Sep 27 '22 20:09

Robert


As documentation say depends_on depends_on it express dependency between containers but that does not mean that a container will wait to other to be ready, a possible solution is to add within of docker-compose a bit sleep, something like this:

command: /bin/bash -c "sleep 7; python3 manage.py runserver -h 0.0.0.0 -p 9000 -r -d"
like image 39
julian salas Avatar answered Sep 27 '22 22:09

julian salas