How to connect to containerized database with its IP? - postgresql

I'm new to Docker. I successfully created a PostgreSQL container my-database and I am able to access it from SQLTools on my local machine with server address localhost and the port.
I got the containerized database's IP address from the following command:
docker container inspect my-database
But when I go back to SQLTools or the PHP web application (not containerized) and try to connect to my-database with the IP address I got above, it couldn't connect successfully.
What am I missing here?
FYI, I also created another container and was able to connect to my-database with the following way: Use the same network for both my-database and the second container.

It all depends on how you enable access to the database.
If your php service runs in the same machine, then localhost could work
If its on a different machine in the same network, then use the network IP assigned to that machine. If you have your php server in a totally different location, then you may want to use something like an nginx reverse proxy to your docker container.
So in your case you should get the ip:port where your db container runs and use that. Docker inspect shows the internal network ip which only helps other containers in the same virtual network connect to a container.

You never need the docker inspect IP address. You can only connect to it in two specific circumstances: if you're in a different container on the same Docker network, or if you're (a) not in a container at all, (b) on the same host, and (c) that host is running native Linux and not a different OS.
You've already identified the right answers. Say you start the container as
docker network create any-network-name
docker run \
--name database \
--net any-network-name \
-p 5432:5432 \
postgres
From another Docker container on the any-network-name network, you can use the database container name as a DNS name, and avoid the manual IP lookup; ignore any -p options and use the "normal" port for the service. From outside a container, you can use the host's DNS name or IP address (or, if it's the same host, localhost) and the first -p port number.
If you're running this in Docker Compose, it automatically creates a network for you and registers containers under their Compose service name; you do not need networks:, container_name:, or other similar settings.
version: '3.8'
services:
database:
image: postgres
ports: ['5432:5432']
application:
build: .
environment:
- PGHOST=postgres

Related

Docker postgres image: How to restrict access from host network?

