Process.Start 不会将消息重定向到 docker 托管的父上下文?
Process.Start does not redirect message to the parent context hosted by docker?
这个问题花了我一天的时间,真的,一开始我只是觉得很简单。
我有一台主机 (Windows 10) 安装了用于 Windows 的 Docker 桌面。
从主机上,我想使用 docker run
启动一个容器,其中包含一些简单的代码 运行.
这是代码(在容器中构建),这是一个 .NET 核心控制台应用程序(假设它的构建名称是 console.dll
):
static void Main(string[] args)
{
Console.WriteLine("Running...");
_execTest();
Console.WriteLine("Finished!");
Console.ReadLine();
}
static void _execTest()
{
var sharedFilePath = Path.Combine(Environment.CurrentDirectory, "Temp", "test.exe");
var si = new ProcessStartInfo(sharedFilePath);
si.RedirectStandardOutput = false;
si.RedirectStandardError = false;
si.RedirectStandardInput = false;
Console.WriteLine("Starting ..." + sharedFilePath);
var p = Process.Start(si);
p.WaitForExit();
}
主要代码只是启动另一个名为test.exe
的程序。本程序放在共享文件夹Temp
(调用docker run
时建立,挂载宿主机和容器之间的文件夹)
这是 test.exe
的代码(它只是一个 .NET 控制台应用程序):
static void Main(string[] args)
{
Console.WriteLine("Something went wrong!");
Console.Write("Welldone!");
}
所以我希望使用 Console
在 test.exe
中写入的所有消息都应该被定向回父上下文(应该使用相同的 STDOUT)。
我已经通过 运行直接使用 dotnet console.dll
对容器代码进行了测试,我可以看到预期打印的消息(来自 test.exe
)。
然而,在将 console.dll
部署到映像 (console
) 并尝试对 运行 容器执行以下命令后:
docker run --rm -v D:\SourceFolder:C:\app\Temp console
那么消息(来自test.exe
)就不会被打印出来。仅打印直接在父上下文中写入的消息(Running...
、Starting...
和 Finished!
)。
可以看到上面的命令使用-v
将容器中的文件夹C:\app\Temp
挂载到宿主机中的源文件夹D:\SourceFolder
。
test.exe
放在 D:\SourceFolder
中。
我确定容器的代码可以通过共享文件夹访问此文件。
这太奇怪了,很难诊断。
如果容器和主机之间没有来回共享消息,运行宁docker这样就没用了。
我希望这里有人能给我一些建议,以便我尝试解决这个问题。谢谢!
更新:
如果我使用带有参数 /?
的 cmd.exe
(它已经存在于 docker 图像中),那么我可以看到它的输出。所以看起来这是执行通过文件夹 共享的 EXE 的一些问题。
不过,我尝试先将共享文件复制到容器的某个本地文件夹,然后 运行 该文件,但仍然是同样的问题。所以看起来可能是 test.exe
文件本身的问题?太可笑了
UPDATE:感谢@jazzdelightsme 关于检查 ExitCode
的有用建议,所以实际上容器中的环境缺少一些无法启动 test.exe
正确。我试过针对最低的 .NET Framework 2.0 版编译 test.exe
,但仍然出现同样的错误。这是 Dockerfile
的内容,应该提供有关容器环境的一些信息:
FROM microsoft/dotnet:2.1-runtime-nanoserver-1709 AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk-nanoserver-1709 AS build
WORKDIR /src
COPY ConsoleApp/ConsoleApp.csproj ConsoleApp/
RUN dotnet restore ConsoleApp/ConsoleApp.csproj
COPY . .
WORKDIR /src/ConsoleApp
RUN dotnet build ConsoleApp.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish ConsoleApp.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ConsoleApp.dll"]
要检查的一般故障排除事项是进程的退出代码。这通常会给出问题所在的线索。
在这种情况下,退出代码是 STATUS_DLL_NOT_FOUND
。如果您了解应用程序的依赖项,仅此一项可能就足够了,因为您可以手动检查容器并找出缺少的内容。
如果您不知道缺少什么,调试的直接方法是使用 Windows 调试器并打开 "Show Loader Snaps"。有关获取 Windows 个调试器 here 的信息。您可以将它们 xcopy 到容器中。您可以使用像 C:\Debuggers\cdb.exe -xe "ld ntdll" test.exe
这样的命令行,它在调试器下启动 test.exe,一旦加载 ntdll.dll 就停止(这比正常情况早)。一旦停止,您 运行 !gflag +sls
打开加载程序快照,然后 运行 g
继续执行。检查溢出应该会告诉您缺少或加载失败的内容。
在这种特殊情况下,STATUS_DLL_NOT_FOUND
可能是因为 test.exe 是一个 .NET Framework 应用程序,但 nanoserver 图像中不存在完整的 .NET Framework。
这个问题花了我一天的时间,真的,一开始我只是觉得很简单。
我有一台主机 (Windows 10) 安装了用于 Windows 的 Docker 桌面。
从主机上,我想使用 docker run
启动一个容器,其中包含一些简单的代码 运行.
这是代码(在容器中构建),这是一个 .NET 核心控制台应用程序(假设它的构建名称是 console.dll
):
static void Main(string[] args)
{
Console.WriteLine("Running...");
_execTest();
Console.WriteLine("Finished!");
Console.ReadLine();
}
static void _execTest()
{
var sharedFilePath = Path.Combine(Environment.CurrentDirectory, "Temp", "test.exe");
var si = new ProcessStartInfo(sharedFilePath);
si.RedirectStandardOutput = false;
si.RedirectStandardError = false;
si.RedirectStandardInput = false;
Console.WriteLine("Starting ..." + sharedFilePath);
var p = Process.Start(si);
p.WaitForExit();
}
主要代码只是启动另一个名为test.exe
的程序。本程序放在共享文件夹Temp
(调用docker run
时建立,挂载宿主机和容器之间的文件夹)
这是 test.exe
的代码(它只是一个 .NET 控制台应用程序):
static void Main(string[] args)
{
Console.WriteLine("Something went wrong!");
Console.Write("Welldone!");
}
所以我希望使用 Console
在 test.exe
中写入的所有消息都应该被定向回父上下文(应该使用相同的 STDOUT)。
我已经通过 运行直接使用 dotnet console.dll
对容器代码进行了测试,我可以看到预期打印的消息(来自 test.exe
)。
然而,在将 console.dll
部署到映像 (console
) 并尝试对 运行 容器执行以下命令后:
docker run --rm -v D:\SourceFolder:C:\app\Temp console
那么消息(来自test.exe
)就不会被打印出来。仅打印直接在父上下文中写入的消息(Running...
、Starting...
和 Finished!
)。
可以看到上面的命令使用-v
将容器中的文件夹C:\app\Temp
挂载到宿主机中的源文件夹D:\SourceFolder
。
test.exe
放在 D:\SourceFolder
中。
我确定容器的代码可以通过共享文件夹访问此文件。
这太奇怪了,很难诊断。 如果容器和主机之间没有来回共享消息,运行宁docker这样就没用了。
我希望这里有人能给我一些建议,以便我尝试解决这个问题。谢谢!
更新:
如果我使用带有参数 /?
的 cmd.exe
(它已经存在于 docker 图像中),那么我可以看到它的输出。所以看起来这是执行通过文件夹 共享的 EXE 的一些问题。
不过,我尝试先将共享文件复制到容器的某个本地文件夹,然后 运行 该文件,但仍然是同样的问题。所以看起来可能是 test.exe
文件本身的问题?太可笑了
UPDATE:感谢@jazzdelightsme 关于检查 ExitCode
的有用建议,所以实际上容器中的环境缺少一些无法启动 test.exe
正确。我试过针对最低的 .NET Framework 2.0 版编译 test.exe
,但仍然出现同样的错误。这是 Dockerfile
的内容,应该提供有关容器环境的一些信息:
FROM microsoft/dotnet:2.1-runtime-nanoserver-1709 AS base
WORKDIR /app
FROM microsoft/dotnet:2.1-sdk-nanoserver-1709 AS build
WORKDIR /src
COPY ConsoleApp/ConsoleApp.csproj ConsoleApp/
RUN dotnet restore ConsoleApp/ConsoleApp.csproj
COPY . .
WORKDIR /src/ConsoleApp
RUN dotnet build ConsoleApp.csproj -c Release -o /app
FROM build AS publish
RUN dotnet publish ConsoleApp.csproj -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "ConsoleApp.dll"]
要检查的一般故障排除事项是进程的退出代码。这通常会给出问题所在的线索。
在这种情况下,退出代码是 STATUS_DLL_NOT_FOUND
。如果您了解应用程序的依赖项,仅此一项可能就足够了,因为您可以手动检查容器并找出缺少的内容。
如果您不知道缺少什么,调试的直接方法是使用 Windows 调试器并打开 "Show Loader Snaps"。有关获取 Windows 个调试器 here 的信息。您可以将它们 xcopy 到容器中。您可以使用像 C:\Debuggers\cdb.exe -xe "ld ntdll" test.exe
这样的命令行,它在调试器下启动 test.exe,一旦加载 ntdll.dll 就停止(这比正常情况早)。一旦停止,您 运行 !gflag +sls
打开加载程序快照,然后 运行 g
继续执行。检查溢出应该会告诉您缺少或加载失败的内容。
在这种特殊情况下,STATUS_DLL_NOT_FOUND
可能是因为 test.exe 是一个 .NET Framework 应用程序,但 nanoserver 图像中不存在完整的 .NET Framework。