Ok, so, I'm trying to start a project using Django and docker. The first step is simple, I just want to launch a default django app in container and see the django starting screen in my browser. I also want to hook up a simplest postgres container to run along with it. Everything great. I created a simple image for my app, nothing fancy:
FROM python:3.7
RUN mkdir /app
COPY requirements.txt /app/
WORKDIR /app
RUN pip install -r requirements.txt
COPY . /code/
And a docker-compose.yml:
version: '3'
services:
python:
build:
context: .
dockerfile: docker/python/Dockerfile
volumes:
- .:/app
command: python manage.py runserver 0.0.0.0:8000
ports:
- "8000:8000"
depends_on:
- db
restart: always
db:
image: postgres:9.5
environment:
POSTGRES_USER: cards
POSTGRES_DB: cards
POSTGRES_PASSWORD: cards
As you can see, I'm not even copying any source code into the docker image, I'm mounting a volume for django to read it from host.
The problem is when I start the containers, the django server is starting too soon for the postgres to be ready, and psycopg2 throws an OperationalError. Here are the logs, when I start fresh containers:
Creating network "backend_default" with the default driver
Creating backend_db_1 ... done
Creating python ... done
Attaching to backend_db_1, python
db_1 | The files belonging to this database system will be owned by user "postgres".
db_1 | This user must also own the server process.
db_1 |
db_1 | The database cluster will be initialized with locale "en_US.utf8".
db_1 | The default database encoding has accordingly been set to "UTF8".
db_1 | The default text search configuration will be set to "english".
db_1 |
db_1 | Data page checksums are disabled.
db_1 |
db_1 | fixing permissions on existing directory /var/lib/postgresql/data ... ok
db_1 | creating subdirectories ... ok
db_1 | selecting default max_connections ... 100
db_1 | selecting default shared_buffers ... 128MB
db_1 | selecting default timezone ... Etc/UTC
db_1 | selecting dynamic shared memory implementation ... posix
db_1 | creating configuration files ... ok
db_1 | creating template1 database in /var/lib/postgresql/data/base/1 ... ok
db_1 | initializing pg_authid ... ok
db_1 | setting password ... ok
db_1 | initializing dependencies ... ok
db_1 | creating system views ... ok
db_1 | loading system objects' descriptions ... ok
db_1 | creating collations ... ok
db_1 | creating conversions ... ok
db_1 | creating dictionaries ... ok
db_1 | setting privileges on built-in objects ... ok
db_1 | creating information schema ... ok
db_1 | loading PL/pgSQL server-side language ... ok
db_1 | vacuuming database template1 ... ok
db_1 | copying template1 to template0 ... ok
db_1 | copying template1 to postgres ... ok
python | Watching for file changes with StatReloader
python | Performing system checks...
python |
db_1 | syncing data to disk ...
db_1 | WARNING: enabling "trust" authentication for local connections
db_1 | You can change this by editing pg_hba.conf or using the option -A, or
db_1 | --auth-local and --auth-host, the next time you run initdb.
db_1 | ok
db_1 |
db_1 | Success. You can now start the database server using:
db_1 |
db_1 | pg_ctl -D /var/lib/postgresql/data -l logfile start
db_1 |
db_1 | waiting for server to start....LOG: database system was shut down at 2020-04-12 14:17:12 UTC
db_1 | LOG: MultiXact member wraparound protections are now enabled
db_1 | LOG: database system is ready to accept connections
db_1 | LOG: autovacuum launcher started
python | System check identified no issues (0 silenced).
python | Exception in thread django-main-thread:
python | Traceback (most recent call last):
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 217, in ensure_connection
python | self.connect()
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 195, in connect
python | self.connection = self.get_new_connection(conn_params)
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/postgresql/base.py", line 178, in get_new_connection
python | connection = Database.connect(**conn_params)
python | File "/usr/local/lib/python3.7/site-packages/psycopg2/__init__.py", line 127, in connect
python | conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
python | psycopg2.OperationalError: could not connect to server: Connection refused
python | Is the server running on host "db" (192.168.160.2) and accepting
python | TCP/IP connections on port 5432?
python |
python |
python | The above exception was the direct cause of the following exception:
python |
python | Traceback (most recent call last):
python | File "/usr/local/lib/python3.7/threading.py", line 926, in _bootstrap_inner
python | self.run()
python | File "/usr/local/lib/python3.7/threading.py", line 870, in run
python | self._target(*self._args, **self._kwargs)
python | File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 54, in wrapper
python | fn(*args, **kwargs)
python | File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/runserver.py", line 120, in inner_run
python | self.check_migrations()
python | File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 453, in check_migrations
python | executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
python | File "/usr/local/lib/python3.7/site-packages/django/db/migrations/executor.py", line 18, in __init__
python | self.loader = MigrationLoader(self.connection)
python | File "/usr/local/lib/python3.7/site-packages/django/db/migrations/loader.py", line 49, in __init__
python | self.build_graph()
python | File "/usr/local/lib/python3.7/site-packages/django/db/migrations/loader.py", line 212, in build_graph
python | self.applied_migrations = recorder.applied_migrations()
python | File "/usr/local/lib/python3.7/site-packages/django/db/migrations/recorder.py", line 73, in applied_migrations
python | if self.has_table():
python | File "/usr/local/lib/python3.7/site-packages/django/db/migrations/recorder.py", line 56, in has_table
python | return self.Migration._meta.db_table in self.connection.introspection.table_names(self.connection.cursor())
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 256, in cursor
python | return self._cursor()
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 233, in _cursor
python | self.ensure_connection()
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 217, in ensure_connection
python | self.connect()
python | File "/usr/local/lib/python3.7/site-packages/django/db/utils.py", line 89, in __exit__
python | raise dj_exc_value.with_traceback(traceback) from exc_value
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 217, in ensure_connection
python | self.connect()
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/base/base.py", line 195, in connect
python | self.connection = self.get_new_connection(conn_params)
python | File "/usr/local/lib/python3.7/site-packages/django/db/backends/postgresql/base.py", line 178, in get_new_connection
python | connection = Database.connect(**conn_params)
python | File "/usr/local/lib/python3.7/site-packages/psycopg2/__init__.py", line 127, in connect
python | conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
python | django.db.utils.OperationalError: could not connect to server: Connection refused
python | Is the server running on host "db" (192.168.160.2) and accepting
python | TCP/IP connections on port 5432?
python |
python |
db_1 | done
db_1 | server started
db_1 | CREATE DATABASE
db_1 |
db_1 |
db_1 | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
db_1 |
db_1 | waiting for server to shut down...LOG: received fast shutdown request
db_1 | LOG: aborting any active transactions
db_1 | LOG: autovacuum launcher shutting down
db_1 | .LOG: shutting down
db_1 | LOG: database system is shut down
db_1 | done
db_1 | server stopped
db_1 |
db_1 | PostgreSQL init process complete; ready for start up.
db_1 |
db_1 | LOG: database system was shut down at 2020-04-12 14:17:13 UTC
db_1 | LOG: MultiXact member wraparound protections are now enabled
db_1 | LOG: database system is ready to accept connections
db_1 | LOG: autovacuum launcher started
As you can see, django container starts up in he middle of the postgres setup, and it fails to connect. If I just restart the django container (another thing, even if the runserver command failed, docker container does not think that was an error and continues working without restarting - thats I think understandable because it launches itself with StatReloader) it works of course, but I would be happy if I could have an application running from the first launch, not to restart it on purpose...
Is there anyway to prevent this from happening? Have I made any mistake here, or maybe should I take another approach on that?
Thanks in advance.