Accessing the docker-for-mac network from a browser: the fast and dirty way

September 28, 2019 · 2 minute read

For a authentication-related prototype I needed to be able to access some services running in containers. Unfortunately Docker runs in a VM on MacOS, and the Docker network is network is not bridged. This prevents us from accessing the container IPs directly.

Of course, there are many options to expose/proxy specific container ports to the host, such as, using port mapping in Docker or a reverse proxy alongside the target container.

However, in this project there was an additional constraint: throughout the project the services assumed (and required!) that the user—or more accurately, the browser—is able to access the exact same IP/DNS name of the containers as the containers themselves. The common solutions are based on proxying, which alters the address. Also, I wanted to avoid the need to modify the actual services, which would be time-consuming and pointless for a prototype. Finally, I wanted to avoid any external dependency on a DNS server, to avoid overcomplicating the setup—because the issue is related to a MacOS setup.

So, I decided to solve it using the quickest and hackiest way I could think of, which is to simply deploy and expose Chrome in a Docker container. Because it is deployed as container, it does have access to the Docker network and therefore the container IPs.

The initial setup requires a bit of work. First, besides Docker, you will need xquartz (for a X Window system on MacOS) and socat (for hooking the Chrome container to xquartz).

brew install socat
brew cask install xquartz

After installing, you will need to reboot your machine.

Now, to run Chrome in a container, first, setup a stream between the Chrome container and the XQuartz server:

socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

In a different shell, run the Chrome container:

docker run \
  --rm \
  --name chrome \
  --net host \
  --volume "${HOME}/Downloads:/root/Downloads" \
  --volume "${HOME}/.config/google-chrome/:/data" \
  --security-opt seccomp:unconfined \
  --env "DISPLAY=$(ifconfig en0 | grep inet | awk '$1=="inet" {print $2}'):0" \
  jess/chrome

Chrome should now launch in a XQuartz window.

I found that responsiveness of the window varies quite a bit depends on the display setup. The responsiveness varies from acceptable to terrible. One way to speed up the rendering is to change the color output to 256 Colors in the preferences of XQuartz.

That said, this is just the quickest solution that I came up with. There might be (and probably is) an easier solution that I am not aware of. If you know a faster alternative, let me know!

Further reading