I'm running a postgres server in a docker container within a custom docker network, and I found I can access it using psql from the host.
This seems to me to be undesirable from a security perspective since I thought the point of docker networks was to isolate access to the containers.
My thinking was that I would run my app in a separate container within the same docker network and publish ports on the app container only. That way, the app can be accessed from the outside world, but the database can't be.
My question is: Why is the 5432 port being published to host on the postgres container without me explicitly specifying that, and how can I "unpublish" this port?
And a related question would be: am I wrong that publishing port 5432 is a security concern in this case (or at least less secure than not publishing it)?
My container is running the official docker postgres image here: https://hub.docker.com/_/postgres/
Thanks for any help!
Edit: Here is the docker command I'm using to run the container:
docker run -d --restart=always --name=db.geppapp.com -e "POSTGRES_USER=<user>" -e "POSTGRES_PASSWORD=<password>" -e "POSTGRES_DB=gepp" -v "/mnt/storage/postgres-data:/var/lib/postgresql/data" --net=db postgres
Edit 2: My original question was not entirely correct as docker was not in fact publishing the port 5432 to the host but rather I was specifying the container's IP address as the host when connecting to postgres with psql as follows:
psql --host=<docker-assigned-ip> --username=<user> --dbname=gepp
So the thing preventing me from restricting access to the container from the host is in fact that an IP address is assigned to the container on the host network.
The Dockerfile of postgres exposes that port 5432, but that does not mean it makes the port of the container accessible to the host. To expose the port to host, you must use either the -p flag to publish a range of ports or the -P flag to publish all of the exposed ports. But I don't see that in your command.
Are you sure you are not accessing a local postgres and not the container postgres?
or Are you connected to the Host network? If docker container is set to network_mode: host or type of host, any port exposed in the container would be exposed on the docker host as well, without requiring the -p or -P docker run options.
Thanks everyone who commented and answered. I'm answering my own question with a summary of my best understanding based on the replies and other things I've read.
As I mentioned in the edit to my question the thing preventing me from restricting access to the container from the host is the IP assignment on the host network.
According to the docker docs: (https://docs.docker.com/config/containers/container-networking/)
By default, the container is assigned an IP address for every Docker
network it connects to.
In this case, the container is not technically "connected" to the host network but has an IP on that network anyway. David pointed out in comments that this only occurs on Linux, not on Windows or Mac (I haven't personally verified this).
So it would appear that due to the way docker networks are implemented in Docker Linux, an IP address is published to the host for all running containers, and there's no way to prevent this.
From a security perspective, since the docker host is always trusted, my understanding is that database security comes mainly from restricting access to the host itself (network and linux account security), and the native database credential security. Docker does not add another secure layer as I was initially thinking it might.

To connect postgres docker with the Widlfy docker

I have running widlfy docker and the postgres docker and also nginx docker, I want to connect all the three docker internally so my widlfy can connect to postgres and nginx and I have my url running. I have added the parameter of networking in the docker-compose.yml file but still not success.
Can you suggest how can I perform this activity of interconnection.
If you can't have all the containers in the same docker-compose.yml, then use the next.
The containers have assigned an internal port and external port, internal is inside the every docker's network and the external is where you can access using the computer's IP or localhost. In this case you need use your computer's IP, If the IP is 192.168.1.20 and the externals ports for the containers are:
Widlfy: 8080
Postgresql: 5432
ngnx: 80
Then you can connect them using this information:
Widlfy: 192.168.1.20:8080
Postgresql: 192.168.1.20:5432
ngnx: 192.168.1.20:80
The computer's IP use to change in a period of time, it depends of your modem, so check that your IP be the right when you use this option.

Connect to Windows Postgres from Debian Docker container

I am running Postgres on a Windows 10 computer, and I want to connect to it from a Docker container. I've followed instructions from many sources and things should be working, but they're not.
Command line used to create Docker container:
docker run --rm -d --network=host --name mycontainer myimage
In postgresql.conf:
listen_addresses = '*'
In pg_hba.conf:
host all all 172.17.0.0/16 trust
In the bash shell of my container, I run:
psql -h 127.0.0.1
and I get the error:
psql: could not connect to server: Connection refused
Is the server running on host "127.0.0.1" and accepting TCP/IP connections on port 5432?
Needless to say, Postgres is definitely running on my computer and I am able to query it from local applications. What am I missing?
THIS WON'T WORK FOR DOCKER v18.03 AND ONWARDS
The answer is already there - From inside of a Docker container, how do I connect to the localhost of the machine?
This question is related to a mysql setup, but it should work for your case too.
FOR DOCKER v18.03 ONWARDS
Use host.docker.internal to refer to the host machine.
https://docs.docker.com/docker-for-windows/networking/#i-cannot-ping-my-containers
As you've discovered, --network-host doesn't work with Docker for Windows or Docker for Mac. It only works on Linux hosts.
One option for this scenario might be to host PostgreSql in a container, also. If you deploy them with a docker-compose file, you should be able to have two separate Docker containers (one for the database and one for your service) that are networked together. By default, docker-compose will expose containers to others in the same compose file using the container name as its DNS name.
You could also consider including the database in the same container as your service, but I think the docker-compose solution is better for several reasons:
It adheres to the best practice of each container having only a single process and single responsibility.
It means that you can easily change and re-deploy your service without having to recreate the database container.
Configure the connection inside your docker container with the real ip-address of your host or as workaround with a dns name

Equivalent of using a ssh tunnel

Using virtual hosts rather than deployed Docker container it was a normal work process for me to create ssh tunnels in order to access delimited machines from my local box. For instance connect with my psql client to a Postgres instance which I could only reach from a bastion box.
With Docker everything is boxes away even more. Is there an equivalent for doing the same but with Docker? Tunnel through the Docker instance to the RDS instance?
You use the docker CLI to connect to a running container. For instance...
To log into a db running in a container you can use (from your local machine)
docker exec -it mypsqlcontainer psql -U username dbname
I personally almost never have to ssh into the host. Everything can be done through the docker CLI.
You can make ssh-tunnel to the docker host. DB port must be accessible from docker host (i.e. using "-p" docker run option).
If you prefer not publishing DB port you can create jumpbox container with ssh server, publish port 22 on this container and user container linking to link jumpbox container with DB container.

Allowing Docker container to access Postgres running on localhost

I've got a docker container which is supposed to run a (HTTP) service.
This container should be able to connect to PostgresSQL running on the host machine (so it's not part of the container). The container uses the host's network settings:
docker run -e "DBHOST=localhost:5432" -e "DB=somedb" -e "AUTH=user:pw" -i -t --net="host" myservice
I'm using MacOSX, so Docker is running on a Virtualbox VM. I guess I need port forwarding to make this work. I've tried to configure that:
VBoxManage controlvm "default" natpf1 "rule1,tcp,,5432,,5432";
But this doesn't work. If I start up the service, all I get is a connection refused message and the service cannot connect to Postgres.
Postgres is running on port 5432, on the host machine. The "default" is the name of the VM created by Docker installer.
What am I doing wrong? Please help!
I've had success with this using the --add-host flag, which adds an entry into the /etc/hosts in your container. Boot2docker and docker-machine both assign an ip you can use to hit your localhost from inside a container, so you just want to add an entry that points back to this.
With boot2docker, where the default host ip is 192.168.59.3, you can just do docker run --add-host=my_localhost:192.168.59.3 ...
With docker-machine, I think you'll need to lookup your localhost's mapped ip in Virtualbox, and then you can do the same: docker run --add-host=my_localhost:[localhost_mapped_ip_from_docker] ...
Try setting that up and then trying to connect to your Postgres instance through my_localhost. Make sure you correctly set access and accepted inbound ip permissions in Postgres as well, as if it's not listening on the container's ip or 0.0.0.0, it won't work no matter what.