1

I'm having problems getting two Docker containers to talk to each other using Docker Compose. In an attempt to reduce the problem down to the smallest reproducible example, I have created the following three files:

docker-compose.yml

services:
  db:
    build: webSQL
    ports:
      - "3000:3000"
  client-test:
    build: clientTest

webSQL/Dockerfile

FROM ubuntu

RUN apt update

RUN apt install netcat-traditional

RUN nc -l 3000

clientTest/Dockerfile

FROM ubuntu

RUN apt update

RUN apt install curl -y

RUN curl -X "hello" http://db:3000

When I run docker-compose up in the directory containing the docker-compose.yml file, I get the following output:

[+] Building 4.1s (11/11) FINISHED                                                                       docker:default
 => [client-test internal] load build definition from Dockerfile                                                   0.0s
 => => transferring dockerfile: 131B                                                                               0.0s
 => [db internal] load metadata for docker.io/library/ubuntu:latest                                                0.0s
 => [client-test internal] load .dockerignore                                                                      0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [db internal] load build definition from Dockerfile                                                            0.0s
 => => transferring dockerfile: 122B                                                                               0.0s
 => [db 1/4] FROM docker.io/library/ubuntu:latest                                                                  0.0s
 => CACHED [db 2/4] RUN apt update                                                                                 0.0s
 => CACHED [client-test 3/4] RUN apt install curl -y                                                               0.0s
 => ERROR [client-test 4/4] RUN curl -X "hello" http://db:3000                                                     4.0s
 => [db internal] load .dockerignore                                                                               0.0s
 => => transferring context: 2B                                                                                    0.0s
 => CACHED [db 3/4] RUN apt install netcat-traditional                                                             0.0s
 => CANCELED [db 4/4] RUN nc -l 3000                                                                               4.0s
------
 > [client-test 4/4] RUN curl -X "hello" http://db:3000:
0.641   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
0.641                                  Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0curl: (6) Could not resolve host: db
------
failed to solve: process "/bin/sh -c curl -X \"hello\" http://db:3000" did not complete successfully: exit code: 6

My understanding of Docker Compose is that every container can automatically make requests to every other container in the same Docker Compose file. (Assuming you're not specifying different networks for the containers to run in) What am I doing wrong?

1
  • It could be that on startup, the db host isn't running yet, so it can't be resolved either. I guess if you start them separately with enough time in between, first db then client-test, it works. Declare dependencies and a proper healthcheck to make this more robust. Commented May 26, 2024 at 9:05

2 Answers 2

2

RUN statements are executed at build time. At build time, the Docker network isn't available and you can't connect to other containers.

The Docker network is set up at run-time and it's at that time that containers can connect to each other.

To specify a command that runs at run-time, you use the ENTRYPOINT statement in connection with the CMD statement.

When you have containers that depend on other containers, you can specify that relationship in depends_on statements in your Docker Compose file. Note that depends_on only waits for the containers to be started. Not for the containers to be ready for connections. Often containers like databases do some work at startup and are not immediately available for connections.

To fix your setup, we can add depends_on to your compose file

services:

  db:
    build: webSQL
    ports:
      - "3000:3000"
  client-test:
    build: clientTest
    depends_on:
      - db

And your db Dockerfile

FROM ubuntu

RUN apt update

RUN apt install netcat-traditional

CMD nc -l 3000

And your clientTest Dockerfile

FROM ubuntu

RUN apt update

RUN apt install curl -y

CMD curl -X "hello" http://db:3000
Sign up to request clarification or add additional context in comments.

3 Comments

That makes a lot of sense to me. However, have you actually tried your proposed fix? I tried it, and it's still not working, although it's at least failing with a different error. Now I get "client-test-1 | curl: (7) Failed to connect to db port 3000 after 1 ms: Couldn't connect to server client-test-1 exited with code 7"
Yes, I've tried it to verify that it could resolve the host which was what your question was about. If you have a new, different, issue, you should create a new question.
But for what it's worth, your nc command seems to be wrong. I got it to work with nc -l -p 3000. Without -p it complains that it doesn't understand 3000 and listens on a random port instead. I also changed -X to -d on the curl command.
1

You're trying to RUN the two commands that involve the network as part of the image build. During the build sequence you can't connect to other containers at all.

If you change these to CMD

CMD nc -l 3000
CMD curl -X "hello" http://db:3000

then they will run as the main container commands when Compose starts the containers. At that point they will be connected to a common network and this setup should work (up to the point where you can't type the HTTP response into nc).

In the example you've named the server container db. The most common implication of this setup is that you can't run database migrations or seed data during an image build. Typical setups use an entrypoint wrapper script to run migrations on every startup, or else manually docker-compose run the migrations. How do you perform Django database migrations when using Docker-Compose? has examples of both techniques.

Comments

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.