这个问题花了我一天的时间,我起初觉得这很简单。
我有一台安装了Docker桌面的主机(Windows 10)。从主机,我想使用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!");
}
因此,我希望使用test.exe
在Console
中编写的所有消息都应该返回到父上下文(应该使用相同的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
文件本身的问题?太荒谬了。
更新:感谢@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的信息。您可以将它们复制到容器中。你可以使用像C:\Debuggers\cdb.exe -xe "ld ntdll" test.exe
这样的命令行,它在调试器下启动test.exe,加载ntdll.dll后会立即停止(比正常情况更早)。一旦它停止,你运行!gflag +sls
打开加载器快照,然后运行g
继续执行。检查喷射应告诉您缺少或未加载的内容。
在这种特殊情况下,STATUS_DLL_NOT_FOUND
可能是因为test.exe是.NET Framework应用程序,但是纳米服务器映像中不存在完整的.NET Framework。