在 Docker Compose Stack 中通过 Npgsql 从 ASP.NET Core 6 连接到 PostgreSql
Connecting to PostgreSql via Npgsql from ASP.NET Core 6 in a Docker Compose Stack
我正在尝试创建一个 docker-compose 脚本来使用 PostgreSql 数据库和 ASP.NET Core 6 Web API 触发堆栈。为了测试这个场景,我使用默认模板创建了一个新的 ASP.NET Core 6 Web API。然后我添加了 NuGet 包 Npgsql
(6.0.3),以及一个仅查询数据库引擎版本的示例控制器,例如:
[ApiController]
[Produces("application/json")]
public class TestController : Controller
{
private readonly IConfiguration _config;
public TestController(IConfiguration config)
{
_config = config;
}
[HttpGet("api/dbversion")]
public IActionResult GetVersion()
{
using NpgsqlConnection conn = new(_config.GetConnectionString("Default"));
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT version();";
return Ok($"Version: {cmd.ExecuteScalar() as string}");
}
}
然后我为此 API 创建了 Docker 图像,并编写了一个 docker-compose 脚本,如下所示:
version: '3.7'
services:
test-db:
image: postgres
# explicit container name
# another approach using hostname:
container_name: test-db
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
ports:
- 5433:5432
networks:
- test-network
test-api:
image: MYREPONAME/test-api:0.0.1
ports:
- 5154:80
depends_on:
- test-db
environment:
- CONNECTIONSTRINGS__DEFAULT=User ID=postgres;Password=postgres;Host=test-db;Port=5433;Database=postgres
networks:
- test-network
networks:
test-network:
driver: bridge
这里我使用的是官方postgres
镜像,设置默认凭证,将服务重定向到compose栈中的5433端口,并从同一网络中的API使用它.我正在覆盖脚本中的连接字符串,使用容器名称作为主机名 (test-db
); localhost
在 Docker 网络中不是一个选项(参见 and here)。
当我从 Ubuntu 主机启动此脚本时,我可以在端口 5433 访问数据库服务,并在 localhost:5154/swagger/index 访问 Web API。 html。然而,当我 运行 应该连接到数据库的操作时,我得到一个连接被拒绝的错误,即使我可以清楚地看到数据库服务 IP 和端口:
"Exception":"Npgsql.NpgsqlException (0x80004005): Failed to connect to 172.27.0.2:5433
---\u003E System.Net.Sockets.SocketException (111): Connection refused
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.\u003COpen\u003Eg__OpenCore|191_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.\u003CGet\u003Eg__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.\u003COpen\u003Eg__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.Open()
...
当一个容器连接到桥接网络上的另一个容器时,您使用容器端口。不是主机上的映射端口。所以你的连接字符串应该是
CONNECTIONSTRINGS__DEFAULT=User ID=postgres;Password=postgres;Host=test-db;Port=5432;Database=postgres
我正在尝试创建一个 docker-compose 脚本来使用 PostgreSql 数据库和 ASP.NET Core 6 Web API 触发堆栈。为了测试这个场景,我使用默认模板创建了一个新的 ASP.NET Core 6 Web API。然后我添加了 NuGet 包 Npgsql
(6.0.3),以及一个仅查询数据库引擎版本的示例控制器,例如:
[ApiController]
[Produces("application/json")]
public class TestController : Controller
{
private readonly IConfiguration _config;
public TestController(IConfiguration config)
{
_config = config;
}
[HttpGet("api/dbversion")]
public IActionResult GetVersion()
{
using NpgsqlConnection conn = new(_config.GetConnectionString("Default"));
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT version();";
return Ok($"Version: {cmd.ExecuteScalar() as string}");
}
}
然后我为此 API 创建了 Docker 图像,并编写了一个 docker-compose 脚本,如下所示:
version: '3.7'
services:
test-db:
image: postgres
# explicit container name
# another approach using hostname:
container_name: test-db
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
ports:
- 5433:5432
networks:
- test-network
test-api:
image: MYREPONAME/test-api:0.0.1
ports:
- 5154:80
depends_on:
- test-db
environment:
- CONNECTIONSTRINGS__DEFAULT=User ID=postgres;Password=postgres;Host=test-db;Port=5433;Database=postgres
networks:
- test-network
networks:
test-network:
driver: bridge
这里我使用的是官方postgres
镜像,设置默认凭证,将服务重定向到compose栈中的5433端口,并从同一网络中的API使用它.我正在覆盖脚本中的连接字符串,使用容器名称作为主机名 (test-db
); localhost
在 Docker 网络中不是一个选项(参见
当我从 Ubuntu 主机启动此脚本时,我可以在端口 5433 访问数据库服务,并在 localhost:5154/swagger/index 访问 Web API。 html。然而,当我 运行 应该连接到数据库的操作时,我得到一个连接被拒绝的错误,即使我可以清楚地看到数据库服务 IP 和端口:
"Exception":"Npgsql.NpgsqlException (0x80004005): Failed to connect to 172.27.0.2:5433
---\u003E System.Net.Sockets.SocketException (111): Connection refused
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.\u003COpen\u003Eg__OpenCore|191_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.ConnectorPool.\u003CGet\u003Eg__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.\u003COpen\u003Eg__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.Open()
...
当一个容器连接到桥接网络上的另一个容器时,您使用容器端口。不是主机上的映射端口。所以你的连接字符串应该是
CONNECTIONSTRINGS__DEFAULT=User ID=postgres;Password=postgres;Host=test-db;Port=5432;Database=postgres