Skip to content

Image Export puppeteer not working on dotnet sdk alpine #255

@martijndormans

Description

@martijndormans

Description

When doing integration tests with a dotnet sdk alpine image, I get the error that it can't find the chrome-linux directory.

\u001b[41m\u001b[30mfail\u001b[39m\u001b[22m\u001b[49m: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
       An unhandled exception has occurred while executing the request.
       System.AggregateException: One or more errors occurred. (An error occurred trying to start process '/builds/test/ClientReportConclusionDrawer.Graph.Tests/bin/Release/net6.0/.local-chromium/Linux-884014/chrome-linux/chrome' with working directory '/builds/test/ClientReportConclusionDrawer.Graph.Tests/bin/Release/net6.0'. No such file or directory)
        ---> System.ComponentModel.Win32Exception (2): An error occurred trying to start process '/builds/test/ClientReportConclusionDrawer.Graph.Tests/bin/Release/net6.0/.local-chromium/Linux-884014/chrome-linux/chrome' with working directory '/builds/test/ClientReportConclusionDrawer.Graph.Tests/bin/Release/net6.0'. No such file or directory
          at System.Diagnostics.Process.ForkAndExecProcess(ProcessStartInfo startInfo, String resolvedFilename, String[] argv, String[] envp, String cwd, Boolean setCredentials, UInt32 userId, UInt32 groupId, UInt32[] groups, Int32& stdinFd, Int32& stdoutFd, Int32& stderrFd, Boolean usesTerminal, Boolean throwOnNoExec)
          at System.Diagnostics.Process.StartCore(ProcessStartInfo startInfo)
          at System.Diagnostics.Process.Start()
          at PuppeteerSharp.States.ChromiumStartingState.StartCoreAsync(LauncherBase p) in C:\projects\puppeteer-sharp\lib\PuppeteerSharp\States\ChromiumStartingState.cs:line 68
          at PuppeteerSharp.Launcher.LaunchAsync(LaunchOptions options) in C:\projects\puppeteer-sharp\lib\PuppeteerSharp\Launcher.cs:line 68
          at PuppeteerSharp.Launcher.LaunchAsync(LaunchOptions options) in C:\projects\puppeteer-sharp\lib\PuppeteerSharp\Launcher.cs:line 91
          --- End of inner exception stack trace ---
          at Microsoft.FSharp.Control.AsyncResult`1.Commit() in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 391
          at Microsoft.FSharp.Control.AsyncPrimitives.RunImmediate[a](CancellationToken cancellationToken, FSharpAsync`1 computation) in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1063
          at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1069
          at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1365
          at ClientReportConclusionDrawer.Graph.Services.GraphService.<>c__DisplayClass2_0.<GenerateGaugeGraph>b__0() in /builds/src/ClientReportConclusionDrawer.Graph/Services/GraphService.cs:line 32
          at System.Threading.Tasks.Task`1.InnerInvoke()
          at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
          at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
       --- End of stack trace from previous location ---
          at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
          at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
       --- End of stack trace from previous location ---
          at ClientReportConclusionDrawer.Graph.Services.GraphService.GenerateGaugeGraph(Double score, Int32 width, Int32 height, Int32 dpi, Int32 margin, Tuple`2 range, SupportedImageTypes imageType) in /builds/src/ClientReportConclusionDrawer.Graph/Services/GraphService.cs:line 27
          at ClientReportConclusionDrawer.Graph.Controllers.GraphController.GaugeGraph(GraphRequest request) in /builds/src/ClientReportConclusionDrawer.Graph/Controllers/GraphController.cs:line 20
          at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
          at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
          at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
          at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

When using a custom Docker image installing pupeteer on it, I get a different error saying something about an unhandled exception:

\u001b[41m\u001b[30mfail\u001b[39m\u001b[22m\u001b[49m: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
       An unhandled exception has occurred while executing the request.
       System.AggregateException: One or more errors occurred. (An exception occurred during a WebClient request.)
        ---> System.Net.WebException: An exception occurred during a WebClient request.
        ---> System.IO.IOException: Unable to read data from the transport connection: Connection reset by peer.
        ---> System.Net.Sockets.SocketException (104): Connection reset by peer
          at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.CreateException(SocketError error, Boolean forAsyncThrow)
          at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ReceiveAsync(Socket socket, CancellationToken cancellationToken)
          at System.Net.Sockets.Socket.ReceiveAsync(Memory`1 buffer, SocketFlags socketFlags, Boolean fromNetworkStream, CancellationToken cancellationToken)
          at System.Net.Sockets.NetworkStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
          at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](TIOAdapter adapter)
          at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
          at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](TIOAdapter adapter)
          at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
          at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
          at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
          at System.Net.Security.SslStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
          at System.Net.Http.HttpConnection.ReadAsync(Memory`1 destination)
          at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
          at System.Net.Http.HttpConnection.ReadAsync(Memory`1 destination)
          at System.Net.Http.HttpConnection.ContentLengthReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
          at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
          at System.Net.Http.HttpConnection.ContentLengthReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
          at System.Net.WebClient.DownloadBitsAsync(WebRequest request, Stream writeStream, AsyncOperation asyncOp, Action`3 completionDelegate)
          at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s)
          at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
          at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread)
          at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext()
          at System.Threading.ThreadPool.<>c.<.cctor>b__86_0(Object state)
          at System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1.SignalCompletion()
          at Microsoft.Win32.SafeHandles.SafeFileHandle.ThreadPoolValueTaskSource.ExecuteInternal()
          at Microsoft.Win32.SafeHandles.SafeFileHandle.ThreadPoolValueTaskSource.<>c.<System.Threading.IThreadPoolWorkItem.Execute>b__18_0(ThreadPoolValueTaskSource x)
          at Microsoft.Win32.SafeHandles.SafeFileHandle.ThreadPoolValueTaskSource.System.Threading.IThreadPoolWorkItem.Execute()
          at System.Threading.ThreadPoolWorkQueue.Dispatch()
          at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
          at System.Threading.Thread.StartCallback()
       --- End of stack trace from previous location ---
       
          --- End of inner exception stack trace ---
          at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](TIOAdapter adapter)
          at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
          at System.Net.Http.HttpConnection.ReadAsync(Memory`1 destination)
          at System.Net.Http.HttpConnection.ContentLengthReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
          at System.Net.WebClient.DownloadBitsAsync(WebRequest request, Stream writeStream, AsyncOperation asyncOp, Action`3 completionDelegate)
          --- End of inner exception stack trace ---
          at PuppeteerSharp.BrowserFetcher.DownloadAsync(String revision) in C:\projects\puppeteer-sharp\lib\PuppeteerSharp\BrowserFetcher.cs:line 298
          at PuppeteerSharp.BrowserFetcher.DownloadAsync() in C:\projects\puppeteer-sharp\lib\PuppeteerSharp\BrowserFetcher.cs:line 265
          --- End of inner exception stack trace ---
          at Microsoft.FSharp.Control.AsyncResult`1.Commit() in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 391
          at Microsoft.FSharp.Control.AsyncPrimitives.RunImmediate[a](CancellationToken cancellationToken, FSharpAsync`1 computation) in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1063
          at Microsoft.FSharp.Control.AsyncPrimitives.RunSynchronously[T](CancellationToken cancellationToken, FSharpAsync`1 computation, FSharpOption`1 timeout) in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1069
          at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken) in D:\a\_work\1\s\src\fsharp\FSharp.Core\async.fs:line 1365
          at ClientReportConclusionDrawer.Graph.Services.GraphService.<>c__DisplayClass2_0.<GenerateGaugeGraph>b__0() in /builds/src/ClientReportConclusionDrawer.Graph/Services/GraphService.cs:line 32
          at System.Threading.Tasks.Task`1.InnerInvoke()
          at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj)
          at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
       --- End of stack trace from previous location ---
          at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
          at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
       --- End of stack trace from previous location ---
          at ClientReportConclusionDrawer.Graph.Services.GraphService.GenerateGaugeGraph(Double score, Int32 width, Int32 height, Int32 dpi, Int32 margin, Tuple`2 range, SupportedImageTypes imageType) in /builds/src/ClientReportConclusionDrawer.Graph/Services/GraphService.cs:line 27

I am running these integration tests using mcr.microsoft.com/dotnet/sdk:6.0-alpine3.14 base image. So maybe Alpine is to bare bones and I just miss dependencies. Searching on the internet about puppeteer-sharp and alpine I came across that it could be that you need to run puppeteer headless and in sandbox mode. So maybe adding the option to change the LaunchOptions could fix this problem.

Repro steps

  1. To get the first error I made an simple REST API in C# calling a Plotly.NET F# script to generate a gauge graph I made. After that I just return: Chart.toSVGString and give that back to the user, trough the REST call. I used the mcr.microsoft.com/dotnet/sdk:6.0-alpine3.14 docker image and ran the intergration tests on gitlab.

  2. The Docker image I used to get the second error:

FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine3.14

RUN apk add libgdiplus --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted

RUN apk add --no-cache \
  chromium \
  nss \
  freetype \
  harfbuzz \
  ca-certificates \
  ttf-freefont \
  nodejs \
  yarn

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
  PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

RUN yarn add puppeteer@10.0.0

RUN addgroup -S pptruser && adduser -S -g pptruser pptruser \
  && mkdir -p /home/pptruser/Downloads /app \
  && chown -R pptruser:pptruser /home/pptruser \
  && chown -R pptruser:pptruser /app

USER pptruser

Expected behavior

Locally I can run my integration tests and they all work. Running them on a Linux gitlab runner seems to break them. I expect the same result as when I run my tests on my Windows machine.

Actual behavior

The gitlab pipeline breaks when runinning the first two integration tests.

Known workarounds

Using the custom Dockerfile (that I published: https://hub.docker.com/repository/docker/whyellowmd/dotnet-puppeteer) seems to change the error but did not fix it.

Related information

  • Alpine 3.14
  • Plotly.NET 2.0.0-preview.16

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions