Docker Community Forums

Share and learn in the Docker community.

How to make a client and server communicate with each other in a user defined network in docker?

I have a basic client server program written in python which I have containerized using docker. In this program, I want the client to request to the server to display a html file on the client. In one container, I have the client and in another the server. I want these containers to communicate in a user defined docker network and with that have the client communicate with the server. I have tried all the basic stuff but still unable to do get a solution. I’ll be attaching the codes too. Can one someone please help me out with the appropriate solution ?

Here is the code for client.py along with the respective dockerfile

import urllib.request
fp = urllib.request.urlopen("http://localhost:9000/")

encodedContent = fp.read()
decodedContent = encodedContent.decode("utf8")

print(decodedContent)

# Close the server connection.
fp.close()

Now, the dockerfile

 FROM python:alpine3.10
 COPY client.py /client/

 WORKDIR /client/

 CMD python ./client.py

Here is the code for server.py along with the respective dockerfile

import http.server
import socketserver

handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", 9000), handler) as httpd:
# This instruction will keep the server running, waiting for requests from the client.
      httpd.serve_forever()

Now, the dockerfile

FROM python:alpine3.10
WORKDIR /server/
EXPOSE 9000
COPY server.py /server/
COPY index.html /server/
CMD python ./server.py

Just start them from a compose file, then you get this network automatically.

In this example, you start two different alpine containers on the same Docker host and do some tests to understand how they communicate with each other. You need to have Docker installed and running.

Open a terminal window. List current networks before you do anything else. Here’s what you should see if you’ve never added a network or initialized a swarm on this Docker daemon. You may see different networks, but you should at least see these (the network IDs will be different):

$ docker network ls

NETWORK ID NAME DRIVER SCOPE
17e324f45964 bridge bridge local
6ed54d316334 host host local
7092879f2cc8 none null local
The default bridge network is listed, along with host and none. The latter two are not fully-fledged networks, but are used to start a container connected directly to the Docker daemon host’s networking stack, or to start a container with no network devices. This tutorial will connect two containers to the bridge network.

Start two alpine containers running ash, which is Alpine’s default shell rather than bash. The -dit flags mean to start the container detached (in the background), interactive (with the ability to type into it), and with a TTY (so you can see the input and output). Since you are starting it detached, you won’t be connected to the container right away. Instead, the container’s ID will be printed. Because you have not specified any --network flags, the containers connect to the default bridge network.

$ docker run -dit --name alpine1 alpine ash

$ docker run -dit --name alpine2 alpine ash
Check that both containers are actually started:

$ docker container ls

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
602dbf1edc81 alpine “ash” 4 seconds ago Up 3 seconds alpine2
da33b7aa74b0 alpine “ash” 17 seconds ago Up 16 seconds alpine1
Inspect the bridge network to see what containers are connected to it.

$ docker network inspect bridge

[
{
“Name”: “bridge”,
“Id”: “17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10”,
“Created”: “2017-06-22T20:27:43.826654485Z”,
“Scope”: “local”,
“Driver”: “bridge”,
“EnableIPv6”: false,
“IPAM”: {
“Driver”: “default”,
“Options”: null,
“Config”: [
{
“Subnet”: “172.17.0.0/16”,
“Gateway”: “172.17.0.1”
}
]
},
“Internal”: false,
“Attachable”: false,
“Containers”: {
“602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c”: {
“Name”: “alpine2”,
“EndpointID”: “03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd”,
“MacAddress”: “02:42:ac:11:00:03”,
“IPv4Address”: “172.17.0.3/16”,
“IPv6Address”: “”
},
“da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168”: {
“Name”: “alpine1”,
“EndpointID”: “46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5”,
“MacAddress”: “02:42:ac:11:00:02”,
“IPv4Address”: “172.17.0.2/16”,
“IPv6Address”: “”
}
},
“Options”: {
“com.docker.network.bridge.default_bridge”: “true”,
“com.docker.network.bridge.enable_icc”: “true”,
“com.docker.network.bridge.enable_ip_masquerade”: “true”,
“com.docker.network.bridge.host_binding_ipv4”: “0.0.0.0”,
“com.docker.network.bridge.name”: “docker0”,
“com.docker.network.driver.mtu”: “1500”
},
“Labels”: {}
}
]
Near the top, information about the bridge network is listed, including the IP address of the gateway between the Docker host and the bridge network (172.17.0.1). Under the Containers key, each connected container is listed, along with information about its IP address (172.17.0.2 for alpine1 and 172.17.0.3 for alpine2).

The containers are running in the background. Use the docker attach command to connect to alpine1.

$ docker attach alpine1

/ #
The prompt changes to # to indicate that you are the root user within the container. Use the ip addr show command to show the network interfaces for alpine1 as they look from within the container:

ip addr show

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
The first interface is the loopback device. Ignore it for now. Notice that the second interface has the IP address 172.17.0.2, which is the same address shown for alpine1 in the previous step.

From within alpine1, make sure you can connect to the internet by pinging google.com. The -c 2 flag limits the command to two ping attempts.

ping -c 2 google.com

PING google.com (172.217.3.174): 56 data bytes
64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.841 ms
64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.897 ms

google.com ping statistics —
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 9.841/9.869/9.897 ms
Now try to ping the second container. First, ping it by its IP address, 172.17.0.3:

ping -c 2 172.17.0.3

PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms

— 172.17.0.3 ping statistics —
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.086/0.090/0.094 ms
This succeeds. Next, try pinging the alpine2 container by container name. This will fail.

ping -c 2 alpine2

ping: bad address ‘alpine2’
Detach from alpine1 without stopping it by using the detach sequence, CTRL + p CTRL + q (hold down CTRL and type p followed by q). If you wish, attach to alpine2 and repeat steps 4, 5, and 6 there, substituting alpine1 for alpine2.

Stop and remove both containers.

docker container stop alpine1 alpine2 docker container rm alpine1 alpine2

I did that and still not working.

Thank you for the response but I tried something like this too. It didn’t work.

Please show your compose file, otherwise it’s very difficult to help you. And don’t waste your time with answers to L95, he’s a bot.

I don’t want to do it using docker compose initially as I am just an amateur. I want to accomplish it using docker run and then docker compose. So, if you don’t mind, can you help me with that ? By the way, whenever I am running these containers in a user-defined network, I am getting two errors: OSError: [Errno 99] Address not available and urllib.error.URLError: <urlopen error [Errno 99] Address not available>.

Oh Okay. Didn’t know L95 was a bot

docker compose makes everything 10 times easier, especially because it sets up all the network stuff and name resolving for you.

Thanks for your help but I got the solution. In the client.py, I just had to replace localhost with the name of the server container.
I have another program which I am facing problem towards. Here is the link: https://stackoverflow.com/questions/65344980/download-file-from-server-container-to-client-container-in-docker

Can you please help me out with the solution to this ?