This site uses cookies to deliver our services and to show you relevant ads and job listings.
By using our site, you acknowledge that you have read and understand our Cookie Policy, Privacy Policy, and our Terms of Service.
Your use of Stack Overflow’s Products and Services, including the Stack Overflow Network, is subject to these policies and terms.

Join us in building a kind, collaborative learning community via our updated
Code of Conduct.

So I have a Nginx running inside a docker container, I have a mysql running on localhost, I want to connect to the MySql from within my Nginx. The MySql is running on localhost and not exposing a port to the outside world, so its bound on localhost, not bound on the ip address of the machine.

Is there any way to connect to this MySql or any other program on localhost from within this docker container?

docker run --net="host"

Alternatively you can run a docker container with network settings set to host. Such a container will share the network stack with the docker host and from the container point of view, localhost (or 127.0.0.1) will refer to the docker host.

Be aware that any port opened in your docker container would be opened on the docker host. And this without requiring the -p or -Pdocker run option.

As you can see both the docker host and docker container share the exact same network interface and as such have the same IP address.

Connecting to MySQL from containers

bridge mode

To access MySQL running on the docker host from containers in bridge mode, you need to make sure the MySQL service is listening for connections on the 172.17.42.1 IP address.

To do so, make sure you have either bind-address = 172.17.42.1 or bind-address = 0.0.0.0 in your MySQL config file (my.cnf).

If you need to set an environment variable with the IP address of the gateway, you can run the following code in a container :

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

then in your application, use the DOCKER_HOST_IP environment variable to open the connection to MySQL.

Note: if you use bind-address = 0.0.0.0 your MySQL server will listen for connections on all network interfaces. That means your MySQL server could be reached from the Internet ; make sure to setup firewall rules accordingly.

Note 2: if you use bind-address = 172.17.42.1 your MySQL server won't listen for connections made to 127.0.0.1. Processes running on the docker host that would want to connect to MySQL would have to use the 172.17.42.1 IP address.

host mode

To access MySQL running on the docker host from containers in host mode, you can keep bind-address = 127.0.0.1 in your MySQL configuration and all you need to do is to connect to 127.0.0.1 from your containers:

Thank you for such a detailed answer! From what I've gathered, using host mode is the only way to get this functionality through localhost. I haven't tried but I would assume you could create a separate network to connect containers over their own bridge offering them a common 'localhost'.
– BenMay 12 '15 at 5:45

brilliant and thanks, this worked for me from within the container. mysql -uroot -hdocker.for.mac.localhost
– Richard FrankJul 22 '17 at 5:46

1

docker.for.mac.localhost Is exactly what I was looking for. But this is dirty as hell at the same time. IN docker, one would expect that the hook docker.for.mac.localhost would be a generic docker internal name that would be valid for any operating system, not just for Mac. But for development purposes this is good enough.
– 99SonoDec 3 '17 at 15:06

How do I access a port which is exposed at say 9093.. I am trying to telnet docker.for.mac.localhost 9093 . Its unreachable but if I ping docker.for.mac.localhost , its reachable.Am i missing something here?
– Akhilanand Benkal VenkannaDec 19 '17 at 15:59

I doing a hack similar to above posts of get the local IP to map to a alias name (DNS) in the container. The major problem is to get dynamically with a simple script that works both in Linux and OSX the host IP address. I did this script that works in both environments (even in Linux distribution with "$LANG" != "en_*" configured):

Depending on your use case, you might even just get away with using the DOCKERHOST value here instead of "localhost" or 0.0.0.0 in whatever service your docker container needs to connect to locally.
– Elysian FieldsMar 15 '17 at 15:51

1

I have slightly modified your solution to be compatible with custom networks: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') Where <NETWORK-NAME> could be bridge or the name of the network as defined by docker-compose (usually path-name-network_name).
– dieresysApr 26 '17 at 17:09

1

You need to add a comment: use dockerhost as the host for db connection (usualy replace for localhost in config file).
– JustinJun 30 '17 at 11:12

This is a much cleaner solution, not exposing Mysql to the outside (if not using a firewall).
– user1226868Jun 6 '15 at 14:45

5

Sockets do not scale as well as TCP because they block more often and can cause weird behavior. Use TCP whenever possible.
– Joel E SalasJan 19 '16 at 21:54

2

@JoelESalas Do you have a source for that claim?
– PrivateOct 13 '16 at 9:21

I have found this to be the easiest solution. Thumbs up user833482! You should contribute more often to StackOverflow.
– PrivateOct 13 '16 at 10:32

1

@JoelESalas I think you're mistaken. The mysql client library even uses unix sockets by default when connecting to localhost rather than actually making a connection to localhost. A unix socket avoids the overhead of the TCP stack and routing, and should run faster.
– M ConradJan 11 '17 at 1:28

You deserve a medal! I've been working on this for two full days. Thank you for helping out!
– MichaelAug 3 '17 at 23:08

I was also working on this for two full days. This is the only place on the web I've found it mentioned. Microsoft is completely silent on this when it talks about connecting to MSSQL from within a Docker container. It makes you wonder if they ever got it working themselves!
– ContangoNov 2 '17 at 15:44

