You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8.0+Playwright+NUnit Docker部署:Chromium可执行文件缺失求助

问题描述

我正在开发基于.NET 8.0、C#、NUnit测试框架和Playwright的测试项目,编写了如下Dockerfile:

# Use an official .NET 8.0 SDK base image
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env

# Set the working directory to /app
WORKDIR /app

# Copy csproj and restore NuGet packages
COPY *.sln ./
COPY EncryptionDecryptionUsingSymmetricKey/EncryptionDecryptionUsingSymmetricKey.csproj EncryptionDecryptionUsingSymmetricKey/
COPY MyTestProject/MyTestProject.csproj MyTestProject/
RUN dotnet restore

#Installing Playwright Separately
RUN rm -rf /root/.cache/ms-playwright
RUN apt-get update && apt-get install -y chromium
ENV CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium-browser
RUN apt-get update
RUN apt-get -y install curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_16.x  | bash -
RUN apt-get -y install nodejs
RUN npm install playwright
ENV CHROMIUM_EXECUTABLE_PATH=/root/.cache/ms-playwright/chromium-1117/chrome-linux/chrome
RUN export PWADIR=/root/.cache/ms-playwright/chromium-1117/chrome-linux/chrome
RUN echo "Chromium Executable Path: $CHROMIUM_EXECUTABLE_PATH"  # Verify the Chromium executable path
RUN apt-get update && apt-get install -y --no-install-recommends \
    fonts-liberation\
    libasound2\
    libatk-bridge2.0-0\
    libatk1.0-0\
    libatspi2.0-0\
    libcairo2\
    libcups2\
    libdbus-1-3\
    libdrm2\
    libgbm1\
    libglib2.0-0\
    libgtk-3-0\
    libnspr4\
    libnss3\
    libpango-1.0-0\
    libx11-6\
    libxcb1\
    libxcomposite1\
    libxdamage1\
    libxext6\
    libxfixes3\
    libxrandr2
    
# Copy the rest of the application code
COPY . .

# Install NUnit and Microsoft.Playwright.NUnit NuGet packages
RUN dotnet add MyTestProject package NUnit --version 3.14.0
RUN dotnet add MyTestProject package Microsoft.Playwright.NUnit --version 1.44.0
RUN dotnet add MyTestProject package Microsoft.Extensions.Configuration --version 8.0.0
RUN dotnet add MyTestProject package Microsoft.Extensions.Configuration.Abstractions --version 8.0.0
RUN dotnet add MyTestProject package Microsoft.Extensions.Configuration.Json --version 8.0.0
RUN dotnet add MyTestProject package Microsoft.NET.Test.Sdk --version 17.8.0
RUN dotnet add MyTestProject package NUnit.Analyzers --version 3.9.0
RUN dotnet add MyTestProject package NUnit3TestAdapter --version 4.5.0
RUN dotnet add MyTestProject package Allure.NUnit --version 2.12.1
RUN dotnet add MyTestProject package coverlet.collector --version 6.0.0


# Build the application
RUN dotnet build


# Installing browser msedge
RUN dotnet tool update --global PowerShell
#RUN apt-get update && apt-get install -y microsoft-edge-dev
#RUN echo $PATH | grep -q '/usr/bin/microsoft-edge-dev' || (echo "Error: Microsoft Edge not found in PATH" && exit 1)

 # Set the environment variable to point to the Microsoft Edge binary for Playwright
ENV PLAYWRIGHT_BROWSERS_PATH=/usr/bin/microsoft-edge-dev

#Installing Playwright using playwright.ps1
RUN pwsh /app/MyTestProject/bin/Debug/net8.0/playwright.ps1 install
RUN pwsh /app/MyTestProject/bin/Debug/net8.0/playwright.ps1 install-deps chromium

RUN dotnet publish MyTestProject/MyTestProject.csproj -c Release -o out

#Runtime
FROM mcr.microsoft.com/dotnet/sdk:8.0

# Set the working directory inside the container
WORKDIR /app

# Copy the built application from the build stage into this stage
COPY --from=build-env /app/out .

