Skip to content

Commit

Permalink
docs: initial readme
Browse files Browse the repository at this point in the history
  • Loading branch information
gregnr committed Nov 11, 2021
1 parent 33e1536 commit ced4e38
Showing 1 changed file with 88 additions and 0 deletions.
88 changes: 88 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Docker Mac Net Connect

> Connect directly to Docker-for-Mac containers via IP address.
## Background

Accessing containers directly by IP (instead of port binding) can be useful and convenient.

## Problem

Docker-for-Mac works by running Linux in a VM and executing containers within that VM.

Containers are accessible by IP address from the Linux VM, but not from the macOS host.

## Solution

Create a network tunnel between your macOS host and the Docker Desktop Linux VM. The tunnel is implemented using WireGuard.

## Why WireGuard?

WireGuard is an extremely lightweight and fast VPN. It’s also built in to the Linux kernel, which means no background processes/containers are required to build the tunnel. It is the perfect tool for this application.

## Installation

This project just passed POC, so installation is manual. Homebrew package coming soon.

```bash
$ git clone https://github.com/chipmk/docker-mac-net-connect
$ cd docker-mac-net-connect/client && docker build -t docker-mac-net-connect .
$ cd .. && sudo go run .
```

## How does it work?

### macOS side

A lightweight customized WireGuard server runs on your macOS host and creates a virtual network interface (`utun`) that acts as the link between your Mac and the Docker Desktop Linux VM.

### Linux VM side

Since WireGuard is built into the Linux kernel, all we need to do is configure the VM with a virtual network interface that links to the macOS host. No background processes or containers are required.

How do we configure the VM? A one-time container is deployed with just enough privileges to configure the Linux host’s network interfaces (`—-cap-add=NET_ADMIN` + `-—net=host`).

The container creates the interface, configures WireGuard, then exits and is destroyed. The WireGuard interface continues working after the container is gone because it was created on the Linux host’s network namespace, not the container’s.

### Tying it together

The server on macOS monitors your Docker container networks and automatically adds their subnets to your macOS routing table (routing through the `utun` interface). Now you can connect to any container directly by it’s IP address from your macOS host. Eg.

```bash
# Run an nginx container
$ docker run --rm --name nginx -d nginx

# Get the internal IP for the container
$ docker inspect nginx --format '{{.NetworkSettings.IPAddress}}'
172.17.0.2

# Make an HTTP request directly to its IP
$ curl -I 172.17.0.2
HTTP/1.1 200 OK
Server: nginx/1.21.3
Date: Thu, 11 Nov 2021 21:00:37 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 07 Sep 2021 15:21:03 GMT
Connection: keep-alive
ETag: "6137835f-267"
Accept-Ranges: bytes
```

## FAQ

### What happens if Docker Desktop restarts?

The server detects when the Docker daemon stops and automatically reconfigures the tunnel when it starts back up.

### Do you remove routes when Docker networks are removed?

Yes, the server watches the Docker daemon for both network creations and deletions and will add/remove routes accordingly.

### Will routes remain orphaned in the routing table if the server crashes?

No, routes are tied to the `utun` device created by the server. If the server dies, the `utun` interface will disappear along with its routes.

## License

MIT

0 comments on commit ced4e38

Please sign in to comment.