Secondly, for those of you who are using Linux (my direct experience was with Ubuntu 14.04 LTS and I'm upgrading to 16.04 LTS in production soon), yes, you can make the service running inside a Docker container connect to localhost services running on the Docker host (eg. your laptop).

How?

The key is when you run the Docker container, you have to run it with the host mode. The command looks like this:

docker run --network="host" -id <Docker image ID>

When you do an ifconfig (you will need to apt-get install net-tools your container for ifconfig to be callable) inside your container, you will see that the network interfaces are the same as the one on Docker host (eg. your laptop).

It's important to note that I'm a Mac user, but I run Ubuntu under Parallels, so using a Mac is not a disadvantage. ;-)

And this is how you connect NGINX container to the MySQL running on a localhost.

I was able to get access to the host mysql databases by mounting the volume as per @user833482, and after installing mysql-client and server on the docker container of course.
– MichaelMay 22 '17 at 11:07

Making mysql bind to 172.17.42.1 will prevent other programs using the database on the host to reach it. This will only work if all your database users are dockerized.

Making mysql bind to 0.0.0.0 will open the db to outside world, which is not only a very bad thing to do, but also contrary to what the original question author wants to do. He explicitly says "The MySql is running on localhost and not exposing a port to the outside world, so its bound on localhost"

To answer the comment from ivant

"Why not bind mysql to docker0 as well?"

This is not possible. The mysql/mariadb documentation explicitly says it is not possible to bind to several interfaces. You can only bind to 0, 1, or all interfaces.

As a conclusion, I have NOT found any way to reach the (localhost only) database on the host from a docker container. That definitely seems like a very very common pattern, but I don't know how to do it.

from the docker host you could still connect to the MySQL server using the 172.17.42.1 address. But your note is right otherwise. Aso, I edited my answer with the host networking mode that allows to keep the MySQL server bound to 127.0.0.1 while allowing containers to connect to it
– ThomasleveilMar 13 '15 at 23:31

no, as I said, you can't connect to 172.17.42.1 if mysql is bound to localhost.
– orzelMar 14 '15 at 4:19

4

"Making mysql bind to 172.17.42.1 will prevent other programs using the database on the host to reach it." - that is not true. Other programs can use mysql, they just have to connect to 172.17.42.1 instead of localhost/127.0.0.1.
– 0x89Mar 9 '16 at 16:00

The solution to the problem in this answer generally is to get the MySQL server to bind to 0.0.0.0 and then set up a firewall so that the db is not accessible from the internet.
– halferJun 16 '17 at 15:05

The CGroups and Namespaces are playing major role in the Container Ecosystem.

Namespace provide a layer of isolation. Each container runs in a separate namespace and its access is limited to that namespace. The Cgroups controls the resource utilization of each container, whereas Namespace controls what a process can see and access the respective resource.

Here is the basic understanding of the solution approach you could follow,

Use Network Namespace

When a container spawns out of image, a network interface is defined and create. This gives the container unique IP address and interface.

$ docker run -it alpine ifconfig

By changing the namespace to host, cotainers networks does not remain isolated to its interface, the process will have access to host machines network interface.

$ docker run -it --net=host alpine ifconfig

If the process listens on ports, they'll be listened on the host interface and mapped to the container.

Use PID Namespace
By changing the Pid namespace allows a container to interact with other process beyond its normal scope.

This container will run in its own namespace.

$ docker run -it alpine ps aux

By changing the namespace to the host, the container can also see all the other processes running on the system.

$ docker run -it --pid=host alpine ps aux

Sharing Namespace

This is a bad practice to do this in production because you are breaking out of the container security model which might open up for vulnerabilities, and easy access to eavesdropper. This is only for debugging tools and understating the loopholes in container security.

The first container is nginx server. This will create a new network and process namespace. This container will bind itself to port 80 of newly created network interface.

$ docker run -d --name http nginx:alpine

Another container can now reuse this namespace,

$ docker run --net=container:http mohan08p/curl curl -s localhost

Also, this container can see the interface with the processes in a shared container.

$ docker run --pid=container:http alpine ps aux

This will allow you give more privileges to containers without changing or restarting the application. In the similar way you can connect to mysql on host, run and debug your application. But, its not recommend to go by this way. Hope it helps.

3) SIGN UP for an account and they will provide an authentication token. Signing up is required because ngrok only give you tcp port tunnel after signing up. There is no cost or credit card required to sign up.

4) in your terminal do ngrok tcp 3306. 3306 is the port that mysql runs on my local, you can do it with any other port as well.

5) You will receive an address from step 4 such as this: tcp://0.tcp.ngrok.io:10117. This is the tunnel connection to your local machine. 0.tcp.ngrok.io is mapped to your localhost and port 10117 is mapped to your local port 3306. Now you can access your localhost port 3306 from anywhere using this address, including any docker container running on this machine. In your docker container(wherever it is), assuming you have mysql client already installed, do the following:

mysql --host 0.tcp.ngrok.io --port 10117 -u root

You will be able to log into your root account of your local machine from inside of the docker container!