dockerkuberneteskubectlportforwarding

Connect to port-forwarded Postgresql instance in Kubernetes from local Docker container


I have a Django application that talks to a Postgresql database running in a remote Kubernetes cluster. There is a docker-compose.yml file for local development. For Kubernetes deployment, I have a simple deployment.yaml file for the Django Application and I'm using the helm chart from bitnami for Postgresql deployment.

I want to be able to connect to the Postgresql instance from within the Docker container running the Django API. Now, when I do a port-forward to the Postgresql instance I can connect to the database from my local machine using psql or other tools. From what I've found, to be able to access services running on localhost from within a container, you need to access it through host.docker.internal.

I've added the extra_hosts parameter in my docker compose file and can access services running on my local machine just fine. However, I can't connect to the port-forwarded Postgresql instance from within the Django API container. It seems that I can't connect to any port-forwarded service from the container this way. Am I doing something wrong or is this the expected behavior?


Solution

  • kubectl port-forward is normally intended as a developer or debugger tool; it doesn't see itself as the "normal" way to access services that are in the cluster. One consequence of this is that, by default, it listens on only the 127.0.0.1 (host) localhost interface.

    You can fix this, specifically on a native-Linux host not running Docker Desktop, by setting kubectl port-forward to listen on all host interfaces

    kubectl port-forward --address 0.0.0.0 service/some-name-postgresql 5432
    

    If you're using Docker Desktop (as in for example this question) then everything Docker-related runs inside a hidden Linux virtual machine. For calls out of that VM, whether to host.docker.internal or to the broader Internet, Docker Desktop needs to run a proxy to forward those requests out of the VM. Since this proxy is on the host, it can also reach things that listen on 127.0.0.1. (This is also related to host networking not working inside the container: the "host" is actually the Linux VM.)

    But if you're using the core Docker engine directly on a native-Linux host, Docker just uses the Linux iptables subsystem to forward packets around. If you look around with debugging tools, docker network inspect might show you that the Compose default network is 172.18.0.0/16, and on the host there might be a docker1 interface with IPv4 address 172.18.0.1 on that network.

    This means, from a Unix networking point of view, that the request is coming from the docker1 interface, but the kubectl port-forward is bound only to the lo0 (localhost) interface. It doesn't match, and that's why you get a "connection refused" error. Changing the port-forward to listen on all interfaces removes this restriction.