27

I commonly see solutions that expose a docker container's port to the host.

In my case I want to forward a local port from one container, to another.

Let's say I run a service on container A that has a hard-coded configuration to access db on localhost 3306. But I want to run the db server on container B.

What is the best way to port-forward from A-localhost:3306 to B-IP:3306?

Marinos An
  • 6,191
  • 2
  • 35
  • 68

7 Answers7

30

Install socat in your container and at startup run

socat TCP-LISTEN:3306,fork TCP:B-IP:3306 &

This will listen locally on your 3306 and pass any traffic bidirectionally to B-IP:3306. socat is available in package named socat. So you will run any of the below commands to install it

$ yum install -y socat
$ apt install -y socat
$ apk add socat

Edit-1

You can even do this by not touching your original container

Dockerfile

FROM alpine
RUN apk update && apk add socat

Build the file as below

docker build -t socat .

Now run a container from same

docker run --name mysql-bridge-a-to-b --net=container:<containerAid> socat socat TCP-LISTEN:3306,fork TCP:BIP:3306

This will run this container on A's network. So when it listens on A's network the localhost:3306 will become available in A even though A container was not touched.

Tarun Lalwani
  • 124,930
  • 8
  • 149
  • 214
16

You can simply run the container with network mode equal to host.

docker run --network=host ...

In that case, from the container point of view, localhost or 127.0.0.1 will refer to the host machine. Thus if your db is running in another container B that listens on 3306, an address of localhost:3306 in container A will hit the database in container B.

yamenk
  • 33,910
  • 9
  • 61
  • 67
  • 1
    Absolute f&%$^!g legend! +1 – Ash Apr 11 '19 at 06:06
  • this actually solved me. dockerA runs in its own network (and maybe exposed to host). dockerB is the same. my intuition was that when exposing it on `docker run -p` that will transparently make it has the host network – adonese Apr 09 '20 at 18:34
  • 2
    this is only supported on Linux: https://docs.docker.com/network/host/ – TmTron Sep 08 '20 at 07:42
14

If you want container B's port to be exposed as a localhost port on container A you can start container B with the network option set to container mode to start container B on container A's network namespace.

Example:

docker run --net=container:A postgres

Where:

  • A is the name or identifier of the container you want to map into.

This will startup postgres in a container on the same network namespace as A, so any port opened in the postgres container will be being opened on the same interface as A and it should be available on localhost inside container A.

Leigh McCulloch
  • 1,624
  • 21
  • 21
1

For development on Windows we can simply use host.docker.internal: see docker-for-windows networking

I WANT TO CONNECT FROM A CONTAINER TO A SERVICE ON THE HOST
We recommend that you connect to the special DNS name host.docker.internal which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Windows.

So in your case:

  • container A publishes port 3306
    this port is now available on the host
  • container B can simply connect to host.docker.internal:3306
TmTron
  • 10,318
  • 3
  • 52
  • 97
0

This solution is way overkill for the use case stated but in the case you run across this while researching a larger scope.

Hashicorp Consul installs a localhost agent that will proxy the localhost port to the ipaddress and port of a service registered within the directory. https://www.consul.io/intro

I have no relation to Hashicorp besides using their products in systems I've built.

Stevko
  • 3,969
  • 6
  • 36
  • 57
0

Containers can access each other internally you dont need to expose or forward anything.

ZobairQ
  • 59
  • 3
-1

You can do it with Docker-Compose.

docker-compose.yml example:

version: '3'
services:
  web:
    build: .web
    ports:
     - "5000:5000"
  mysql:
    build: .mysql
    ports:
     - "3306:3306"

Here you have 2 docker instances: web and mysql, so each docker instance can see each other using the names you defined as services.

Hope this helps

Andrew Graham-Yooll
  • 1,690
  • 2
  • 18
  • 40
Jorge Chavez
  • 129
  • 6
  • I don't know why this was downvoted without a comment. This works best for me since I don't have to mess with figuring out the port or hostname of the other container. The URI for mysql would be e.g. "mysql:3306" – Stevko Jun 15 '20 at 07:09
  • 1
    @Stevko because the db access is hardcoded to `localhost:3306`. It is not possible to change it to link to `mysql:3306`. – Julian Pieles Sep 08 '20 at 08:03