Offload Docker tasks to a remote Windows host!

Time for another work from home related post!

We all love Docker! - it makes our lives easier, and it lets us package up just what we need into finite packages for reproduction, testing, distribution or pretty much anything else we can think of.  But it definitely isn’t light on system resources.  Reserving 2GB of RAM by default (at least on MacOS) and potentially using a lot of CPU power to keep all the applications we need running in the background.

This has been one of my main pain points while working from home, or just generally working with Docker while at home, on my MacBook.  So I recently went about an adventure to figure out a way to ease this heavy resource consumption, and allow me to free up my local machine resources while using docker to build and run services.

Preparation

  1. The first important part of this, is to have the docker client installed on your machine, as well as have the full Docker install present and running on the destination machine that you wish to use as the “workhorse”
  2. The second important bit is to understand how the DOCKER_HOST environment variable works.  As we can see from the Docker documentation located here: https://docs.docker.com/engine/reference/commandline/cli/ the DOCKER_HOST environment variable tells Docker which Daemon socket to connect to.  This is important for what we need to do.

Once I had these things set up, I wanted a way to be able to issue a docker build command on my local machine, and have the remote (Windows based) machine, actually build the image for me, so that my local machine did not bear the resource impact of doing the build.

Normally, with a Linux setup, we could simply set the DOCKER_HOST environment variable to the destination machine, however, in this instance, because of the way Docker for Windows works, we need one additional step.

This step, is to run a docker socket proxy, which allows us to take the Docker socket, and expose it at host level on the Windows machine, so that we can access it over the local network.

In order to do this, I simply used the docker socket proxy that already exists on GitHub here: https://github.com/Tecnativa/docker-socket-proxy - full credits to the creator and publisher of that!

Deploying the proxy

I simply used the Dockerfile present in the repo to build the proxy image.  Once I had built the Docker image for the Docker socket proxy, I simply pushed it to Dockerhub, and got it running on my destination Windows host, using the compose file located in my fork of the proxy repo, here: https://github.com/devinsmith911/docker-socket-proxy/blob/master/docker-compose.yml - you are welcome to check this out and modify it to work for your use case.  As you can see in the Compose file, I am simply mapping port 2375 on the container, to port 2375 on the host level network.

After running the docker stack deployment command on the Windows host, and pointing it to the compose file, the proxy was up and running.  I was able to confirm this by running a netcat to port 2375 on my Windows desktop machine, from my MacBook.

~ nc -z -w 1 devin-desktop.local 2375
Connection to devin-desktop.local port 2375 [tcp/*] succeeded!

Setting the Docker destination

Now that we have a successful connection locally to the Docker socket, it is simply a case of setting the DOCKER_HOST environment variable to the destination host on my MacBook like so:

export DOCKER_HOST=devin-desktop.local

Since we are using the default port of 2375, we don’t need to specify it specifically.  Additionally, I am using the internal, local hostname of my desktop machine here, you can also use the internal IP address to set this.

Once done, we are now all set up and ready to go.  We can verify that this works by running a Docker build on your local machine, and checking to see that the build actually executes on the remote machine:

The below command was run from the Window machine, after running a Docker build from my Mac:

 docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                                      NAMES
b90cc627d744        4e5021d210f6                       "/bin/sh -c 'sleep 6…"   2 seconds ago       Up 1 second                                                    zen_poincare

As we can see, the build container has spawned on the Windows machine and is building my image!

Notes and Thanks

  • Full credits to the creator of the Docker socket proxy repo in Github, this was extremely helpful here! Without the socket proxy, we are not able to access the Docker socket from the host port on the Windows machine, and thus this process does not work.
  • NEVER expose port 2375 on the Windows machine to the internet (via port fowarding etc) as this will very likely open you up to intrusions and attacks, it essentially gives full docker access to the system.
  • You can also modify the environment variables in the socket proxy, to only allow the clients to perform certain tasks on the destination (such as only allowing builds, and not docker run for example)

And there you have it!  Docker builds happening on your remote Windows machine, without too much fuss or complications.  Now you can do Docker builds and run images without any significant impact to your local machine!

I particularly enjoyed writing this quick article, so if you’d like more like this, let me know!

-Devin

comments powered by Disqus