从Windows Docker主机连接到Docker化的PostgreSQL

3

我的设置是在装有postgres(只有命令行工具,没有数据库)的Windows 10 Pro机器上安装Docker for Windows(版本为18.09.2)。

我使用来自docker hub的官方postgres镜像运行以下命令:

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

之后,我可以通过以下方式进行连接

docker exec -it <docker-id> bash

并运行

psql -U postgres

一切都运作良好。现在我想从我的主机连接。我拨打

psql -h <local-ip> -U postgres

并获得了

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?

我很确定,数据库是可以访问的。因为如果我更改IP地址,我就能收到反馈。

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?

有人知道我该如何解决这个问题吗?或者是我做错了什么吗?

事实证明,这个问题应该是:当标准端口5432已被Windows PostgreSQL安装使用时,如何从Windows Docker主机连接到dockerized postgres?至少从第一个答案下的评论中可以看出,可能存在冲突。OP的评论“为避免与可能正在运行的本地数据库发生任何端口冲突”,以及其他评论中的误解都表明了这一点。改变这个问题是不公平的,因为第一个答案在没有占用端口5432的情况下确实有效。 - questionto42
2个回答

3
我花了相当长的时间才找到如何在Windows上正常的psql提示符中访问容器数据库,这是由于额外的本地Windows安装造成的。

创建一个没有端口冲突的Docker容器(Linux)在5432

端口参数的结构(无论是在docker run还是在docker-compose中)是:

<docker_host_port_on_linux>:<docker_container_port_on_linux>

参见从外部连接Docker容器中的Postgresql<host_port>是你可以在Windows上找到用来连接容器端口的端口。似乎需要的核心技巧是避免端口冲突,这在同一线程的另一个答案中有所提及。

如果你采用5432:5432,这可能会与Windows上的本地postgres安装发生冲突,后者使用5432作为标准端口。你可以通过打开psql,在菜单中登录(在标准测试阶段,你可能只需要在任何菜单点上按Enter键)并打印所有可用的数据库\l,以查明是否存在冲突。如果这些是你本地Windows安装的数据库,则知道在使用docker时必须使用另一个端口。

如果端口之间存在冲突,请为Docker主机使用新端口,可以使用参数

-p 5433:5432

当使用docker-compose时,文件需要包含以下内容:

ports:
    - "5433:5432"

无论您是否在-d分离模式下启动,这都是不相关的:

`docker-compose up -d`

或者:

`docker-compose up`

使用后者,您将直接在容器日志中看到每个更改。

检查您的容器是否已启动:

docker ps -a

如果它没有启动,请执行以下操作:
docker container start CONTAINER_NAME

容器的PORTS属性将如下所示:
0.0.0.0:5433->5432/tcp, :::5433->5432/tcp

那意味着:容器使用端口5433用于Docker主机(Linux),然后可以在端口5432找到Docker容器(Linux)。
在Windows上使用psql连接到Docker容器
完成后,您可以在Windows上打开psql,在简单测试阶段,您通常只需要按下每个菜单点的Enter键,除了端口,您需要输入5433来连接到Docker主机(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=#

然后您将进入postgres shell,\l会显示您在容器的postgres中而不是Windows postgres中,因为它将具有容器中的数据库。在我的情况下,我使用docker-compose文件添加了数据库db,如下所示:

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)

我在Windows本地安装的PostgreSQL上有不同的数据库。

例如,您现在可以连接到db数据库:

\c db

创建一个空表格:
CREATE TABLE "test" (

);

并展示表格:
\dt

db=# 创建表test (); CREATE TABLE db=# \dt 关系列表 模式 | 名称 | 类型 | 拥有者 --------+----------------+---------+------------ public | test | 表格 | db (1 行)

使用 Linux 容器上的 psql 检查新表

同时,由于您现在从外部更改了容器,因此该表将在容器中可用。在 WSL 的普通 Linux 终端中运行:

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

这导致:
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)

关于-W的附注

顺便提一下,使用-W似乎是推荐的,正如PostgreSQL文档所说:

强制psql在连接到数据库之前提示输入密码。

这个选项从来不是必要的,因为如果服务器要求密码验证,psql将自动提示输入密码。但是, psql会浪费一个连接尝试去找出服务器需要一个密码。在某些情况下,输入-W可能值得一试,以避免多余的连接尝试。

-W后面不需要跟任何值,也就是说,明文密码不跟在-W后面。相反,它只是表示用户必须输入密码才能连接,以避免一次无用的连接尝试。

奇怪的是,在密码提示符处,我也可以输入错误的密码或者根本不输入密码就进入了数据库。


-p 5433:5432 - 你是我的救星 - Alexufo

1
要从主机连接到容器,您需要将端口发布到主机。这是使用端口发布和 -p 选项完成的:
docker run -it -v D:/postgres:/home/dump --name some_postgres -p 5432:5432 -e POSTGRES_PASSWORD=root -d postgres

请注意-p选项。现在,当您尝试连接本地主机上的端口5432时,流量将被重定向到容器的端口5432

1
这不重要。如果你运行 'docker ps',你会看到容器已经发布了端口5432。你试过你的“解决方案”了吗? - FlorianSchunke
是的,我为你专门使用Docker For Windows测试了它。通过我的解决方案,我可以从运行在主机上的客户端连接到Postgres实例。您的PORTS列可能显示5432/tcp,但这并不意味着您可以在该端口从主机访问容器——它意味着此容器公开了某些内容。有关“解决方案”的详细信息,请查看我的答案。应用后,您将在PORTS列中得到0.0.0.0: 5432-> 5432 / tcp。顺便问一句,你试过我的“解决方案”吗? - Michał Krzywański
1
我之前尝试过你的解决方案,甚至在发布这个帖子之前就已经尝试了。我已经将端口更改为5433:5432,以避免与可能正在运行的本地数据库发生端口冲突。但仍然是相同的结果。40277b8c7256 postgres "docker-entrypoint.s…" 2 hours ago Up 2 hours 5432/tcp, 0.0.0.0:5432->5433/tcp p1psql -U postgres -h <local-ip>的结果是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
@MichałKrzywański -p 5433:5432 在我的测试中确实会导致 0.0.0.0:5432->5433/tcp,你的评论似乎是错误的。 - questionto42
@FlorianSchunke 你可能遇到的问题是在Windows上已经存在一个使用默认端口5432的postgres安装,然后“占用”了它,因此您无法在同一端口上访问Linux Docker主机。这就是为什么我添加了另一个答案。最终,如果您在Windows上没有PostgreSQL标准安装,则此答案才有效。这与是否以“-d”模式运行无关。(当然,还要确保您的容器已启动。) - questionto42
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接