1

I wanted to create a Docker image for my Django project mysite that has two apps tracks and users. I used docker build -t mysite to build my docker image. I have written a Dockerfile like it says on dockerhub. Then i created docker-compose.yml file and bash script entypoint.sh that I use in docker-compose file.

These are my files:

Dockerfile:

FROM django:onbuild

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

docker-compose.yml:

version: '3'

services:
  db:
    image: postgres
    container_name: postgres_container
    environment:
     - POSTGRES_USER=postgres
     - POSTGRES_PASSWORD=postgres
     - POSTGRES_DB=postgres
    ports:
     - 5432:5432
  web:
    image: mysite:latest
    build:
     context: .
     dockerfile: Dockerfile
    container_name: mysite_container
    ports:
      - "8000:8000"
    depends_on:
      - db
    entrypoint: /entrypoint.sh

entrypoint.sh

#!/bin/sh

python manage.py makemigrations
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
exec "$@"

So when I wanted to start the whole container I used following commands

docker build .
docker-compose build
docker-compose up

And my postgres_containter starts successfully, but mysite_container throws the following error:

mysite_container | Traceback (most recent call last):
mysite_container |   File "manage.py", line 22, in <module>
mysite_container |     execute_from_command_line(sys.argv)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
mysite_container |     utility.execute()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/core/management/__init__.py", line 365, in execute
mysite_container |     self.fetch_command(subcommand).run_from_argv(self.argv)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/core/management/base.py", line 288, in run_from_argv
mysite_container |     self.execute(*args, **cmd_options)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/core/management/base.py", line 335, in execute
mysite_container |     output = self.handle(*args, **options)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/core/management/commands/migrate.py", line 79, in handle
mysite_container |     executor = MigrationExecutor(connection, self.migration_progress_callback)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/migrations/executor.py", line 18, in __init__
mysite_container |     self.loader = MigrationLoader(self.connection)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/migrations/loader.py", line 49, in __init__
mysite_container |     self.build_graph()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/migrations/loader.py", line 207, in build_graph
mysite_container |     self.applied_migrations = recorder.applied_migrations()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/migrations/recorder.py", line 61, in applied_migrations
mysite_container |     if self.has_table():
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/migrations/recorder.py", line 44, in has_table
mysite_container |     return self.Migration._meta.db_table in self.connection.introspection.table_names(self.connection.cursor())
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/backends/base/base.py", line 255, in cursor
mysite_container |     return self._cursor()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/backends/base/base.py", line 232, in _cursor
mysite_container |     self.ensure_connection()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection
mysite_container |     self.connect()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/utils.py", line 89, in __exit__
mysite_container |     raise dj_exc_value.with_traceback(traceback) from exc_value
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/backends/base/base.py", line 216, in ensure_connection
mysite_container |     self.connect()
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/backends/base/base.py", line 194, in connect
mysite_container |     self.connection = self.get_new_connection(conn_params)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/django/db/backends/postgresql/base.py", line 168, in get_new_connection
mysite_container |     connection = Database.connect(**conn_params)
mysite_container |   File "/usr/local/lib/python3.4/site-packages/psycopg2/__init__.py", line 130, in connect
mysite_container |     conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
mysite_container | django.db.utils.OperationalError: could not connect to server: Connection refused
mysite_container |      Is the server running on host "localhost" (127.0.0.1) and accepting
mysite_container |      TCP/IP connections on port 5432?
mysite_container | could not connect to server: Cannot assign requested address
mysite_container |      Is the server running on host "localhost" (::1) and accepting
mysite_container |      TCP/IP connections on port 5432?

My database in settings.py is

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

So, does anyone know why am I getting this error? My postgres is running successfully on localhost on port 5432 when I do docker-compose up, but it seems that my web container is not detecting that. What should I change in my Docker files to be able to run mysite_container properly?

EDIT: Now I added new settings_docker.py where I set my host to 'db' file and added environment variable DOCKER_SETTINGS_MODULE=mysite.settins_docker to my web service in docker-compose.yml and the container starts properly, but I don't have my database relations. So, how can I migrate those relations to docker?

