Accessing localhost inside the container itself

Hi,

I guess this is a very general question, but how do i access the localhost of the container itself?

I can ping the localhost which i guess is directed to the host, but telnet of localhost returns a connection refused.

If the answer is to use --network=host. The second problem that arises is that most of my test cases written in go for a library randomly timeout.

Client:
 Version:      17.06.2-ce
 API version:  1.30
 Go version:   go1.8.4
 Built:        Fri Nov 10 00:50:37 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.06.2-ce
 API version:  1.30 (minimum version 1.12)
 Go version:   go1.8.4
Built:        Fri Nov 10 00:51:08 2017
 OS/Arch:      linux/amd64
 Experimental: false

Environment is Jenkins master sending commands via JNLP to jenkins slave inside which the code is executed.

P.S. - The test cases run successfully on non dockerized environment

127.0.0.1 (and, I think, the IPv6 address ::1) access localhost of the container itself, which is to say, the container.

Right, your container probably isn’t running a telnet daemon.

If you mean you’re trying to access a service running on the physical host that the container happens to be running on, it’s essentially the same question as trying to access the Web-based admin console of your home router: it’s somewhere else on the network that definitely isn’t localhost. Depending on your specific environment the host is often 172.17.0.1, or else it’s 192.168.99.1, or maybe it’s something else. Some Docker variants have a dedicated DNS name for it too. The most portable path is to find the host system’s IP address (maybe the docker0 interface address) and pass that as a parameter into the container.

(That is: you’d do it the exact same way as you would otherwise in your Jenkins setup if the master and the slave were on different systems.)

Thanks for a quick reply. Let me provide more clarity on the question. When i exec into the container any connection I try to make to localhost, it returns a connection refused error. As for the telnet, it is installed, the connection refused error is thrown by it as well.

I run the below script as its a modified snippet of something that i am trying to do.

package main

import (
	"fmt"
	"net"
)

func main(){
	var hostPort string
	for openPort := 0; openPort < 10000; openPort++ {
		hostPort = fmt.Sprintf("localhost:%d", openPort)
		conn, err := net.Dial("tcp", hostPort)
		if err == nil {
			conn.Close()
			break
		}
		fmt.Println(err)
	}
}

I am not trying to access the service on physical host. Its a test case which tries to connect to localhost.

So how do i get localhost connection on the container itself?

Thanks in advance.

Typically containers run only a single process that is running a network service, and you probably know what port it’s on. If your container is running a Web server that’s listening on port 80, I’d expect a connect(2) call to localhost:80 to work, and absolutely everything else to return “connection refused”.

What behavior are you expecting?

When you say connect to localhost:80, you mean from the host machine or the container?

The behavior I am expecting is to find make a connection on localhost inside the container itself. I have exposed few ports e.g. 49000 but those are accessible by the host ip and not localhost on the container.

If I run it from the host, I expect to get whatever the host has running on port 80 (which could be a Docker container docker run -p 80:....). If I run it from the container, I expect to get whatever in the container is listening on port 80, which may or may not be exposed to the host (it might be on a different port on the host; docker run -p ...:80).

I’m still not clear what you mean by “localhost inside the container itself”. Since a container usually only runs one service, and it usually isn’t that valuable for a service to connect to itself, the usual meaning of 127.0.0.1 (“connect back to the same place I’m calling from”) isn’t very useful inside a Docker container. “Expose” has a specific meaning in Docker which also isn’t especially useful (it’s a declaration in an image that it runs a service that listens on a port, but doesn’t cause that port to actually be published).

If your container is running a service:

CMD ["/mydaemon", "-http", ":8080"]

and you publish it on a port:

sudo docker run --rm -p 49152:8080 --name test myimage

and you make an HTTP request from within the container, you’d use the port the daemon runs on within the container, not the port it’s published on from the host

host$ curl http://localhost:49152
host$ sudo docker exec test curl http://localhost:8080

Does that help? What is or isn’t working?

This returns connection refused.

Hi,

This is my first post and my English is not that good, so pls do not BASH me


I think you miss the point of “localhost”. As it always points to the actual LOCAL “machine” where it is called, it will try to curl the 8080 port of the container itself this way.

If you execute docker inspect test you can find a line like this “Gateway”: “172.17.0.1” this points to the base Docker network’s Gateway (represented by docker0 if you execute ifconfig).

So running docker exec test curl http://172.17.0.1:8080 will give you the page you are hosting on the machine where you run Docker.

And if you want to go deeper you can write a script like this inside the container:

#!/bin/bash
curl `route | awk ‘/^default/ { print $2 }’`:8080

Which will give you the same result if you run docker exec test ./path/of/script/script.sh from the host machine, except it will work with any IP, as route | awk ‘/^default/ { print $2 }’ translates to the default Gateway’s IP address.

I hope this helps


1 Like

github.com/qoomon/docker-host worked perfectly for me, tested with docker-compose.

3 Likes

Ugh, thank you - I’ve been “not getting this” for a while. This made perfect sense. Now, I see below I can “fix” this by using docker-host and docker compose. Is there another way to forward into the container itself (not the local machine) without using docker compose?