7

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
6
  • Could you update post with your docker-compose, dockerfile and settings de django, please? Commented Jul 12, 2017 at 0:56
  • seems to be like that your django container hasn't a correct conection with your db container Commented Jul 12, 2017 at 1:03
  • Thanks, I've added my docker-compose, dockerfile and Django settings for the database. And yes, I've checked again and again to make sure the connection settings to the db are correct. In fact, as said in the question, if I stop and start the compose again it would connect to the db with no problem. So I assume the connection setting must be right? Commented Jul 12, 2017 at 1:17
  • Why not try to give a few seconds to start django container, I'm not sure if that is a problem but you try command: /bin/bash -c "sleep 7; python3 manage.py runserver -h 0.0.0.0 -p 9000 -r -d" Commented Jul 12, 2017 at 1:25
  • Thank you very much. Adding sleep 5 to the command of the web container has fixed the problem for me. I've read about this but it never comes to my mind that this is actually the problem. It's still a bit strange to me though, as I would expect that once you have set the depends_on, the web container would wait for the db to be fully ready before attempting to connect to it? Commented Jul 12, 2017 at 1:48

3 Answers 3

13

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I accepted julian's answer as it did help me resolve my problem, quick and simple. I've also done some research and this solution is a more proper solution to me, hence my upvote.
8

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"

Comments

4

You can use healthcheck.

example from: peter-evans/docker-compose-healthcheck: How to wait for container X before starting Y using docker-compose healthcheck

version: '3'

services:
  db:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 3s
      timeout: 30s
      retries: 3
  web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy

1 Comment

this way no more supported by docker compose file version 3 or higher

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.