anzoman
  • 129
  • 1
  • 10
  • What does your DATABASES setting look like in settings.py? – Andrew Graham-Yooll Aug 22 '18 at 07:47
  • It's like this: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'postgres', 'USER': 'postgres', 'PASSWORD': 'postgres', 'HOST': 'localhost', 'PORT': '5432', } } – anzoman Aug 22 '18 at 08:00
  • Also I would strongly suggest you not using the db name `postgres` unless you really know what you are doing connecting to the default db. https://stackoverflow.com/questions/2370525/default-database-named-postgres-on-postgresql-server – Andrew Graham-Yooll Aug 22 '18 at 08:10
  • When running postgres as a docker container, it's common practice to just have a single database. The database is called `postgres` by default in the official postgres docker image. What would be the problem with that? https://hub.docker.com/_/postgres/ – Håken Lid Aug 22 '18 at 08:25
  • Do you know if I can configure docker-compose.yml in a way that I wil keep localhost in my HOST configuration in settings.py? Also I tried changing HOST to 'db' and it starts running migrations but it is also throwing the same error like before. – anzoman Aug 22 '18 at 08:31

2 Answers2

2

In the django container, the postgres container looks like a different server. You should not use localhost as the hostname. Instead use the container name. So in the django config set this:

DATABASES = {
  'default': {
    'HOST': 'db',  # container name for postgres 
     [...]

https://docs.docker.com/compose/networking/

By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.

Håken Lid
  • 22,318
  • 9
  • 52
  • 67
  • Thank you. Is there any other way without changing HOST from 'localhost' to 'db'? – anzoman Aug 22 '18 at 09:11
  • Yes, there is always another way. But why? The solution is literally to change one single word. You could probably open up the port somehow. Read through the docker documentation. I find the structure of the docker docs quite confusing, but you can do all sorts of custom network configs. Or you could run postgresql and django in the same container, of course. But why would it be important that the hostname for the database should be `localhost`? – Håken Lid Aug 22 '18 at 10:33
  • You could try to change the name of the postgres container to `localhost`. I'm not sure if that would be a valid name. And it would be breaking the normal expectation of what `localhost` is. You would probably have to change the `/etc/hosts` file in the django container. And something else might break. But why do it the easy way, when you can make it complicated? – Håken Lid Aug 22 '18 at 10:41
  • I want to keep localhost because if I change localhost to db I am not able to run my Django site with python manage.py runserver anymore. – anzoman Aug 22 '18 at 10:50
  • In the container? Or on the host? If your environment is different, use environment variables to configure. – Håken Lid Aug 22 '18 at 11:06
  • Yes I meant starting it on the host. Which environment variables should I specify and where exactly if you know? – anzoman Aug 22 '18 at 11:14
  • https://stackoverflow.com/questions/45250494/storing-config-in-environment-python-django – Håken Lid Aug 22 '18 at 11:40
  • Hey, I've tried creating new settings file just for docker with host db, but I don't have any relations. How can I add my tables to this new host? – anzoman Aug 22 '18 at 13:33
  • Read the answer I linked to. Use environment variables. You don't need different settings files. – Håken Lid Aug 22 '18 at 14:13
  • Yes, I've read it but I doesn't say anything about importing tables and relations. – anzoman Aug 22 '18 at 14:45
0

I'm going to take a shot in the dark here and say your DATABASES setting is not correct in settings.py.

It needs to resemble:

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

For further reading here

EDIT: docker-compose.yml file adapted directly from the above link:

version: '3'

services:
  db:
    image: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=postgres
  web:
    image: mysite:latest
    build:
    context: .
    dockerfile: Dockerfile
    container_name: mysite_container
    ports:
      - "8000:8000"
    depends_on:
      - db
    entrypoint: /entrypoint.sh
Andrew Graham-Yooll
  • 2,148
  • 4
  • 24
  • 49
  • I have a similar DATABASES setting, but my host is localhost. Can i configure docker-compose.yml in a way that I wil keep localhost in my HOST configuration? Also I tried changing HOST to 'db' and it starts running migrations but it is also throwing the same error like before. – anzoman Aug 22 '18 at 08:26
  • @Anzoman What happens when you remove the container_name from the compose file? – Andrew Graham-Yooll Aug 22 '18 at 08:29
  • The database and the django app are running in different containers, so from the perspective inside the container, the postgres host is not `localhost`. – Håken Lid Aug 22 '18 at 08:30
  • @Andrew Graham-Yooll When I remove the container_name from the compose file the containers just get different names which are like services (web_1 and db_1) but else is the same. – anzoman Aug 22 '18 at 08:39
  • @Andrew Graham-Yooll thank you! The container starts successfully now. But is there any other way without changing HOST from 'localhost' to 'db'? – anzoman Aug 22 '18 at 09:09