Process.Start не перенаправляет сообщение в родительский контекст, размещенный в Docker? - PullRequest
2 голосов
/ 20 марта 2019

Этот вопрос занял у меня один день, на самом деле я просто подумал, что сначала все просто.

У меня есть хост-компьютер (Windows 10) с установленным рабочим столом Docker для Windows. С хост-машины я хотел бы использовать 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. Я уверен, что код контейнера может получить доступ к этому файлу через общую папку.

Это так странно и трудно диагностировать. Без обмена сообщениями между контейнером и хостом, запуск подобной докер просто бесполезен.

Я надеюсь, что кто-то здесь может дать мне какое-то предложение, чтобы я мог попытаться разобраться в этом. Спасибо!

UPDATE : Если я использую cmd.exe (который уже существует в образе докера) с аргументом /?, то я могу увидеть его вывод. Похоже, что это проблема запуска EXE через папку .

Однако я попытался сначала скопировать общий файл в некоторую локальную папку контейнера и запустить этот файл, но проблема все еще та же. Похоже, это может быть проблема самого файла test.exe? так смешно.

ОБНОВЛЕНИЕ : спасибо @jazzdelightsme за его полезное предложение о проверке ExitCode, так что на самом деле в среде контейнера есть что-то, что не может правильно запустить test.exe. Я попытался скомпилировать test.exe для самой низкой версии .NET Framework версии 2.0, но все еще с той же ошибкой. Вот содержимое 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"]

1 Ответ

1 голос
/ 21 марта 2019

Общая вещь, которую необходимо проверить, это код выхода процесса. Это часто дает понять, в чем проблема.

В этом случае код выхода был STATUS_DLL_NOT_FOUND. Одного этого может быть достаточно, если вы понимаете зависимости своего приложения, потому что вы можете просто вручную проверить контейнер и выяснить, чего не хватает.

Если вы не знаете, чего не хватает, прямой способ отладки - использование отладчиков Windows и включение «Показать оснастку загрузчика». Информация о получении отладчиков Windows здесь . Вы можете скопировать их в контейнер. Вы должны использовать командную строку, такую ​​как 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 отсутствует в образе nanoserver.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...