# Execute the tests
ENTRYPOINT ["dotnet", "test", "MyTestProject.dll", "--settings:Runset.runsettings"]

构建后运行测试时出现如下错误:

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
  Failed LogInInfo(MyTestProject.Assets.QA.TestsData.TestDataObj.Login) [649 ms]

Error Message:
   Microsoft.Playwright.PlaywrightException : Executable doesn't exist at /root/.cache/ms-playwright/chromium-1117/chrome-linux/chrome
╔════════════════════════════════════════════════════════════╗
║ Looks like Playwright was just installed or updated.       ║
║ Please run the following command to download new browsers: ║
║                                                            ║
║     pwsh bin/Debug/netX/playwright.ps1 install             ║
║                                                            ║
║ <3 Playwright Team                                         ║
╚════════════════════════════════════════════════════════════╝
  Stack Trace:
     at Microsoft.Playwright.Transport.Connection.InnerSendMessageToServerAsync[T](ChannelOwner object, String method, Dictionary`2 dictionary, Boolean keepNulls) in /_/src/Playwright/Transport/Connection.cs:line 206
   at Microsoft.Playwright.Transport.Connection.WrapApiCallAsync[T](Func`1 action, Boolean isInternal) in /_/src/Playwright/Transport/Connection.cs:line 532
   at Microsoft.Playwright.Core.BrowserType.LaunchAsync(BrowserTypeLaunchOptions options) in /_/src/Playwright/Core/BrowserType.cs:line 56
   at Microsoft.Playwright.NUnit.BrowserService.CreateBrowser(IBrowserType browserType) in /_/src/Playwright.NUnit/BrowserService.cs:line 55
   at Microsoft.Playwright.NUnit.BrowserService.<>c__DisplayClass5_0.<Register>b__0>d.MoveNext() in /_/src/Playwright.NUnit/BrowserService.cs:line 45
