Closed mu88 closed 10 months ago
Looks like your user has no permissions to access /app. Have you tried the following instead of chmod?
RUN chown -R $APP_UID /app
This will give your user permission to /app.
Correct me if I'm wrong, but doesn't chown
change a directory's ownership, and therefore theoretically I could manipulate the /app
directory using the app
user? If yes, I shouldn't do that according to what I learned here:
That's kind of counter to the purpose of using a non-root user - the goal is that nothing in the application's binaries' directory can be changed.
I see! So the executable bit of /app/.playwright/node/linux-x64/playwright.sh
seems not to be set correctly.
Investigation:
When we download the drivers before creating the nuget files we seem to be doing the right thing:
❯ ls -la src/Playwright/.drivers/linux/playwright.sh
-rwxr-xr-x 1 maxschmitt staff 216 Nov 16 22:54 src/Playwright/.drivers/linux/playwright.sh
While on the user side the executable bit is only set for user:
❯ ls -la bin/Debug/net8.0/.playwright/node/darwin-arm64/playwright.sh
-rwxr--r-- 1 maxschmitt staff 222 Nov 21 12:58 bin/Debug/net8.0/.playwright/node/darwin-arm64/playwright.sh
Workaround would be RUN chmod +x /app/.playwright/node/linux-x64/playwright.sh
instead of the chown/chmod which is already better while we figure out a better solution.
cc @campersau looks like when we pack the bit gets filtered out?
The problem is that NuGet pack and also extract does not preserve the executable bit, in fact any "external" attribute is ignored. I have only seen an issue about the readonly attribute in the NuGet repro though: https://github.com/NuGet/Home/issues/11286 So maybe you can open an issue for it as well?
It might be possible to workaround it by adding some more logic to Microsoft.Playwright.targets
and set it manually there but it is not that easy.
NuGet uses the ZipArchive
for packing/extracting the nupkg
. And only "recently" APIs to get/set "external" attributes like the execution bit were made available:
https://apisof.net/catalog/a6f34fac-094f-db3b-e4bc-a1c7ed169602
Pack and extract only tries to preserve timestamps.
Pack: https://github.com/NuGet/NuGet.Client/blob/6e01722cb9d4ede0baa3edc5131a90fe71b6c5fa/src/NuGet.Core/NuGet.Packaging/PackageCreation/Authoring/PackageBuilder.cs#L1011-L1031 https://github.com/NuGet/NuGet.Client/blob/6e01722cb9d4ede0baa3edc5131a90fe71b6c5fa/src/NuGet.Core/NuGet.Packaging/PackageCreation/Authoring/PackageBuilder.cs#L1223-L1237
Interesting, it looks like it was there but was lost to time:
@mxschmitt would it be possible to add chmod +x /app/.playwright/node/*/node
as well? When using a rootless container, the permissions inside the container currently look like this:
app@d9c7ae175924:/app$ ls -lh .playwright/node/linux-x64/
total 92M
-rwxr--r-- 1 root root 92M Jan 19 23:07 node
...which leads to the following error when running my rootless container:
System.ComponentModel.Win32Exception (13): An error occurred trying to start process '/app/.playwright/node/linux-x64/node' with working directory '/app'. Permission denied
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 Microsoft.Playwright.Transport.StdIOTransport.StartProcessWithUTF8IOEncoding(Process process) in /_/src/Playwright/Transport/StdIOTransport.cs:line 168
at Microsoft.Playwright.Transport.StdIOTransport..ctor() in /_/src/Playwright/Transport/StdIOTransport.cs:line 47
at Microsoft.Playwright.Playwright.CreateAsync() in /_/src/Playwright/Playwright.cs:line 44
at ScreenshotCreator.Logic.PlaywrightHelper.InitializePlaywrightAsync() in /src/src/ScreenshotCreator.Logic/PlaywrightHelper.cs:line 36
at ScreenshotCreator.Logic.ScreenshotCreator.CreateScreenshotAsync(UInt32 width, UInt32 height) in /src/src/ScreenshotCreator.Logic/ScreenshotCreator.cs:line 14
at ScreenshotCreator.Api.BackgroundScreenshotCreator.ExecuteAsync(CancellationToken stoppingToken) in /src/src/ScreenshotCreator.Api/BackgroundScreenshotCreator.cs:line 32
at Microsoft.Extensions.Hosting.Internal.Host.<StartAsync>b__15_1(IHostedService service, CancellationToken token)
at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation)
Unhandled exception. System.ComponentModel.Win32Exception (13): An error occurred trying to start process '/app/.playwright/node/linux-x64/node' with working directory '/app'. Permission denied
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 Microsoft.Playwright.Transport.StdIOTransport.StartProcessWithUTF8IOEncoding(Process process) in /_/src/Playwright/Transport/StdIOTransport.cs:line 168
at Microsoft.Playwright.Transport.StdIOTransport..ctor() in /_/src/Playwright/Transport/StdIOTransport.cs:line 47
at Microsoft.Playwright.Playwright.CreateAsync() in /_/src/Playwright/Playwright.cs:line 44
This error disappears when using (see here):
FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
RUN chmod +x /app/.playwright/node/*/node
ENTRYPOINT ["dotnet", "ScreenshotCreator.Api.dll"]
We actually got rid of the playwright.sh
file and do chmod +x
to the node
executable: https://github.com/microsoft/playwright-dotnet/blob/48aec3542af34b77fb927c04c8a993117173a81e/src/Playwright/build/Microsoft.Playwright.targets#L60-L66
Are you on 1.41.2?
We actually got rid of the
playwright.sh
file and dochmod +x
to thenode
executable:Are you on 1.41.2?
1.40.0
We actually got rid of the
playwright.sh
file and dochmod +x
to thenode
executable:Are you on 1.41.2?
1.40.0
Could you try 1.41.2?
Do you have any idea what the problem might be, @mxschmitt ?
Some guesses would be that the user has no permission to run the driver aka. Node.js. Maybe the permission bits get lost when using FROM
inside Docker? I would try tracking it backwards to see when the executable bit got lost. Or maybe try running it as root first, so it might be an ownership problem instead?
Thx for that hint! You're right: when running COPY
in a Dockerfile
, the 'execute' bit gets lost (see here).
I was able to resolve the issue by moving the chmod
command into my base image (see here) and configure PLAYWRIGHT_DRIVER_SEARCH_PATH
. Now I'm even able to use the .NET SDK Container Building Tools for building the app image (see here).
Thx for your help and take care 🙂
System info
v1.40.0
Source code
Link to the GitHub repository with the repro
https://github.com/mu88/ScreenshotCreator/tree/feature/repro-Playwright
Test file (self-contained)
/
Steps
feature/repro-Playwright
from https://github.com/mu88/ScreenshotCreator/docker build --platform linux/amd64 -f .\src\ScreenshotCreator.Api\Dockerfile -t screenshotcreator:dev .
docker run --name screenshotcreator -p:8080:8080 screenshotcreator:dev
Expected
The app starts without errors.
Actual
Starting the app fails with the following error:
Comments
When either adding
RUN chmod -R 777 /app
(see here) or using a root container, everything works as expected.