slonopotamus / stevedore

🚢 Docker distribution for Windows Containers that Just Works
Apache License 2.0
305 stars 12 forks source link

Add Linux containers support #8

Closed slonopotamus closed 2 years ago

slonopotamus commented 3 years ago

https://ksummersill.medium.com/creating-a-wsl-2-distro-from-scratch-4f52e3c0b881

slonopotamus commented 3 years ago

For the reference, here's how Docker Desktop works:

  1. Actual Docker demon is started as a service for Windows containers and/or inside WSL2 for Linux containers.
  2. docker CLI doesn't talk to them directly
  3. docker CLI always operates in default context that points at npipe:////./pipe/docker_engine
  4. There's a com.docker.proxy.exe process that actually listens on npipe:////./pipe/docker_engine
  5. Docker proxy routes all traffic to whatever backend is currently declared as "active"
  6. There are desktop-linux and desktop-windows contexts, also pointing to proxy.

Some logs.

This is how proxy is launched for Windows containers:

"C:\Program Files\Docker\Docker\resources\com.docker.proxy.exe" -windowsPipe=\\.\pipe\docker_engine_windows  -dockerExe "C:\Program Files\Docker\Docker\resources\bin\docker.exe"  -inject-hosts=true -native-api=true --windows-containers

This is how proxy is launched for Linux containers:

"C:\Program Files\Docker\Docker\resources\com.docker.proxy.exe" -windowsPipe=\\.\pipe\docker_engine_windows -wsl-distro docker-desktop  -dockerExe "C:\Program Files\Docker\Docker\resources\bin\docker.exe

Neither proxy nor backend is running:

>docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Build with BuildKit (Docker Inc., v0.6.3)
  compose: Docker Compose (Docker Inc., v2.0.0)
  scan: Docker Scan (Docker Inc., v0.8.0)

Server:
ERROR: error during connect: This error may indicate that the docker daemon is not running.: Get "http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/info": open //./pipe/docker_engine: The system cannot find the file specified.
errors pretty printing info

Proxy is running but backend is not (Linux containers):

>docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Build with BuildKit (Docker Inc., v0.6.3)
  compose: Docker Compose (Docker Inc., v2.0.0)
  scan: Docker Scan (Docker Inc., v0.8.0)

Server:
ERROR: Error response from daemon: open \\.\pipe\docker_engine_linux: The system cannot find the file specified.
errors pretty printing info

Note that Linux dockerd is only listening "hosts":["unix:///var/run/docker.sock","unix:///run/guest-services/docker.sock"] inside WSL2. It isn't yet clear who is listening on \\.\pipe\docker_engine_linux and routing traffic into WSL2.

slonopotamus commented 2 years ago

https://docs.docker.com/engine/install/binaries/#install-daemon-and-client-binaries-on-linux

slonopotamus commented 2 years ago

It isn't yet clear who is listening on \.\pipe\docker_engine_linux routing traffic into WSL2.

vpnkit-bridge.exe does this. See "C:\Users\<user>\AppData\Roaming\Docker\log\host\vpnkit-bridge.exe.log". It is paired with vpnkit-bridge running inside WSL.

slonopotamus commented 2 years ago

It might be possible to open docker.sock in AF_UNIX mode directly from Windows. See net.DialUnix and https://github.com/moby/moby/issues/36442

Unfortunately, there's no way to pass custom transport to docker client: https://github.com/moby/moby/blob/v20.10.12/client/client.go#L120

See https://devblogs.microsoft.com/commandline/windowswsl-interop-with-af_unix/ It is very tempting to use AF_UNIX socket.

UPD: forget about AF_UNIX. It doesn't work in WSL2: https://github.com/microsoft/WSL/issues/5961

slonopotamus commented 2 years ago

I'm currently working on docker-wsl-proxy

It is supposed to become the missing puzzle piece that converts Windows <-> WSL2 paths and routes docker requests into WSL2.

When docker-wsl-proxy is ready, the work will continue in linux-containers branch of current repo.

slonopotamus commented 2 years ago

After several days of messing with docker-wsl-proxy, I start to think that using moby routes is a dead-end for several reasons:

  1. I cannot passthrough client API version
  2. I cannot provide a proper ContainerDecoder. Proxy runs on Windows, so doesn't have access to Linux implementation living in sysinfo_linux.go
  3. Moby routes are not very well adopted for third-party usage: https://github.com/moby/moby/pull/43180
  4. There are issues with systemrouter. Several route implementations simply do not expect that server could fail.
  5. Client.NewClientWithOpts is very restrictive and doesn't allow me to pass AF_UNIX transport. This could be implemented on Moby side (see https://github.com/docker/go-connections/pull/98), but that repo is nearly-dead, so god knows how many years it will take.

New plan: we go one level lower and instead implement a HTTP proxy. Currently, it looks like the only place that requires paths conversions is container creation. We could intercept that API call in the proxy and rewrite JSON.


I suddenly understood that paths is not the only thing we need to do. We also need to support container port bindings to Windows host ports. This possibly can wait though.

slonopotamus commented 2 years ago

HTTP proxy ended up being so much simpler: https://github.com/slonopotamus/docker-wsl-proxy/commit/7c75d2deb751ec6db2210537282a15e374d69910

Missing bits are:

  1. Make it talk to docker-inside-wsl
  2. Do bind path rewriting
slonopotamus commented 2 years ago

image

First proof-of-concept that works across WSL boundary (docker server is inside, docker client is outside).

slonopotamus commented 2 years ago

That's what was committed to main branch:

https://user-images.githubusercontent.com/92637/153852434-f4518f98-fde2-4902-81f0-655df9c554f7.mp4

slonopotamus commented 2 years ago

Docs: https://github.com/slonopotamus/stevedore#experimental-linux-containers-support