--- End of stack trace from previous location ---
   at Microsoft.Playwright.NUnit.WorkerAwareTest.RegisterService[T](String name, Func`1 factory) in /_/src/Playwright.NUnit/WorkerAwareTest.cs:line 55
   at Microsoft.Playwright.NUnit.BrowserTest.BrowserSetup() in /_/src/Playwright.NUnit/BrowserTest.cs:line 46
   at NUnit.Framework.Internal.TaskAwaitAdapter.GenericAdapter`1.BlockUntilCompleted()
   at NUnit.Framework.Internal.MessagePumpStrategy.NoMessagePumpStrategy.WaitForCompletion(AwaitAdapter awaiter)
   at NUnit.Framework.Internal.AsyncToSyncAdapter.Await(Func`1 invoke)
   at NUnit.Framework.Internal.Commands.SetUpTearDownItem.RunSetUpOrTearDownMethod(TestExecutionContext context, IMethodInfo method)
   at NUnit.Framework.Internal.Commands.SetUpTearDownItem.RunSetUp(TestExecutionContext context)
   at NUnit.Framework.Internal.Commands.SetUpTearDownCommand.<>c__DisplayClass0_0.<.ctor>b__0(TestExecutionContext context)
   at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0()
   at NUnit.Framework.Internal.Commands.DelegatingTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action)

检查镜像后发现没有/root/.cache目录,不清楚问题出在哪。


问题排查与修复方案

核心问题分析

  1. 多阶段构建上下文丢失:build-env阶段中通过playwright.ps1 install下载的浏览器缓存(/root/.cache/ms-playwright)没有被复制到最终的runtime阶段,runtime阶段是全新的镜像,仅复制了发布后的out目录,导致Playwright找不到浏览器可执行文件。
  2. 重复安装导致路径冲突:同时用npm install playwright和.NET的playwright.ps1安装Playwright,两种方式的浏览器存储路径不同,后续设置的CHROMIUM_EXECUTABLE_PATH指向了npm安装的路径,但实际运行时依赖的是.NET版的浏览器路径。
  3. 环境变量设置混乱且未传递:CHROMIUM_EXECUTABLE_PATH和PLAYWRIGHT_BROWSERS_PATH多次修改,且未将关键环境变量传递到runtime阶段,Playwright无法正确识别浏览器位置。
  4. 冗余依赖安装:安装nodejs和npm完全不必要,.NET版Playwright自带工具链,不需要依赖Node环境。

修复后的Dockerfile

# 构建阶段:使用.NET 8 SDK镜像
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
WORKDIR /app

# 复制项目文件并还原依赖
COPY *.sln ./
COPY EncryptionDecryptionUsingSymmetricKey/EncryptionDecryptionUsingSymmetricKey.csproj EncryptionDecryptionUsingSymmetricKey/
COPY MyTestProject/MyTestProject.csproj MyTestProject/
RUN dotnet restore

# 复制所有代码
COPY . .

# 安装测试依赖(建议直接在项目csproj中配置,而非在Dockerfile中添加)
RUN dotnet add MyTestProject package NUnit --version 3.14.0
RUN dotnet add MyTestProject package Microsoft.Playwright.NUnit --version 1.44.0
RUN dotnet add MyTestProject package Microsoft.Extensions.Configuration --version 8.0.0
RUN dotnet add MyTestProject package Microsoft.Extensions.Configuration.Abstractions --version 8.0.0
RUN dotnet add MyTestProject package Microsoft.Extensions.Configuration.Json --version 8.0.0
RUN dotnet add MyTestProject package Microsoft.NET.Test.Sdk --version 17.8.0
RUN dotnet add MyTestProject package NUnit.Analyzers --version 3.9.0
RUN dotnet add MyTestProject package NUnit3TestAdapter --version 4.5.0
RUN dotnet add MyTestProject package Allure.NUnit --version 2.12.1
RUN dotnet add MyTestProject package coverlet.collector --version 6.0.0

# 构建项目
RUN dotnet build

# 安装Playwright浏览器及依赖(使用.NET官方工具,无需Node)
RUN dotnet tool install --global Microsoft.Playwright.CLI
ENV PATH="$PATH:/root/.dotnet/tools"
RUN playwright install chromium
RUN playwright install-deps chromium

# 发布测试项目
RUN dotnet publish MyTestProject/MyTestProject.csproj -c Release -o out

# 运行阶段:复用SDK镜像(或改用runtime镜像,需确保包含测试依赖)
FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app

# 复制发布文件和Playwright浏览器缓存
COPY --from=build-env /app/out .
COPY --from=build-env /root/.cache/ms-playwright /root/.cache/ms-playwright

# 设置环境变量,指定浏览器路径(可选,Playwright默认会读取缓存路径)
ENV PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright

# 执行测试
ENTRYPOINT ["dotnet", "test", "MyTestProject.dll", "--settings:Runset.runsettings"]

关键修复点说明

  • 移除Node.js/npm依赖:完全删除nodejs、curl、gnupg等不必要的安装步骤,改用.NET官方的Microsoft.Playwright.CLI工具安装浏览器。
  • 复制浏览器缓存到runtime阶段:新增COPY --from=build-env /root/.cache/ms-playwright /root/.cache/ms-playwright命令,将构建阶段下载的浏览器文件同步到最终镜像。
  • 统一Playwright安装方式:使用playwright install chromium命令,确保浏览器存储在Playwright默认的缓存路径中,无需手动设置CHROMIUM_EXECUTABLE_PATH。
  • 传递必要环境变量:将PLAYWRIGHT_BROWSERS_PATH设置为缓存路径,确保Playwright能正确找到浏览器。

额外优化建议

  • 将所有NuGet依赖直接配置在MyTestProject.csproj文件中,避免在Dockerfile中重复执行dotnet add package命令,提升构建效率和可维护性。
  • 如果不需要在运行阶段保留SDK,可以改用mcr.microsoft.com/dotnet/runtime:8.0作为基础镜像,但需额外安装测试运行时依赖(如dotnet-runtime-deps和测试工具)。

内容的提问来源于stack exchange,提问作者Kedar Ghadge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:00:55