7

I have 2 docker containers running on my Mac host - container 1 is Jenkins from Docker Hub and container 2 is SonarQube from Docker Hub. I have both containers running successfully. I can access Jenkins from my host by going to http://localhost:8080/ and I can access my SonarQube by going to http://localhost:9000/.

The Jenkins container was started like this:

docker run -d -p 8080:8080 -p 50000:50000 jenkins/jenkins:latest

The SonarQube container was started like this:

docker run -d -p 9000:9000 sonarqube

Now I want to have each container communicate with each other so I need to provide the IP address of the other container to each container.

I got the IP address of each container by executing this:

docker inspect --format '{{ .NetworkSettings.IPAddress }}' container_name_or_id

This returns an IP address of 172.17.0.2 for the Jenkins container and 172.17.0.3 for the SonarQube container. But when I try and access the Jenkins container from my host by going to http://172.17.0.2:8080 I get a request timeout. The same thing happens when I try and access the SonarQube container from my host by going to http://172.17.0.3:9000

Is this normal behavior?

Shouldn't I be able to access each container from my host by their internal IP address?

And how can I test that one container (e.g. Jenkins) can access the other container (e.g. SonarQube) by IP address?

gomisha
  • 2,587
  • 3
  • 25
  • 33

3 Answers3

3

Is this normal behavior? Shouldn't I be able to access each container from my host by their internal IP address?

What you describe is normal behavior: you can't directly reach the Docker-internal IP addresses from a MacOS host. See "Per-container IP addressing is not possible" in the Docker for Mac docs.

How can I test that one container (e.g. Jenkins) can access the other container (e.g. SonarQube) by IP address?

This isn't something I normally "test" per se. Start up both processes and have them make their normal (HTTP) connections; if it works you'll see appropriate log messages, and if it doesn't work you'll see complaints. (Getting a root shell in a container to send ICMP packets from one container to another seems to be a popular option but doesn't prove much.)

Also: don't make this connection by explicit IP address. As you've noticed already the Docker-internal IP addresses aren't usable in some contexts, and they'll change whenever you restart containers. Instead, Docker provides an internal DNS service that can resolve host names when communicating between containers, but you need to explicitly set up a non-default bridge network. That setup would look like:

docker network create jenkinsnet
docker run --name sonarqube -d --net jenkinsnet \
  -p 9000:9000 \
  sonarqube
docker run --name jenkins -d --net jenkinsnet \
  -p 8080:8080 -p 50000:50000 \
  -e SONARQUBE_URL=http://sonarqube:9000 \
  jenkins/jenkins:latest

So I've explicitly created a network; started both containers connected to it; and told the client container (via an environment variable) where the server container is. You don't have to publish ports with docker run -p to reach them this way; whether you do or not, use the port the server process is listening on (the second port number in the docker run -p option).

From the host, your only (portable, reliable) path to reach the container is via its published ports.

David Maze
  • 130,717
  • 29
  • 175
  • 215
  • 1
    Your solution is a lot more elegant, but I realized that I can just use the IP of my host as the address of the other container. So when I do `ifconfig` on my host and see that my IP is `192.168.0.14`, I set the Sonar address in the Jenkins container as `192.168.0.14:9000` and in the Sonar container, I set the Jenkins address as `192.168.0.14:8080`. I will have to update these IPs since my host IP can change, but it's good enough for what I need. – gomisha Jan 04 '19 at 12:26
2

Looks like you are using default bridge network model. Internal IPs are meant for each container to talk to each other under bridge networking. You cannot access them from host.

There are multiple options for you.

  1. You can configure http://172.17.0.3:9000 as your sonar endpoint in Jenkins.
  2. You can configure http://172.17.0.2:8000 as your jenkins endpoint in sonar.
  3. If you don't want to hard code above Ips then both of your containers can talk to each using Docker Default GatewayIp(172.17.0.1) and their internal port. so essentially you can configure http://172.17.0.1 as well.

Note - Default Gateway Ip change change if you define user defined bridge network.

https://docs.docker.com/v17.09/engine/userguide/networking/#the-default-bridge-network

https://docs.docker.com/network/network-tutorial-standalone/

If you want to spin up both containers using docker-compose, then you can link both containers using service name. Just follow Networking in Compose.

Imran
  • 5,542
  • 3
  • 23
  • 46
  • I realized that I can just use the IP of my host as the address of the other container. So when I do `ifconfig` on my host and see that my IP is `192.168.0.14`, I set the Sonar address in the Jenkins container as `192.168.0.14:9000` and in the Sonar container, I set the Jenkins address as `192.168.0.14:8080`. I will have to update these IPs since my host IP can change, but it's good enough for what I need. – gomisha Jan 04 '19 at 12:25
  • 1
    @gomisha Yes. you can use host IP. In a typical DevOps environment, I try to use `docker-compose` to bring both containers linked each other so they can talk just using service name and port without hard coding IPs or using host Ip. – Imran Jan 04 '19 at 22:04
2

The accepted answer (https://stackoverflow.com/a/53992787/7730554) already provides valid options of which I personally usually prefer using docker compose.

But as you are running Docker on Mac you could also use host.docker.internal in combination with the defined forwarding host port. So Docker will take care that host.docker.internal is resolved to the corresponding IP even if your Host IP changes.

See https://docs.docker.com/desktop/mac/networking/. Note that this is for development mode only and works when you use Docker Desktop.

Andreas Hütter
  • 3,288
  • 1
  • 11
  • 19
  • Can you show an example or link to the documentation? I guess that host.docker.internal is a path in the docker-compose but from your description I can't determent how the setting should look. – Markus Madeja Nov 05 '21 at 13:21
  • I added the reference to my answer. When using Docker Desktop you can simply connect to host.docker.internal as hostname from within a container to the host machine and Docker will take care it is resolved to the current IP of your host machine. – Andreas Hütter Nov 05 '21 at 17:28