Double port forwarding kubernetes + docker

Summary:

I have a docker container which is running kubectl port-forward, forwarding the port (5432) of a postgres service running as a k8s service to a local port (2223). In the Dockerfile, I have exposed the relevant port 2223. Then I ran the container by publishing the said port (-p 2223:2223)

Now when I am trying to access the postgres through psql -h localhost -p 2223, I am getting the following error:

psql: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.

However, when I do docker exec -ti to the said container and run the above psql command, I am able to connect to postgres.

Dockerfile CMD:

EXPOSE 2223
CMD ["bash", "-c", "kubectl -n namespace_test port-forward service/postgres-11-2 2223:5432"]

Docker Run command:

docker run -it --name=k8s-conn-12 -p 2223:2223 my_image_name:latest

Output of the docker run command:

Forwarding from 127.0.0.1:2223 -> 5432

So the port forwarding is successful, and I am able to connect to the postgres instance from inside the docker container. What I am not able to do is to connect from outside the container with the exposed and published port


I think there are two possible solutions that may help in your case:

  1. You can add the --address argument to the kubectl port-forward command with the IP address of the container running this command. By default, kubectl binds only to localhost and therefore it does not work as you expect (see: Kubectl Reference Docs).
  2. All newly-started containers connect to a default bridge network unless otherwise specified. To solve your problem, you can use the host network instead of the bridge network. As may be found in the Docker host networking documentation:

If you use the host network mode for a container, that container’s network stack is not isolated from the Docker host (the container shares the host’s networking namespace), and the container does not get its own IP-address allocated.

I will briefly describe both solutions to show you how it works.


First, I prepared postgres:

# kubectl get pod,svc
NAME           READY   STATUS    RESTARTS   AGE
pod/postgres   1/1     Running   0          155m

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/postgres     ClusterIP   10.110.151.73   <none>        5432/TCP   2s

Ad 1.

This approach is very similar to yours, I just added the --address argument:
NOTE: I used a container with kubectl already installed. I just want you to pay attention to the kubectl port-forward --address $(hostname -i),localhost service/postgres 2223:5432 command.

root@kworker:~# docker run -it --name=k8s-conn-12 -p 2223:2223 -v /config:/config mattjcontainerregistry/forward:latest bash
root@31b05af956ab:/# kubectl port-forward --address $(hostname -i),localhost service/postgres 2223:5432 --kubeconfig=config
Forwarding from 127.0.0.1:2223 -> 5432
Forwarding from 172.17.0.2:2223 -> 5432

From another terminal tab we can check if it works:

root@kworker:~# docker exec -it k8s-conn-12 bash
root@31b05af956ab:/# psql -U postgres -h localhost -p 2223
psql (12.7 (Ubuntu 12.7-0ubuntu0.20.04.1), server 13.3 (Debian 13.3-1.pgdg100+1))
WARNING: psql major version 12, server major version 13.
         Some psql features might not work.
Type "help" for help.

postgres=# 

In addition, we can do the same from the host machine (from outside the container with the exposed and published port):

root@kworker:~# psql -U postgres -h localhost -p 2223
psql (11.12 (Debian 11.12-0+deb10u1), server 13.3 (Debian 13.3-1.pgdg100+1))
WARNING: psql major version 11, server major version 13.
         Some psql features might not work.
Type "help" for help.

postgres=# 

Ad 2.

This approach requires the use of a host network:

host: For standalone containers, remove network isolation between the container and the Docker host, and use the host’s networking directly.

NOTE: I just want you to pay attention to the --network=host option (I used the same container as before):

root@kworker:~# docker run -it --name=k8s-conn-12 --network=host  -v /config:/config mattjcontainerregistry/forward:latest bash
root@kworker:/# kubectl port-forward service/postgres 2223:5432 --kubeconfig=config
Forwarding from 127.0.0.1:2223 -> 5432
Forwarding from [::1]:2223 -> 5432

Again, we can check if it works as expected from outside the container:

root@kworker:~# psql -U postgres -h localhost -p 2223
psql (11.12 (Debian 11.12-0+deb10u1), server 13.3 (Debian 13.3-1.pgdg100+1))
WARNING: psql major version 11, server major version 13.
         Some psql features might not work.
Type "help" for help.

postgres=# 

Additionally, it's worth considering if you really need a docker container for port forwarding. Perhaps running kubectl port-forward in the background would be better (see: Perform kubectl port-forward in background).