9

I have containers running in docker-compose networks on a remote VPS. I would like to be able to access a database running in one of these containers from my localhost.

Eg, if the containers app and db are in a container network on the VPS, I want to access db:5432 from my machine's localhost:5432. Kubernetes' CLI allows this with kubectl port-forward <service-name> 5432:5432.

Are there any existing solutions to achieve this effect within existing unix commands and Docker's API? My searching around the Internet hasn't yielded any CLI to do this.

Cheers.


Edit: I have accepted Ali Tou's answer, however, it would be great to see a solution which does not require restarting a container to re-configure its ports to expose them onto the host.

Edit 2: I found a clever method for forwarding traffic in the Docker network using socat in a tangentially-related post https://stackoverflow.com/a/42071577/12406113. This is, however, publicly exposing the port instead of creating a tunnel, such as in the SSH solution.

Jarred Vardy
  • 93
  • 1
  • 5
  • What is the point of forwarding to your localhost? – Ali Tou Nov 01 '20 at 06:48
  • @AliTou - In my case it would be to work on the same DB as a partner during development. It's also useful for debugging a DB with your preferred client and troubleshooting in general. – Jarred Vardy Nov 01 '20 at 08:12
  • Do you have ssh access to the target machine? – Ali Tou Nov 01 '20 at 09:00
  • you need to map your local port to the port of your VPS, I think below tutorial is useful also you can always do port mapping with SSH as @AliTou pointed https://devops.ionos.com/tutorials/configure-apache-as-a-reverse-proxy-using-mod_proxy-on-ubuntu/ – badger Nov 01 '20 at 10:09
  • 2
    That's not a programming question, possibly better suited to superuser.com. – Ulrich Eckhardt Nov 01 '20 at 10:17

2 Answers2

11

Assuming you have SSH access to the target machine where the container is running, you can achieve this in two steps:

  1. Expose container port into your VPS port, binding to its loopback IP for security:
ports:
  - 127.0.0.1:5432:5432
  1. Use SSH port-forwarding to access port 5432 of that container:
ssh -f -N -L 127.0.0.1:5432:127.0.0.1:5432 <VPS_IP>

The above command might seem confusing, but it's requesting SSH to listen on 127.0.0.1:5432 on your client system (first ip:port pair) and port forward its connections through an ssh tunnel to 127.0.0.1:5432 (second ip:port pair) of the remote system (demonstrated with <VPS_IP>). See this answer for more info.

Note that this ssh connection is persistent until your network remains connected. If you want to close this connection, do a ps aux | grep ssh to find PID of ssh-forwarding process, then use sudo kill -9 $PID to kill it.

P.S. However, this is not different with the case you connect directly to VPS_IP:5432 if you don't have security concerns.

Ali Tou
  • 2,009
  • 2
  • 18
  • 33
  • This is just the solution I was looking for, thank you! I was unaware that you could bind the IP for a port internally. I thought it was going to be much more complicated, for security reasons. Absolute beauty. – Jarred Vardy Nov 01 '20 at 10:51
  • pretty neat! what about a service? i can't bind service to 127.0.0.1 i get this error `invalid argument "127.0.0.1:15672:15672" for "--publish-add" flag: hostip is not supported` – Ebrahim Karimi Mar 16 '22 at 22:25
  • @EbrahimKarimi You should post it as another question or look for it in their GitHub issues. I found an old issue describing your problem here, however it's unanswered: https://github.com/docker-archive/classicswarm/issues/2478 – Ali Tou Mar 16 '22 at 22:58
-1

You can just use ports section where you can specify host port and container port to forward request https://docs.docker.com/compose/networking/

slashpai
  • 1,141
  • 7
  • 12
  • Perhaps I wasn't clear, but this is not what I was asking. If you read the example, see that I am looking to access the container's port from an entirely different machine to the host of the container network. – Jarred Vardy Nov 01 '20 at 08:10
  • You can use the remote system's host name and the published port number to access the service. – David Maze Nov 01 '20 at 12:35