Host docker2
HostName admin-docker-2.example.com
User ubuntu
IdentitiesOnly yes
IdentityFile ~/.ssh/example.pem
KnownHostsCommand /Users/jacob/bin/prune-docker-socket "%k"
LocalForward /tmp/docker.docker2.sock /var/run/docker.sock
The LocalForward directive creates the local socket file, but doesn't remove it. If the local socket file already exists, then the LocalForward fails. There's no way to run a command when ssh disconnects. Which is why we abuse KnownHostsCommand to run a command before ssh connects.
The prune-docker-socket script is a few lines of shell that constructs the expected socket file path and then deletes the socket file IF it exists and IF it's a socket file. Don't accidentally delete something if any of these expectations are wrong!
#!/bin/sh
[ -z "$1" ] && exit 1
socket="/tmp/docker.$1.sock"
[ -S "$socket" ] && rm "$socket"
printf "%s: %s\n" "🥑" "$@" >&2
In one shell, connect via ssh:
ssh -nNT docker2
List containers on the remote docker engine:
docker --host unix:///tmp/docker.docker2.sock ps
A docker context tells the docker cli what docker engine to connect to. You can have as many as you want!
docker context create docker2 --description 'first run: ssh -nNT docker2' --docker 'host=unix:///tmp/docker.docker2.sock'
Switch contexts:
docker context use docker2
Connect to the remote:
ssh -nNT docker2
Use docker!
❯ docker ps
STATE NAMES PORTS
running typesense-dashboard 443/tcp, 2019/tcp, 443/udp, 0.0.0.0:3007->80/tcp, :::3007->80/tcp
running nexus 0.0.0.0:3002->8081/tcp, :::3002->8081/tcp
running mail 1110/tcp, 0.0.0.0:25->1025/tcp, :::25->1025/tcp, 0.0.0.0:3003->8025/tcp, :::3003->8025/tcp
running uptime-kuma 0.0.0.0:3001->3001/tcp, :::3001->3001/tcp
❯ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
desktop-linux Docker Desktop unix:///Users/jacob/.docker/run/docker.sock
docker2 * first run: ssh -nNT docker2 unix:///tmp/docker.docker2.sock
orbstack OrbStack unix:///Users/jacob/.orbstack/run/docker.sock