我正在使用一个 docker 容器,里面有两个应用程序。第一个应用程序是 .net 7 上的 Web API,它启动第二个应用程序(使用
Process Start()
方法)。第二个应用程序是 Watson lite Web 服务器(控制台应用程序)。 Watson lite Web 服务器侦听 127.0.0.1:9000
。启动 Watson lite Web 服务器后,Web api .net 7 应用程序将发布请求发送到 http://127.0.0.1:9000/calculate/
- Watson lite Web 服务器执行计算并返回响应。如果您在 Windows 11 上测试此类配置,则一切正常,但如果您创建并运行 docker 容器,.net 7 Web api 会成功启动 Watson lite Web 服务器,但当 .net 7 Web api 应用程序尝试发送返回对 http://127.0.0.1:9000/calculate/
错误的请求:连接被拒绝 (127.0.0.1:9000)。
可能是什么错误?
.net 7 Web api 应用程序通过 ENTRY POINT docker 命令作为主进程启动。
我尝试运行 Watson lite,指定地址
0.0.0.0
而不是 127.0.0.1
或仅指定 *
。没有什么帮助...
可能是用户访问权限有问题?我进入工作的 docker 容器并在 curl
命令的帮助下一切正常......
以下是控制台应用程序中 Watson lite Web 服务器的示例代码:
internal class Program
{
private static CancellationTokenSource cts = new CancellationTokenSource();
static async Task Main(string[] args)
{
// define host:
string host = "+";
// define port:
int port = 9000;
// set up web server settings:
WebserverSettings settings = new WebserverSettings(host, port, false);
// create watson lite web server:
WebserverLite server = new WebserverLite(settings, DefaultRoute);
try
{
// set up CalculateRoute:
server.Routes.PreAuthentication.Parameter.Add(WatsonWebserver.Core.HttpMethod.POST, "/calculate/", CalculateRoute);
// set up StopRoute:
server.Routes.PreAuthentication.Parameter.Add(WatsonWebserver.Core.HttpMethod.GET, "/stop/", StopRoute);
// start server:
server.Start();
// wait for cancellation token to cancel:
await Task.Delay(-1, cts.Token);
}
catch (Exception exception)
{
// if there some exception occured or calcullation token canceled,
// then stop the server:
server.Stop();
}
finally
{
// release resources:
cts.Dispose();
}
}
/// <summary>perform calculations:</summary>
private static async Task CalculateRoute(HttpContextBase ctx)
{
// get task as json string:
string inputJson = ctx.Request.DataAsString;
// perform calculations:
string result = Calculate(inputJson);
// return the result:
await ctx.Response.Send(result);
}
/// <summary>stop web server</summary>
private static async Task StopRoute(HttpContextBase ctx)
{
cts.Cancel();
await ctx.Response.Send("Sent stop signal to server");
}
}
Web api .net 7 应用程序(docker 容器中的主要入口点):
[ApiController]
[Route("solve/")]
public async Task<JsonResult> Post(SolveTaskInputDto calculatorModel, int id, CancellationToken ct)
{
try
{
// create Process object:
using Process prs = new Process();
// fill data:
// path to executable file for console app (with Watson lite web server inside):
prs.StartInfo.FileName = pathToWatsonLiteExecutableFile;
prs.StartInfo.UseShellExecute = false;
prs.StartInfo.RedirectStandardOutput = true;
// start Watson Lite web server:
prs.Start()
// create query body:
HttpContent httpContent = new StringContent(
JsonConvert.SerializeObject(calculatorModel),
// use UTF8 encoding
Encoding.UTF8,
// and json data format:
"application/json");
// send post query:
HttpResponseMessage response = await _httpClient.PostAsync("http://127.0.0.1:9000/calculate/", httpContent, ct);
response.EnsureSuccessStatusCode();
// get data as string:
string result = await response.Content.ReadAsStringAsync(ct);
// return result:
return new JsonResult(resultDto);
}
catch(Exception exp)
{
return new JsonResult(exp.Message);
}
}
Dockerfile:
# ====== .NET CORE SDK ======
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
COPY my_nuget_packages/*.nupkg /nuget_local/
# Add package sources
RUN echo "\
<configuration>\
<packageSources>\
<clear />\
<add key=\"nuget.org\" value=\"https://api.nuget.org/v3/index.json\" protocolVersion=\"3\" />\
<add key=\"local\" value=\"/nuget_local\" />\
</packageSources>\
</configuration>\
" > ${HOME}/CustomNuGet.config
# ====== Web.Api ======
WORKDIR /source_api
ARG api_project_prefix=Web.Api
# ====== restore ======
COPY ${api_project_prefix}/*.sln ./
COPY ${api_project_prefix}/Web.Api/*.csproj ./Web.Api/
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
RUN dotnet restore\
--configfile ${HOME}/CustomNuGet.config\
--packages /nuget/packages\
Web.Api\
-r linux-x64\
--no-cache
#/p:PublishSingleFile=true\
#/p:PublishReadyToRun=true
# copy everything else and build app
COPY ${api_project_prefix}/ .
# ====== build ======
RUN dotnet build\
Web.Api\
-c Release\
-r linux-x64\
--packages /nuget/packages\
--no-cache\
--no-restore\
--self-contained true
#/p:PublishSingleFile=true\
#/p:PublishReadyToRun=true
# ====== publish ======
RUN dotnet publish\
Web.Api\
-o /published/api\
-c Release\
-r linux-x64\
--packages /nuget/packages\
--no-cache\
--no-restore\
--no-build\
--self-contained true
#/p:PublishSingleFile=true\
#/p:PublishReadyToRun=true
# ====== Watson.App.Console ======
WORKDIR /source_watson_console
ARG watson_console_project_prefix=Watson.App.Console
# ====== restore ======
COPY ${watson_console_project_prefix}/*.sln ./
COPY ${watson_console_project_prefix}/Watson.App.Console/*.csproj ./Watson.App.Console/
RUN dotnet restore\
--configfile ${HOME}/CustomNuGet.config\
--packages /nuget/packages\
Watson.App.Console\
-r linux-x64\
--no-cache
#/p:PublishSingleFile=true\
#/p:PublishReadyToRun=true
# copy everything else and build app
COPY ${watson_console_project_prefix}/ .
# ====== build ======
RUN dotnet build\
Watson.App.Console\
-c Release\
-r linux-x64\
--packages /nuget/packages\
--no-cache\
--no-restore\
--self-contained true
#/p:PublishSingleFile=true\
#/p:PublishReadyToRun=true
# ====== publish ======
RUN dotnet publish\
Watson.App.Console\
-o /published/cas_console\
-c Release\
-r linux-x64\
--packages /nuget/packages\
--no-cache\
--no-restore\
--no-build\
--self-contained true
#/p:PublishSingleFile=true\
#/p:PublishReadyToRun=true
# ====== ASPNET CORE RUNTIME ======
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
RUN addgroup --system --gid 1000 dotnet && adduser --system --gid 1000 dotnet
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1\
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false\
DOTNET_USE_POLLING_FILE_WATCHER=true\
TZ=Europe/Moscow\
LC_ALL=ru_RU.UTF-8\
LANG=ru_RU.UTF-8\
DOTNET_RUNNING_IN_CONTAINER=true
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app_watson_console
COPY --from=build /published/watson_console ./
WORKDIR /app_api
COPY --from=build /published/api ./
RUN mkdir data
# ====== production ======
EXPOSE 8065
ENTRYPOINT ["./Web.Api"]
以及 Docker Compose 文件:
version: '3.9'
name: web-api
networks:
web-api-network:
services:
seq:
image: datalust/seq:latest
container_name: seq-container
volumes:
- /seq/data:/data
environment:
ACCEPT_EULA: "Y"
ports:
- "15432:80" # for UI
restart: always
networks:
- web-api-network
web-api:
image: web-api:12-05-2023-v-1
container_name: web-api-container-v-1
volumes:
- /web/api/data:/app_api/data
environment:
ASPNETCORE_ENVIRONMENT: "Production"
ASPNETCORE_URLS: "http://+:8065"
Logging__Console__FormatterName: "Simple"
SeqSettings__SeqHost: "http://seq:5341"
PathToWatsonLiteExecutableFile__AppPath: "/app_cas_console/Watson.App.Console"
ports:
- "18065:8065"
restart: always
networks:
- web-api-network
depends_on:
- seq
您的 docker 容器正在侦听 8065 并推送到 18065。没有端口 9000 传递到您的 docker 容器。尝试为 UI 使用端口 80,为 api 主机使用 8065。
问题已解决: 我从 Web api 应用程序使用 Watson Web 服务器启动控制台应用程序,在 Process.Start 之后,我立即将查询发送到 Watson Web 服务器。但 Watson 没有时间启动,并且出现连接拒绝错误。但如果在发送查询之前等待 1 秒,一切都会正常!