Django connection to postgres by docker-compose
Question:
My django project cannot connect to postgres database container. What I should to do?
It crashes on commands python manage.py collectstatic --noinput && python manage.py makemigrations blog && python manage.py migrate
.
I know docker run command creates a new container but I have more commands as
one by bash in docker-compose.yml. It should works, shouldn’t it?
my Dockerfile
:
FROM python:3.6-alpine
MAINTAINER Name <name@domain>
ENV PYTHONUNBUFFERED 1
ENV INSTALL_PATH /heckblog
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH
COPY requirements.txt requirements.txt
# make available run pip install psycopg2
RUN apk update &&
apk add --virtual build-deps gcc python3-dev musl-dev &&
apk add postgresql-dev
RUN pip3 install -r requirements.txt
# add bash into alpine linux
RUN apk add --update bash && rm -rf /var/cache/apk/*
COPY ./heckblog .
#RUN pip install .
CMD gunicorn -b 0.0.0.0:8000 --access-logfile - "config.wsgi:application"
my docker-compose.yml
:
version: '2'
services:
db:
image: postgres:alpine
environment:
POSTGRES_USER: blogdmin
POSTGRES_PASSWORD: password
POSTGRES_DB: heckblog
PGDATA: /tmp/pgdata
volumes:
- postgres_data:/tmp/pgdata
web:
build: .
command: >
bash -c "sleep 10 &&
python manage.py collectstatic --noinput &&
python manage.py makemigrations blog &&
python manage.py migrate &&
echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', '[email protected]', 'pass')" | python manage.py shell &&
gunicorn -b 0.0.0.0:8000 --access-logfile - --reload "config.wsgi:application""
volumes:
- ./heckblog:/heckblog
depends_on:
- db
environment:
IN_DOCKER: 1
ports:
- "80:8000"
volumes:
postgres_data:
settings.py
:
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'heckblog',
'USER': 'blogdmin',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '', # default port
}
}
...
Output of docker-compose up --build
:
web_1 | TCP/IP connections on port 5432?
web_1 | could not connect to server: Connection refused
web_1 | Is the server running on host "localhost" (127.0.0.1) and accepting
web_1 | TCP/IP connections on port 5432?
web_1 |
heckblog_web_1 exited with code 1
I use:
Windows 10
Docker 17.03.0-ce-win1-(10296)
docker-compose version 1.11.2
Django==1.10.6
psycopg2==2.7.1.
Thanks for answers
Answers:
Each container in docker by default gets its own hostname and IP. When compose spins up the containers for you, it also places all of the containers on a network by default to permit DNS based discovery.
What this means is that your database is not reachable on localhost, but you can reach it by the service name “db”. Change this line in your settings.py:
'HOST': 'localhost',
to:
'HOST': 'db',
Here’s what worked for me:
in compose:
version: '3.7'
services:
web:
build: .
command: python /code/manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- 8000:8000
environment:
- DB_HOST=db
- DB_NAME=web
- DB_USER=postgres
- DB_PASSWORD=postgres
depends_on:
- db
db:
image: postgres:12-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_DB=web
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
postgres_data:
in settings:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER':os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST':os.environ.get('DB_HOST'),
'PORT':5432,
}
}
Django settings.py -> Database={host:db}
. Other database option remain same. Like
DATABASE_ENGINE=django.db.backends.postgresql
DATABASE_USER=postgres
DATABASE_PASSWORD=1234
DATABASE_NAME=pos
DATABASE_HOST=db
DATABASE_PORT=5432
Docker compose yml file: This settings created for Django, Nginx, Postgres
version: '3.8'
services:
nginx:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- '81:81'
volumes:
- static_volume:/home/pos/static/
- ./docker/nginx/development:/etc/nginx/conf.d
depends_on:
- backend
backend:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/backend/Dockerfile
image: pos-backend:backend # image_name: image_tag
container_name: pos_backend
volumes:
- ./backend:/home/pos/
- static_volume:/home/pos/static
- media_volume:/home/pos/media
environment:
DJANGO_SETTINGS_MODULE: pos.settings
ports:
- "8000:8000"
command: python manage.py runserver 0.0.0.0:8000
expose:
- 8000
env_file:
- ./backend/.env.dev
depends_on:
- db
db:
image: postgres:12
container_name: pos_db
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=1234
- POSTGRES_DB=pos
ports:
- '5432:5432'
expose:
- 5432
networks:
- default
volumes:
static_volume: {}
media_volume:
postgres_data:
My django project cannot connect to postgres database container. What I should to do?
It crashes on commands python manage.py collectstatic --noinput && python manage.py makemigrations blog && python manage.py migrate
.
I know docker run command creates a new container but I have more commands as
one by bash in docker-compose.yml. It should works, shouldn’t it?
my Dockerfile
:
FROM python:3.6-alpine
MAINTAINER Name <name@domain>
ENV PYTHONUNBUFFERED 1
ENV INSTALL_PATH /heckblog
RUN mkdir -p $INSTALL_PATH
WORKDIR $INSTALL_PATH
COPY requirements.txt requirements.txt
# make available run pip install psycopg2
RUN apk update &&
apk add --virtual build-deps gcc python3-dev musl-dev &&
apk add postgresql-dev
RUN pip3 install -r requirements.txt
# add bash into alpine linux
RUN apk add --update bash && rm -rf /var/cache/apk/*
COPY ./heckblog .
#RUN pip install .
CMD gunicorn -b 0.0.0.0:8000 --access-logfile - "config.wsgi:application"
my docker-compose.yml
:
version: '2'
services:
db:
image: postgres:alpine
environment:
POSTGRES_USER: blogdmin
POSTGRES_PASSWORD: password
POSTGRES_DB: heckblog
PGDATA: /tmp/pgdata
volumes:
- postgres_data:/tmp/pgdata
web:
build: .
command: >
bash -c "sleep 10 &&
python manage.py collectstatic --noinput &&
python manage.py makemigrations blog &&
python manage.py migrate &&
echo "from django.contrib.auth.models import User; User.objects.create_superuser('admin', '[email protected]', 'pass')" | python manage.py shell &&
gunicorn -b 0.0.0.0:8000 --access-logfile - --reload "config.wsgi:application""
volumes:
- ./heckblog:/heckblog
depends_on:
- db
environment:
IN_DOCKER: 1
ports:
- "80:8000"
volumes:
postgres_data:
settings.py
:
...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'heckblog',
'USER': 'blogdmin',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '', # default port
}
}
...
Output of docker-compose up --build
:
web_1 | TCP/IP connections on port 5432?
web_1 | could not connect to server: Connection refused
web_1 | Is the server running on host "localhost" (127.0.0.1) and accepting
web_1 | TCP/IP connections on port 5432?
web_1 |
heckblog_web_1 exited with code 1
I use:
Windows 10
Docker 17.03.0-ce-win1-(10296)
docker-compose version 1.11.2
Django==1.10.6
psycopg2==2.7.1.
Thanks for answers
Each container in docker by default gets its own hostname and IP. When compose spins up the containers for you, it also places all of the containers on a network by default to permit DNS based discovery.
What this means is that your database is not reachable on localhost, but you can reach it by the service name “db”. Change this line in your settings.py:
'HOST': 'localhost',
to:
'HOST': 'db',
Here’s what worked for me:
in compose:
version: '3.7'
services:
web:
build: .
command: python /code/manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- 8000:8000
environment:
- DB_HOST=db
- DB_NAME=web
- DB_USER=postgres
- DB_PASSWORD=postgres
depends_on:
- db
db:
image: postgres:12-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_DB=web
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
postgres_data:
in settings:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER':os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST':os.environ.get('DB_HOST'),
'PORT':5432,
}
}
Django settings.py -> Database={host:db}
. Other database option remain same. Like
DATABASE_ENGINE=django.db.backends.postgresql
DATABASE_USER=postgres
DATABASE_PASSWORD=1234
DATABASE_NAME=pos
DATABASE_HOST=db
DATABASE_PORT=5432
Docker compose yml file: This settings created for Django, Nginx, Postgres
version: '3.8'
services:
nginx:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- '81:81'
volumes:
- static_volume:/home/pos/static/
- ./docker/nginx/development:/etc/nginx/conf.d
depends_on:
- backend
backend:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/backend/Dockerfile
image: pos-backend:backend # image_name: image_tag
container_name: pos_backend
volumes:
- ./backend:/home/pos/
- static_volume:/home/pos/static
- media_volume:/home/pos/media
environment:
DJANGO_SETTINGS_MODULE: pos.settings
ports:
- "8000:8000"
command: python manage.py runserver 0.0.0.0:8000
expose:
- 8000
env_file:
- ./backend/.env.dev
depends_on:
- db
db:
image: postgres:12
container_name: pos_db
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=1234
- POSTGRES_DB=pos
ports:
- '5432:5432'
expose:
- 5432
networks:
- default
volumes:
static_volume: {}
media_volume:
postgres_data: