3

my setup is Docker for Windows (Version 18.09.2) on a Windows 10 Pro machine with installed postgres (not a database, only the command line tools).

I run the official postgres image from docker hub with

docker run -it -v D:/postgres:/home/dump --name some_postgres -e POSTGRES_PASSWORD=root -d postgres

Afterwards I am able to connect via

docker exec -it <docker-id> bash

and run

psql -U postgres

Everything works fine. Now I want to connect from my host. I call

psql -h <local-ip> -U postgres

and got

psql: could not connect to server: Connection refused (0x0000274D/10061)
        Is the server running on host "192.168.116.74" and accepting
        TCP/IP connections on port 5432?

I am pretty sure, the database could be accessed. Because if I change the IP I receive

psql: could not connect to server: Connection timed out (0x0000274C/10060)
        Is the server running on host "192.168.116.11" and accepting
        TCP/IP connections on port 5432?

Has anyone any clue how I can fix this issue? Or what I am doing wrong?

FlorianSchunke
  • 571
  • 5
  • 15
  • It turns out that this question should rather have been: `Connect to dockerized postgres from Windows Docker host when the standard port 5432 is already used by a Windows PostgreSQL installation?` This is at least likely from the comments under the first answer which show that there must have been a conflict. the OP's comment "to avoid any port clash with a probably local running database" and the misunderstandings in the rest of the comments make this likely. Changing this question would be unfair since the first answer does work when there is no such occupied port 5432. – questionto42 Sep 01 '21 at 12:46

2 Answers2

3

It took me quite some time to find out how to enter the container's databases from a normal psql prompt on Windows. This was due to an additional local Windows installation.


Creating a Docker container (Linux) without a port clash at 5432

The structure of the port parameter (both in docker run and in docker-compose) is:

<docker_host_port_on_linux>:<docker_container_port_on_linux>

See Connecting to Postgresql in a docker container from outside. The <host_port> is the port that you can find on Windows to connect to the container's port. And the core trick that seems to be needed here is to avoid a port clash which is in another answer of the same thread.

If you take 5432:5432, this might conflict with a local installation of postgres on Windows which uses port 5432 as a standard. You can find out about such a conflict by opening psql, logging in with the menu (in the standard test phase, you will probably just need to press Enter at any menu point) and then print all available databases with \l. If these are the databases of your local Windows installation, you know that you have to use another port when using docker.

If there is a conflict between the ports, use a new port for the Docker host, either with parameter

-p 5433:5432

or when using docker-compose, the file needs to have:

ports:
    - "5433:5432"

It is not relevant whether you start in -d detached mode or not:

`docker-compose up -d`

or:

`docker-compose up`

With the latter, you will just see every change directly in the container log.

Check that your container is started:

docker ps -a

If it is not started, start with:

docker container start CONTAINER_NAME

The container PORTS attribute will look as follows:

0.0.0.0:5433->5432/tcp, :::5433->5432/tcp

That means: the container uses port 5433 for the Docker host (Linux) which can then find the Docker container (Linux) at port 5432.

Use psql on Windows to connect to the Docker container

After this, you can open psql on Windows, in the easy test phase you will usually just need to press enter for every menu point except for the port where you enter 5433 to connect to the Docker host (Linux):

Server [localhost]:
Database [postgres]:
Port [5432]: 5433
Username [postgres]:
Passwort für Benutzer postgres:
psql (13.3, Server 10.3)
Warnung: Konsolencodeseite (850) unterscheidet sich von der Windows-
         Codeseite (1252). 8-Bit-Zeichen funktionieren möglicherweise nicht
         richtig. Einzelheiten finden Sie auf der psql-Handbuchseite unter
         »Notes for Windows users«.
Geben Sie »help« für Hilfe ein.

postgres=#

and then you will be in the postgres shell and \l will show that you are in the container's postgres and not in the Windows postgres, since it will have the databases of the container. In my case, I added the database db with the docker-compose file, and there it is:

postgres=# \l
                                 Liste der Datenbanken
   Name    | Eigent³mer | Kodierung | Sortierfolge | Zeichentyp |  Zugriffsprivilegien
-----------+------------+-----------+--------------+------------+-----------------------
 db        | postgres   | UTF8      | en_US.utf8   | en_US.utf8 |
 postgres  | postgres   | UTF8      | en_US.utf8   | en_US.utf8 |
 template0 | postgres   | UTF8      | en_US.utf8   | en_US.utf8 | =c/postgres          +
           |            |           |              |            | postgres=CTc/postgres
 template1 | postgres   | UTF8      | en_US.utf8   | en_US.utf8 | =c/postgres          +
           |            |           |              |            | postgres=CTc/postgres
(4 Zeilen)

While I had different databases on my Windows local PostgreSQL installation.

For example, you could now connect to the db database:

\c db

Create an empty table:

CREATE TABLE "test" (

);

and show the tables:

\dt

db=# create table test (); CREATE TABLE db=# \dt Liste der Relationen Schema | Name | Typ | Eigent³mer --------+----------------+---------+------------ public | test | Tabelle | db (1 Zeile)

Use psql on the Linux container to check the new table

At the same time, this table will be available in the container since you have now changed the container from outside. In the normal Linux terminal of your WSL, run:

docker exec -it CONTAINER_ID_OR_NAME psql -U postgres -W -d db

Which leads to:

Password for user postgres:
psql (10.3)
Type "help" for help.

db=# \dt
             List of relations
 Schema |      Name      | Type  |  Owner
--------+----------------+-------+----------
 public | test           | table | postgres
(1 row)

Sidenote about -W

By the way, using -W seems recommended as the PostgreSQL docs say about it:

Force psql to prompt for a password before connecting to a database.

This option is never essential, since psql will automatically prompt for a password if the server demands password authentication. However, psql will waste a connection attempt finding out that the server wants a password. In some cases it is worth typing -W to avoid the extra connection attempt.

-W does not expect a value after it, that is, the plain text password does not follow the -W. Instead, it just shows that the user will have to enter a password to connect, which is avoiding one useless connection attempt.

Strangely, at the password prompt, I could also enter a wrong password or none at all and still enter the database.

questionto42
  • 7,175
  • 4
  • 57
  • 90
1

To connect to a container from your host you have to publish ports to your host. That is done using port publishing and -p option :

docker run -it -v D:/postgres:/home/dump --name some_postgres -p 5432:5432 -e POSTGRES_PASSWORD=root -d postgres

Notice the -p option. Now when you will be trying to connect to port 5432 on your localhost, the traffic will be redirected to the port 5432 of the container.

Michał Krzywański
  • 15,659
  • 4
  • 36
  • 63
  • 1
    This doesn't matter. If you run 'docker ps' you will see that the container already publish the port 5432. Did you try your "solution"? – FlorianSchunke Jul 11 '19 at 16:53
  • Please copy and paste what your `docker ps` shows for PORTS column. – Michał Krzywański Jul 11 '19 at 17:05
  • And yes I actually tested it specially for you with Docker For Windows. And with my solution I can connect to Postgres instance from client running on my host. Your PORTS column probably shows `5432/tcp` but that does not mean you can reach the container from your host on that port - it means that this container exposes something on this port. For a "solution" check my answer. And after applying that you will get `0.0.0.0:5432->5432/tcp` in your PORTS column. BTW Have you even tried my "solution"? – Michał Krzywański Jul 11 '19 at 17:12
  • 1
    Your solution I tried prior, even before I posted the thread here. I already change the port to `5433:5432` to avoid any port clash with a probably local running database. But still the same. `40277b8c7256 postgres "docker-entrypoint.s…" 2 hours ago Up 2 hours 5432/tcp, 0.0.0.0:5432->5433/tcp p1` and `psql -U postgres -h ` results in `D:\>psql -h 192.168.116.74 -U postgres -p 5433 psql: could not connect to server: Connection refused (0x0000274D/10061) Is the server running on host "192.168.116.74" and accepting TCP/IP connections on port 5433?` – FlorianSchunke Jul 11 '19 at 19:18
  • `Up 2 hours 5432/tcp, 0.0.0.0:5432->5433/tcp` - db in exposed from the container on port 5432, but i do not know why you mapped port `5432` of localhost to `5433` in the container - there is probably nothing in the container exposed on port `5433`. Use command that I posted in my answer and try to run `psql -h localhost -U postgres -p 5432` – Michał Krzywański Jul 11 '19 at 19:24
  • You probably had a typo in exposing ports because your `-p 5433:5432` option does not match the output `0.0.0.0:5432->5433/tcp `. Ports are reversed. – Michał Krzywański Jul 11 '19 at 19:32
  • This was exactly my issue. Now it is working. Prior I did `docker run ... 5432:5432` without `-d` and tried to connect from a different terminal and got the `connection refused` error. Now I start a detached container and everything works fine. Sorry about my sarcasm but I was frustrated because I did not know what I am doing wrong. – FlorianSchunke Jul 11 '19 at 19:38
  • @MichałKrzywański `-p 5433:5432` does lead to `0.0.0.0:5432->5433/tcp`, at least in my tests. Your comment seems wrong. – questionto42 Aug 25 '21 at 19:27
  • @FlorianSchunke The problem that you probably had was that there was a conflict with an existing postgres installation on Windows which uses port `5432` by default and then "occupies" it so that you cannot reach the Linux Docker host on the same port. That is why I added another answer. In the end, this answer works only if you have no PostgreSQL standard installation on Windows. It is not about running in `-d` mode or not. (Just make sure as well that your container is started at all, of course.) – questionto42 Aug 26 '21 at 12:09