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?
2
Answers
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
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 manuallydocker-compose run
the migrations. How do you perform Django database migrations when using Docker-Compose? has examples of both techniques.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 theCMD
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 thatdepends_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 fileAnd your db Dockerfile
And your clientTest Dockerfile