0

Here's the current docker-compose.yml

version: '3' services: db: image: postgres environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_DB=my_app ports: - '5432:5432' web: build: . image: my-app ports: - "8000:8000" depends_on: - db command: sh -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" volumes: - .:/code environment: - DB_USER=postgres - DB_PASSWORD=postgres - DB_HOST=db - DB_NAME=my_app 

When I run the app for the first time, this happens:

% docker compose build && docker compose up [+] Building 2.5s (10/10) FINISHED => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 189B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 150B 0.0s => [internal] load metadata for docker.io/library/python:3.11.1-bullseye 2.0s => [1/5] FROM docker.io/library/python:3.11.1-bullseye@sha256:cc4910af48 0.0s => [internal] load build context 0.2s => => transferring context: 1.21MB 0.2s => CACHED [2/5] COPY requirements.txt requirements.txt 0.0s => CACHED [3/5] RUN pip install -r requirements.txt 0.0s => CACHED [4/5] COPY . /app 0.0s => CACHED [5/5] WORKDIR /app 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:d7b4a64b01b9de03dec4a0732eaf975b7bc68f1daefb4 0.0s => => naming to docker.io/library/my-app 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them [+] Running 3/3 ⠿ Network my_app_default Created 0.2s ⠿ Container my_app-db-1 Created 0.1s ⠿ Container my_app-web-1 Created 0.2s Attaching to my_app-db-1, my_app-web-1 my_app-db-1 | The files belonging to this database system will be owned by user "postgres". my_app-db-1 | This user must also own the server process. my_app-db-1 | my_app-db-1 | The database cluster will be initialized with locale "en_US.utf8". my_app-db-1 | The default database encoding has accordingly been set to "UTF8". my_app-db-1 | The default text search configuration will be set to "english". my_app-db-1 | my_app-db-1 | Data page checksums are disabled. my_app-db-1 | my_app-db-1 | fixing permissions on existing directory /var/lib/postgresql/data ... ok my_app-db-1 | creating subdirectories ... ok my_app-db-1 | selecting dynamic shared memory implementation ... posix my_app-db-1 | selecting default max_connections ... 100 my_app-db-1 | selecting default shared_buffers ... 128MB my_app-db-1 | selecting default time zone ... Etc/UTC my_app-db-1 | creating configuration files ... ok my_app-db-1 | running bootstrap script ... ok my_app-db-1 | performing post-bootstrap initialization ... ok my_app-db-1 | syncing data to disk ... ok my_app-db-1 | my_app-db-1 | my_app-db-1 | Success. You can now start the database server using: my_app-db-1 | my_app-db-1 | pg_ctl -D /var/lib/postgresql/data -l logfile start my_app-db-1 | my_app-db-1 | initdb: warning: enabling "trust" authentication for local connections my_app-db-1 | initdb: hint: You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. my_app-web-1 | Traceback (most recent call last): my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 282, in ensure_connection my_app-web-1 | self.connect() my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner my_app-web-1 | return func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 263, in connect my_app-web-1 | self.connection = self.get_new_connection(conn_params) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner my_app-web-1 | return func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/postgresql/base.py", line 215, in get_new_connection my_app-web-1 | connection = Database.connect(**conn_params) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/psycopg2/__init__.py", line 122, in connect my_app-web-1 | conn = _connect(dsn, connection_factory=connection_factory, **kwasync) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | psycopg2.OperationalError: could not connect to server: Connection refused my_app-web-1 | Is the server running on host "db" (172.24.0.2) and accepting my_app-web-1 | TCP/IP connections on port 5432? my_app-web-1 | my_app-web-1 | my_app-web-1 | The above exception was the direct cause of the following exception: my_app-web-1 | my_app-web-1 | Traceback (most recent call last): my_app-web-1 | File "/app/manage.py", line 22, in <module> my_app-web-1 | main() my_app-web-1 | File "/app/manage.py", line 18, in main my_app-web-1 | execute_from_command_line(sys.argv) my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line my_app-web-1 | utility.execute() my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/core/management/__init__.py", line 440, in execute my_app-web-1 | self.fetch_command(subcommand).run_from_argv(self.argv) my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 402, in run_from_argv my_app-web-1 | self.execute(*args, **cmd_options) my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 448, in execute my_app-web-1 | output = self.handle(*args, **options) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/core/management/base.py", line 96, in wrapped my_app-web-1 | res = handle_func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/core/management/commands/migrate.py", line 114, in handle my_app-web-1 | executor = MigrationExecutor(connection, self.migration_progress_callback) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/migrations/executor.py", line 18, in __init__ my_app-web-1 | self.loader = MigrationLoader(self.connection) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/migrations/loader.py", line 58, in __init__ my_app-web-1 | self.build_graph() my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/migrations/loader.py", line 235, in build_graph my_app-web-1 | self.applied_migrations = recorder.applied_migrations() my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/migrations/recorder.py", line 81, in applied_migrations my_app-web-1 | if self.has_table(): my_app-web-1 | ^^^^^^^^^^^^^^^^ my_app-db-1 | waiting for server to start....2023-01-08 12:43:30.440 UTC [47] LOG: starting PostgreSQL 15.1 (Debian 15.1-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/migrations/recorder.py", line 57, in has_table my_app-web-1 | with self.connection.cursor() as cursor: my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner my_app-web-1 | return func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 323, in cursor my_app-web-1 | return self._cursor() my_app-web-1 | ^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 299, in _cursor my_app-web-1 | self.ensure_connection() my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner my_app-web-1 | return func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 281, in ensure_connection my_app-web-1 | with self.wrap_database_errors: my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__ my_app-web-1 | raise dj_exc_value.with_traceback(traceback) from exc_value my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 282, in ensure_connection my_app-web-1 | self.connect() my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner my_app-web-1 | return func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/base/base.py", line 263, in connect my_app-web-1 | self.connection = self.get_new_connection(conn_params) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/utils/asyncio.py", line 26, in inner my_app-web-1 | return func(*args, **kwargs) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/postgresql/base.py", line 215, in get_new_connection my_app-web-1 | connection = Database.connect(**conn_params) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-web-1 | File "/usr/local/lib/python3.11/site-packages/psycopg2/__init__.py", line 122, in connect my_app-web-1 | conn = _connect(dsn, connection_factory=connection_factory, **kwasync) my_app-web-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ my_app-db-1 | 2023-01-08 12:43:30.457 UTC [47] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" my_app-web-1 | django.db.utils.OperationalError: could not connect to server: Connection refused my_app-web-1 | Is the server running on host "db" (172.24.0.2) and accepting my_app-web-1 | TCP/IP connections on port 5432? my_app-web-1 | my_app-db-1 | 2023-01-08 12:43:30.476 UTC [50] LOG: database system was shut down at 2023-01-08 12:43:29 UTC my_app-db-1 | 2023-01-08 12:43:30.490 UTC [47] LOG: database system is ready to accept connections my_app-db-1 | done my_app-db-1 | server started my_app-db-1 | CREATE DATABASE my_app-db-1 | my_app-db-1 | my_app-db-1 | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* my_app-db-1 | my_app-web-1 exited with code 1 my_app-db-1 | 2023-01-08 12:43:31.286 UTC [47] LOG: received fast shutdown request my_app-db-1 | waiting for server to shut down....2023-01-08 12:43:31.288 UTC [47] LOG: aborting any active transactions my_app-db-1 | 2023-01-08 12:43:31.319 UTC [47] LOG: background worker "logical replication launcher" (PID 53) exited with exit code 1 my_app-db-1 | 2023-01-08 12:43:31.320 UTC [48] LOG: shutting down my_app-db-1 | 2023-01-08 12:43:31.326 UTC [48] LOG: checkpoint starting: shutdown immediate my_app-db-1 | 2023-01-08 12:43:31.469 UTC [48] LOG: checkpoint complete: wrote 918 buffers (5.6%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.054 s, sync=0.076 s, total=0.149 s; sync files=250, longest=0.023 s, average=0.001 s; distance=4217 kB, estimate=4217 kB my_app-db-1 | 2023-01-08 12:43:31.488 UTC [47] LOG: database system is shut down my_app-db-1 | done my_app-db-1 | server stopped my_app-db-1 | my_app-db-1 | PostgreSQL init process complete; ready for start up. my_app-db-1 | my_app-db-1 | 2023-01-08 12:43:31.692 UTC [1] LOG: starting PostgreSQL 15.1 (Debian 15.1-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit my_app-db-1 | 2023-01-08 12:43:31.695 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 my_app-db-1 | 2023-01-08 12:43:31.695 UTC [1] LOG: listening on IPv6 address "::", port 5432 my_app-db-1 | 2023-01-08 12:43:31.701 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" my_app-db-1 | 2023-01-08 12:43:31.708 UTC [63] LOG: database system was shut down at 2023-01-08 12:43:31 UTC my_app-db-1 | 2023-01-08 12:43:31.720 UTC [1] LOG: database system is ready to accept connections 

It fails to connect to db because the service hasn't started yet depite being specified as a dependency. Here's the 2nd time:

% docker compose build && docker compose up [+] Building 4.8s (11/11) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 32B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 34B 0.0s => [internal] load metadata for docker.io/library/python:3.11.1-bullseye 4.2s => [auth] library/python:pull token for registry-1.docker.io 0.0s => [1/5] FROM docker.io/library/python:3.11.1-bullseye@sha256:cc4910af48 0.0s => [internal] load build context 0.1s => => transferring context: 8.42kB 0.1s => CACHED [2/5] COPY requirements.txt requirements.txt 0.0s => CACHED [3/5] RUN pip install -r requirements.txt 0.0s => CACHED [4/5] COPY . /app 0.0s => CACHED [5/5] WORKDIR /app 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:d7b4a64b01b9de03dec4a0732eaf975b7bc68f1daefb4 0.0s => => naming to docker.io/library/my-app 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them [+] Running 2/0 ⠿ Container my_app-db-1 Created 0.0s ⠿ Container my_app-web-1 Created 0.0s Attaching to my_app-db-1, my_app-web-1 my_app-db-1 | my_app-db-1 | PostgreSQL Database directory appears to contain a database; Skipping initialization my_app-db-1 | my_app-db-1 | 2023-01-08 12:48:54.148 UTC [1] LOG: starting PostgreSQL 15.1 (Debian 15.1-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit my_app-db-1 | 2023-01-08 12:48:54.152 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 my_app-db-1 | 2023-01-08 12:48:54.153 UTC [1] LOG: listening on IPv6 address "::", port 5432 my_app-db-1 | 2023-01-08 12:48:54.157 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" my_app-db-1 | 2023-01-08 12:48:54.171 UTC [28] LOG: database system was shut down at 2023-01-08 12:48:30 UTC my_app-db-1 | 2023-01-08 12:48:54.187 UTC [1] LOG: database system is ready to accept connections my_app-web-1 | Operations to perform: my_app-web-1 | Apply all migrations: admin, auth, contenttypes, core, sessions my_app-web-1 | Running migrations: my_app-web-1 | Applying contenttypes.0001_initial... OK my_app-web-1 | Applying auth.0001_initial... OK my_app-web-1 | Applying admin.0001_initial... OK my_app-web-1 | Applying admin.0002_logentry_remove_auto_add... OK my_app-web-1 | Applying admin.0003_logentry_add_action_flag_choices... OK my_app-web-1 | Applying contenttypes.0002_remove_content_type_name... OK my_app-web-1 | Applying auth.0002_alter_permission_name_max_length... OK my_app-web-1 | Applying auth.0003_alter_user_email_max_length... OK my_app-web-1 | Applying auth.0004_alter_user_username_opts... OK my_app-web-1 | Applying auth.0005_alter_user_last_login_null... OK my_app-web-1 | Applying auth.0006_require_contenttypes_0002... OK my_app-web-1 | Applying auth.0007_alter_validators_add_error_messages... OK my_app-web-1 | Applying auth.0008_alter_user_username_max_length... OK my_app-web-1 | Applying auth.0009_alter_user_last_name_max_length... OK my_app-web-1 | Applying auth.0010_alter_group_name_max_length... OK my_app-web-1 | Applying auth.0011_update_proxy_permissions... OK my_app-web-1 | Applying auth.0012_alter_user_first_name_max_length... OK my_app-web-1 | Applying sessions.0001_initial... OK my_app-web-1 | Watching for file changes with StatReloader my_app-web-1 | Performing system checks... my_app-web-1 | my_app-web-1 | System check identified no issues (0 silenced). my_app-web-1 | January 08, 2023 - 12:49:01 my_app-web-1 | Django version 4.1.5, using settings 'my_app.settings' my_app-web-1 | Starting development server at http://0.0.0.0:8000/ my_app-web-1 | Quit the server with CONTROL-C. 

It runs as it should've had in the first time.

0

1 Answer 1

3

According to the docker compose documentation, depends_on it does not wait until the service is ready, only that it has started. In my experience starting a postgres container usually takes a few seconds and since you need to wait until postgres is ready to recieve connections, it is recommended to use some form of control startup.

You could use the example Docker provides or do this yourself in Django, here is an example from a similar stackoverflow thread.

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

2 Comments

The whole point of having a startup order is to avoid these kinds of issues. I don't understand the difference between this and not specifying it as a dependency at all. Both lead to the same result, which makes it pretty useless.
I agree, it is mostly useless since the only thing you can be sure of using depends_on is that the service will get initiated first, not that it's ready. Only thing I can maybe think of is that it's a bit more explicit for people to read... maybe

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.