Remote Docker
Table of Contents
what & why
If you want to control a docker instance (the docker daemon) which is not your machine, you can expose it as a TCP socket (instead of a traditionnal UNIX socket) and connect to it remotely using the docker client. We’ll also use SSH forwarding to secure the connection to the docker api if security is a concern.
how
Install docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
then edit the systemd service unit by adding the -H tcp://0.0.0.0:2375
to the ExecStart
options.
sudo systemctl edit docker.service
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 --containerd=/run/containerd/containerd.sock
reload & restart
sudo systemctl daemon-reload
sudo systemctl restart docker.service
FYI, the first ExecStart=
is to remove the corresponding statement from the docker.service unit file. If we omit this, systemd will complain like Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.
We can check on the server that docker is indeed listening on port 2375 by running sudo ss -tulnp | grep 2375
:
tcp LISTEN 0 4096 *:2375 *:* users:(("dockerd",pid=11239,fd=7))
On our local machine we should now be able to do docker -H <server_ip:2375> ps
.
Important note: using -p
or -v
will not forward ports/volumes on your local machine but on the server.
ssh tunnel
Finally, if don’t want to expose the bare docker API to our network, we can wrap it in a SSH tunnel !
(you can use docker -H ssh://example.com ps
directly, but it’s good to know that you can do it using ssh tunneling like a unix greybeard.)
I assume you have ssh enabled on the server, and copied your pubkeys to make the connection passwordless. If not, enable ssh then ssh-copy-id <remote_user>@<server_ip>
.
We can also change the override we made earlier of the docker daemon, from -H tcp://0.0.0.0:2375
to -H tcp://127.0.0.1:2375
, so we don’t expose the docker API on each interface but only the loopback. (don’t forget to reload&restart).
On our local machine, we’ll do ssh -L 8375:127.0.0.1:2375 -N <remote_user>@<server_ip>
.
-L
means to use the SSH connection to port forward to our port8375
the port127.0.0.1:2375
from the server point of view, which is its docker tcp socket.-N
means to not launch any command
You can now do docker -H tcp://127.0.0.1:8375 ps
from our local machine, we we are now connecting through our port 8375
, which is forwarded by SSH to the port 2375
of the server.
But we we have a look at the ssh man page, we can read this for -L
:
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
I was intrigued by [bind_address:]port:remote_socket
, specifically by remote_socket
. That would mean we can also forward unix socket. We know that on the server, the docker API is also exposed on /var/run/docker.sock
.
let’s try ssh -L 8375:/var/run/docker.sock -N <remote_user>@<server_ip>
. We should redirect the docker unix socket on the server to our host’s port 8375
.
> docker -H tcp://127.0.0.1:8375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
sure enough, it works !
As a bonus point we could disable completely the use of a TCP connection now, as we are using the unix socket on the server.