Docker: MacOSX Expose Container ports to host machine

In my job I working with docker and the option --net=host working like a charm forwarding the docker container ports to the machine. This allows me to adding grunt tasks that use certain ports by example:

When I begin to use Docker in Mac, the first problem that i had was: The option --net=host don't work anymore. I researched and I understand why this is not possible (Docker in Mac runs in a own virtual machine) and my momentary solution it's use the -p option for expose the ports, but this limit to me to add more and more task that use ports because i need run the explicit -p command for each port that i need expose.

Anyone with this same problem? How to dealing with this ?

Upvotes: 20

Views: 29225

Answers (4)

Daniel Trugman
Daniel Trugman

Reputation: 8501

Had the same issue, but couldn't find an answer in any of the relevant threads. The following worked for me.

Recapping the scenario:

  • There is a service on the MacOS host that is listening on port X.
  • We want to run a container that will connect to that service.

Solution if your client can perform DNS resolutions

If your client can accept a hostname as input and perform DNS resolutions, the solution is as simple as replacing localhost or 127.0.0.1 in your target address with host.docker.internal.

Example: If you client tries to connect to the server using localhost:8080, just replace that with host.docker.internal:8080.

Solution if your client can't perform DNS resolutions

If your client cannot accept hostnames, and requires an IP address, you will have to help with the DNS resolution manually.

First, run the container interactively once, and use a DNS resolution tool (e.g. nslookup) to resolve the IP address of host.docker.internal. For example:

root@c05d907053e5:/app# nslookup host.docker.internal
Server:         127.0.0.11
Address:        127.0.0.11#53

Non-authoritative answer:
Name:   host.docker.internal
Address: 192.168.65.2

Then, just replace the server address with the resolved address (192.168.65.2 in this example).

Example: If you client tries to connect to the server using 127.0.0.1:8080, just replace that with 192.168.65.2:8080.

Notes:

  • You don't need to pass any --network flags to docker run

Upvotes: 2

Eugen Mayer
Eugen Mayer

Reputation: 9916

Your issue is most probably that you are using dockertoolbox or dhingy/dlite or anything else providing a full-fledged linux VM, which then hosts docker to run your container inside this VM. This VM has, of course, its own network stack and own IP on the host, and thats were your tools will have issues with. The exposed ports of the container are not exposed to OSX host localhost, but rather OSX Docker-VM-ip.

To solve those issues elegantly

Expose ports to OSX localhost from the container

  1. First, use/install docker-for-mac https://docs.docker.com/engine/installation/mac/ instead of dockertoolbox or others. Its based on a special xhyve stack which reuses your hosts network stack
  2. when you now do docker run -p 3306:3306 percona it will bind 3306 on the osx-host-localhost, thus every other osx-tool trying to attach to localhost:3306 will work ( very useful ) just as you have been used to it when you installed mysql using brew install mysql or likewise
  3. If you experience performance issues with code shares on OSX with docker containers, check http://docker-sync.io - it is compatible with docker-for-mac ( hint: i am biased on this one )

Export ports from the OSX-host to a containter

You do not really export anything in particular, you rather make them accessable as a whole from all containers ( all ports of the OSX-host-localhost)

If you want to attach to a port you offered on the OSX host, from within a container, e.g. during a xdebug session were your IDE listens on port 9000 on the OSX-host-localhost and the container running FPM/PHP should attach to this osx-localhost:9000 on the mac, you need to do this: https://gist.github.com/EugenMayer/3019516e5a3b3a01b6eac88190327e7c

So you create a dummy loopback ip, so you can access your OSX-host ports from without containers using 10.254.254.254:9000 - this is portable and basically gives you all you need to develop like you have used to


So one gives you the connectivity to container-exposed ports to apps running on the mac and trying to connect to localhost:port

And the second the inverse, if something in the container wants to attach to a port on the host.

Upvotes: 13

xdays
xdays

Reputation: 787

Not sure if docker for mac can support bi-directional connection later https://forums.docker.com/t/will-docker-for-mac-support-bi-directional-connection-between-host-and-container-in-the-future/19871

I have two solution:

  1. you can write a simple wrapper script and pass the port you want to expose to the script
  2. use vagrant to start a virtual machine with network under control.

Upvotes: 1

VonC
VonC

Reputation: 1325017

One workaround, mentioned in "Bind container ports to the host" would be to use -P:

(or --publish-all=true|false) to docker run which is a blanket operation that identifies every port with an EXPOSE line in the image’s Dockerfile or --expose <port> commandline flag and maps it to a host port somewhere within an ephemeral port range.
The docker port command then needs to be used to inspect created mapping.

So if your app can use docker port <CONTAINER> to retrieve the mapped port, you can add as many containers as you want and get the mapped ports that way (without needed an "explicit -p command for each port").

Upvotes: 1

Related Questions