docker container networking to connect localhost in one container to another - docker

I am using the default bridge network for docker (and yes, I am relatively new to docker). I have two docker containers.
The first container provides a service on port 12345. When creating this container, I did not specify the --publish option because I did not want to expose this port to the outside world.
The second container needs to use the service from the first container. However, the application running in this second container was hardcoded to access the service at 127.0.0.1:12345. Clearly, the second container's localhost is not the same as the first container. Is there a way to course docker networking to think that localhost in the second container should actually be connected to the port in the first container, without exposing anything to the outside world?

Option N: (this works but may not be the best solution)
One way you can force this to behave the way you need is through injecting an additional service to bind to the port within on the application container and redirecting it outward.
socat TCP-LISTEN:12345,fork TCP:172.18.0.2:12345
A quick test here, I was able to confirm 127.0.0.1:12345 is treated as the remote 12345
Things to consider:
The two containers needs to be able to reach each other
It breaks the recommendation of one service per container.
Getting the app into the docker container. (yum / apt-get install socat, source build = ?)
Getting it to run on startup on container start/restart.

Related

Docker cannot access exposed port inside container

I have a container for which I expose my port to access a service running within the container. I am not exposing my ports outside the container i.e. to the host (using host network on mac). On getting inside the container using exec -t and running a curl for a post request, I get the error:
curl command: curl http://localhost:19999
Failed connect to localhost:19999; Connection refused.
I have the expose command in my dockerfile and do not want to expose ports to my host. My service is also up and running inside the container. I also have the property within config set as
"ExposedPorts": {"19999/tcp": {}}
(obtained through `docker inspect <container id/name>\ Any idea on why this is not working? Using docker for Mac
I'd post my docker-compose file too but this is being built through maven. I can ensure that I am exposing my port using 19999:19999. Another weird issue is that on disabling my proxies it would run a very light weight command for my custom service and wouldn't run it again returning the same error as above. The issue only occurs on my machine and not others
Hints:
The app must be listening on port 19999 which is probably not.
The EXPOSE that you're using inside the Dockerfile does nothing.
Usually there is no need to change the default port on which an application is listening, hence each container has its own IP and you shouldn't run in a port conflict.
Answer:
Instead of curling 19999 try to use the default port on which your app would normally be listening to(it's hard to guess what you are trying to run).
If you don't publish a port (with the docker run -p option or the Docker Compose ports: option), you cannot directly reach the container on Docker for Mac. See the Known limitations, use cases, and workarounds in the Docker Desktop for Mac documentation: the "per-container IP addressing is not possible" item ism what you're trying to attempt.
The docker inspect IP address is basically useless, except in one very specific Docker configuration (on a native-Linux host, calling from outside of Docker, on the same host); I wouldn't bother looking it up.
The Dockerfile EXPOSE directive and similar runtime options do very little and mostly serve as documentation. Even if you have that configured you still need to separately publish the port when you start the container to reach it from outside of Docker space.

How to connect to docker host?

I'm a bit confused about "what" a docker host is and how is it different from my system in itself.
I did the following,
docker run jenkins
/* in a new tab */
docker ps // to get the container id
docker inspect {container-id} // to get the IP
From what I understand the only way I can connect to the container's IP is from within the docker host (if I don't port map that is) - so how do I connect to the host?
I know I can bash into the container and curl the IP I got from inspect, but that's not the same as connecting to the docker host, is it?
The way you are using the term "docker host" here makes it sound like you are using the term to refer to the container itself. (You might also be referring to the physical machine which the container is running on).
You can think of the container as basically a very lightweight VM -- it has its own filesystem, network, possibly CPU and RAM resources, etc. So, without configuring the network, the container will be isolated. This analogy isn't perfect for any number of reasons, but its pretty close to what is going on.
Put another way, without port mapping (or "host networking", see this page for more details about docker networking), you can, as you discovered, only access the network within the container unless you map the ports (or, perhaps, are inside of a different container which is connected to the same bridge network).
In this case, you are probably just best off mapping the port so that you can access the service running inside the container.

Understanding why ports need to be exposed for inter container communication on docker0

I was going through docker official docs to understand the difference between user-defined and default bridge. Link to specific page - https://docs.docker.com/network/bridge/
In first point of section "Differences between user-defined bridges and the default bridge", it is stated that
If you run the same application stack on the default bridge network,
you need to open both the web port and the database port, using the -p
or --publish flag for each.
I don't understand this specific text, as to why it is need to explicitly publish(-p) required port of database container when it will be used only by some other container connected to the same bridge.
My existing understanding is that, unless explicitly blocked, containers connected to the docker0 can freely communicate with each other.
So, this extract has confused me. Can somebody help ?
If you take away one thing from that page, it's that you should always docker create network and then docker run --net containers on that network, if you're using plain Docker commands. (Docker Compose does this automatically for you; Kubernetes's networking model is fundamentally different.)
If you docker run a container without a --net option then you wind up using a backwards-compatiblitiy networking mode. In this mode (the "default bridge network") from the page you cite containers cannot communicate with each other by default. Your two options are for the server to publish a port (docker run -p) and the client to connect to the published port on the host, or for the server to expose a port (almost always done with an EXPOSE directive in the Dockerfile) and the client to --link to it.
There's no real reason to be using this "default" mode at this point, and in practice the paragraph you cite shouldn't matter except for fairly old scripted Docker setups.

How to obtain the published ports from within a docker container?

I wrote a simple peer to peer system, in which, when starting a node
the node looks for a free port and then makes its service accessible on that port,
it registers its URL including the port to a central server, so that other nodes know how to connect to it.
I have the impression this is a typical kind of task that docker is useful for, so I thought of making a container for these peers (my previous experience with docker has only been to write a hello world container).
Ideally I would map (publish) my exposed port to a host port from within the container using the same code that I am running now, but I could imagine that is simply not possible, and I could get around that by starting the image using a script that checks for availability of ports and then runs the container on an appropriate free host port. If the first is possible however, that would be even better. To be explicit, I do something like the following in Python
port = 5001
while not port_is_free(port):
port += 1
The second part really has to be taken care of from within the container. Assume that it has been started with the command docker run -p 5005:80 p2p-node then I need to find out the published port 5005 that the exposed port 80 is mapped to from within the container.
Searching this site and the internet it looks like more people are interested in doing the same, but I couldn't find a solution, nor an affirmation that this simply cannot be done.
So this is the main question I want to ask: how can I see which published ports my exposed ports are mapped to from within a running docker container?
Some of your requirements are not clear to me.
However if you want to know only which host port is mapped with your container's port, you can simply pass an environment variable, -e VAR=val. Just an idea
Start container:
docker run -p 5005:80 -e HOST_PORT=5005 p2p-node
Access the variable from container
echo $HOST_PORT
there is docker-py, a python library of docker.
It is not clear why you want the host port. In docker, containers can communicate with each other without having to expose ports on host machines.
As long as the peer apps are containerized, you don't need the expose port. The containers can be connected via a Docker network and the internal port can be used for communication between the containers.

Inter-container connection via localhost

I would like to set up my containers so that they connect to each other via localhost.
My setup is a main application container and two other containers that it needs to connect to (ActiveMQ and Wiremock).
I already run ActiveMQ and Wiremock in containers with the relevant ports exposed, and the main application runs through IntelliJ and connects to these. However, when I am not developing the main applications, I would like to run it in a container for simplicity but it cannot connect to the ports exposed by the others.
Setting --net=host doesn't seem to work, nor does creating a network docker network create <NAME> and assigning it in the docker run with --net=<NAME>.
The application already runs in a container in other environments on the host network.
docker creates a default network in which all containers run, and sets a network name for each of your containers, using the container name.
if you have a contained named mq for your ActiveMQ, then you would use something like tcp://mq:61616 (or whatever protocol / port you have configured) from your other containers, to connect to it.
you shouldn't need to set the --net option unless you need to create a specific network for specific containers to use.

Resources