快速入门:将 Docker 与 Visual Studio 中的 React 单页面应用结合使用

适用范围:yesVisual Studio noVisual Studio for Mac

借助 Visual Studio,可以轻松地生成、调试和运行容器化的 ASP.NET Core 应用(包括使用客户端 JavaScript 的应用,如 React.js 单页应用)并将其发布到 Azure 容器注册表、Docker Hub、Azure 应用服务或你自己的容器注册表。 在本文中,我们将发布到 Azure 容器注册表。

先决条件

  • Docker Desktop
  • 安装了“Web 开发”、“Azure 工具”工作负载和/或“.NET Core 跨平台开发”工作负载的 Visual Studio 2022
  • 若要发布到 Azure 容器注册表,需要 Azure 订阅。 注册免费试用版
  • Node.js
  • 对于 Windows 容器、Windows 10 版本 1809 或更高版本,使用本文中引用的 Docker 映像。

安装和设置

要安装 Docker,请先查看用于 Windows 的 Docker Desktop:安装须知了解相关信息。 然后安装用于 Windows 的 Docker Desktop

创建项目并添加 Docker 支持

  1. 使用“带 React.js 的 ASP.NET Core”模板创建新项目。

    Screenshot of creating a new React.js project.

  2. 在“其他信息”屏幕上,你无法选择“启用 Docker 支持”,但不要担心,可以稍后添加该支持。

    Screenshot of creating a new React.js project - Additional information screen.

  3. 右键单击项目节点,然后选择“添加”>“Docker 支持”,将 Dockerfile 添加到你的项目中。

    Screenshot of Add Docker support menu item.

  4. 选择容器类型。

  1. 使用“带 React.js 的 ASP.NET Core”模板创建新项目。

    Screenshot of creating a new React.js project.

  2. 在“其他信息”屏幕上,你无法选择“启用 Docker 支持”,但不要担心,可以稍后添加该支持。

    Screenshot of creating a new React.js project - Additional information screen.

  3. 右键单击项目节点,然后选择“添加”>“Docker 支持”,将 Dockerfile 添加到你的项目中。

    Screenshot of Add Docker support menu item.

  4. 选择容器类型。

根据你使用的是 Linux 容器还是 Windows 容器,下一步会有所不同。

修改 Dockerfile(Linux 容器)

Dockerfile,用于创建最终 Docker 映像的方案,已在项目中创建。 请参阅 Dockerfile 引用,了解其中的命令。

在项目中打开“Dockerfile”,并添加以下代码行以将 curl、Node.js 14.x 和某些必需的 Node 库安装到容器中。 请务必在第一部分中添加这些行,以将 Node 包管理器 npm.exe 的安装添加到基础映像以及 build 部分中。

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y libpng-dev libjpeg-dev curl libxi6 build-essential libgl1-mesa-glx
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get install -y nodejs

“Dockerfile”现在看起来如下所示:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y libpng-dev libjpeg-dev curl libxi6 build-essential libgl1-mesa-glx
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get install -y nodejs

FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y libpng-dev libjpeg-dev curl libxi6 build-essential libgl1-mesa-glx
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get install -y nodejs
WORKDIR /src
COPY ["ReactSPA/ReactSPA.csproj", "ReactSPA/"]
RUN dotnet restore "ReactSPA/ReactSPA.csproj"
COPY . .
WORKDIR "/src/ReactSPA"
RUN dotnet build "ReactSPA.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ReactSPA.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ReactSPA.dll"]
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y libpng-dev libjpeg-dev curl libxi6 build-essential libgl1-mesa-glx
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get install -y nodejs

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y libpng-dev libjpeg-dev curl libxi6 build-essential libgl1-mesa-glx
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get install -y nodejs
WORKDIR /src
COPY ["ReactSPA/ReactSPA.csproj", "ReactSPA/"]
RUN dotnet restore "ReactSPA/ReactSPA.csproj"
COPY . .
WORKDIR "/src/ReactSPA"
RUN dotnet build "ReactSPA.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ReactSPA.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ReactSPA.dll"]

前面的 Dockerfile 基于 mcr.microsoft.com/dotnet/core/aspnet 映像,并包括通过构建项目并将其添加到容器中修改基本映像的说明。

如果选中了新建项目对话框的“为 HTTPS 配置”复选框,则 Dockerfile 公开两个端口。 一个端口用于 HTTP 流量;另一个端口用于 HTTPS。 如果未选中该复选框,则为 HTTP 流量公开单个端口 (80)。

修改 Dockerfile(Windows 容器)

通过双击项目节点来打开项目文件,然后通过将以下属性添加为 <PropertyGroup> 元素的子元素来更新项目文件 (*.csproj):

 <DockerfileFastModeStage>base</DockerfileFastModeStage>

通过添加以下行来更新 Dockerfile。 这样会将节点和 npm 复制到容器。

  1. # escape=` 添加到 Dockerfile 的第一行

  2. FROM … base 之前添加以下行

    FROM mcr.microsoft.com/powershell AS downloadnodejs
    ENV NODE_VERSION=14.16.0
    SHELL ["pwsh", "-Command", "$ErrorActionPreference = 'Stop';$ProgressPreference='silentlyContinue';"]
    RUN Invoke-WebRequest -OutFile nodejs.zip -UseBasicParsing "https://nodejs.org/dist/v$($env:NODE_VERSION)/node-v$($env:NODE_VERSION)-win-x64.zip"; `
        Expand-Archive nodejs.zip -DestinationPath C:\; `
        Rename-Item "C:\node-v$($env:NODE_VERSION)-win-x64" c:\nodejs
    
  3. FROM … build 之前和之后添加以下行

    COPY --from=downloadnodejs C:\nodejs\ C:\Windows\system32\
    
  4. 完整的 Dockerfile 现在看起来如下所示:

    # escape=`
    #Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
    #For more information, please see https://aka.ms/containercompat
    FROM mcr.microsoft.com/powershell AS downloadnodejs
    ENV NODE_VERSION=14.16.0
    SHELL ["pwsh", "-Command", "$ErrorActionPreference = 'Stop';$ProgressPreference='silentlyContinue';"]
    RUN Invoke-WebRequest -OutFile nodejs.zip -UseBasicParsing "https://nodejs.org/dist/v$($env:NODE_VERSION)/node-v$($env:NODE_VERSION)-win-x64.zip"; \
        Expand-Archive nodejs.zip -DestinationPath C:\; \
        Rename-Item "C:\node-v$($env:NODE_VERSION)-win-x64" c:\nodejs
    
    FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    COPY --from=downloadnodejs C:\nodejs\ C:\Windows\system32\
    
    FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
    COPY --from=downloadnodejs C:\nodejs\ C:\Windows\system32\
    WORKDIR /src
    COPY ["WebApplicationReact1/WebApplicationReact1.csproj", "WebApplicationReact1/"]
    RUN dotnet restore "WebApplicationReact1/WebApplicationReact1.csproj"
    COPY . .
    WORKDIR "/src/WebApplicationReact1"
    RUN dotnet build "WebApplicationReact1.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "WebApplicationReact1.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "WebApplicationReact1.dll"]
    
    # escape=`
    #Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
    #For more information, please see https://aka.ms/containercompat
    FROM mcr.microsoft.com/powershell AS downloadnodejs
    ENV NODE_VERSION=14.16.0
    SHELL ["pwsh", "-Command", "$ErrorActionPreference = 'Stop';$ProgressPreference='silentlyContinue';"]
    RUN Invoke-WebRequest -OutFile nodejs.zip -UseBasicParsing "https://nodejs.org/dist/v$($env:NODE_VERSION)/node-v$($env:NODE_VERSION)-win-x64.zip"; \
        Expand-Archive nodejs.zip -DestinationPath C:\; \
        Rename-Item "C:\node-v$($env:NODE_VERSION)-win-x64" c:\nodejs
    
    FROM mcr.microsoft.com/dotnet/core/aspnet:6.0 AS base
    WORKDIR /app
    EXPOSE 80
    EXPOSE 443
    COPY --from=downloadnodejs C:\nodejs\ C:\Windows\system32\
    
    FROM mcr.microsoft.com/dotnet/core/sdk:6.0 AS build
    COPY --from=downloadnodejs C:\nodejs\ C:\Windows\system32\
    WORKDIR /src
    COPY ["WebApplicationReact1/WebApplicationReact1.csproj", "WebApplicationReact1/"]
    RUN dotnet restore "WebApplicationReact1/WebApplicationReact1.csproj"
    COPY . .
    WORKDIR "/src/WebApplicationReact1"
    RUN dotnet build "WebApplicationReact1.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "WebApplicationReact1.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "WebApplicationReact1.dll"]
    
  5. 通过删除 **/bin来更新 .dockerignore 文件。

调试

设置用于调试的启动属性。 可以使用“开始”按钮旁的下拉菜单,并选择“调试属性”。 在出现的“启动配置文件”对话框中,选择“Docker”。

将“环境变量”设置为以下内容。 SSL 端口号应与“容器”窗口的“端口”选项卡中的 HTTPS“主机端口”匹配。

ASPNETCORE_ENVIRONMENT=Development,ASPNETCORE_HOSTINGSTARTUPASSEMBLIES=Microsoft.AspNetCore.SpaProxy,ASPNETCORE_HTTPS_PORT=<your SSL port>,ASPNETCORE_URLS=https:////+:443;http:////+:80

此操作更改 launchSettings.json 文件中的 Docker 条目,并使 SPA 代理能够正常工作。 在“解决方案资源管理器”的“属性”下,找到 launchSettings.json 文件。 应会看到如下所示的内容,但应用分配的端口号如下:

    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
      "environmentVariables": {
        "ASPNETCORE_URLS": "https://+:443;http://+:80",
        "ASPNETCORE_HTTPS_PORT": "7136",
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
      },
      "publishAllPorts": true,
      "useSSL": true,
      "httpPort": 5136,
      "sslPort":  7136
    }

在工具栏的调试下拉列表中选择“Docker”,然后开始调试应用。 你可能会看到提示信任证书的消息;选择信任证书以继续。 第一次生成时,docker 会下载基础映像,因此可能需要更长的时间。

项目使用 SPA 代理。 如果浏览器在代理准备就绪前加载首页,你可能会看到一个页面,指出在代理准备就绪时会自动重定向。

如果页面从未重定向,请检查是否能够运行代理。 打开 Visual Studio 开发命令提示符,转到项目中的 ClientApp 文件夹,然后提供命令 npm run start。 你应看到与下面类似的内容:

> projectspa1@0.1.0 prestart
> node aspnetcore-https && node aspnetcore-react


> projectspa1@0.1.0 start
> rimraf ./build && react-scripts start

[HPM] Proxy created: [ '/weatherforecast' ]  ->  http://localhost:30449
i 「wds」: Project is running at https://0.0.0.0:44445/
i 「wds」: webpack output is served from
i 「wds」: Content not from webpack is served from c:\Users\ghogen\source\repos\ProjectSpa1\ProjectSpa1\ClientApp\public
i 「wds」: 404s will fallback to /
Starting the development server...
Compiled successfully!

如果成功,请尝试在浏览器中再次启动应用。 如果它未成功,请再次检查 launchSettings.json 文件中的所有内容是否正确。

“输出”窗口中的“容器工具”选项显示正在进行的操作。 你将看到与 npm.exe 关联的安装步骤。

浏览器将显示应用的主页。

Screenshot of running app.

Screenshot of running app.

打开“容器”工具窗口。 可以在“查看”>“其他 Windows”>“容器”下找到它,或按 Ctrl+Q 并开始在搜索框中键入 containers,然后从结果中选择“容器”窗口。 窗口打开时,将其停靠在编辑器窗格的底部。

“容器”窗口显示正在运行的容器,并可查看相关信息。 可以查看环境变量、标签、端口、卷、文件系统和日志。 使用工具栏按钮,可以在容器内创建一个终端(shell 提示)、附加调试器或删除未使用的容器。 请参阅使用“容器”窗口

Screenshot of Containers window.

单击“文件”选项卡,然后展开 app 文件夹以查看已发布的应用程序文件。

还可以查看图像并检查相关信息。 选择“图像”选项卡,找到项目对应的选项卡,然后选择“详细信息”选项卡以查看包含图像相关信息的 json 文件。

Screenshot of Containers window showing images and details.

注意

“开发”映像不包含应用程序二进制文件和其他内容,因为“调试”配置使用卷装载提供迭代编辑和调试体验 。 若要创建包含所有内容的生产映像,请使用“版本”配置。

发布 Docker 映像

完成应用程序的开发和调试循环后,可以创建应用程序的生产映像。

  1. 将配置下拉列表更改为“发布”,然后生成应用。

  2. 在解决方案资源管理器中右键单击项目,并选择“发布” 。

  3. 在“发布目标”对话框中,选择“Docker 容器注册表”。

    Choose Docker Container Registry.

  4. 接下来,选择“Azure 容器注册表”。

    Choose Azure Container Registry.

  5. 选择“新建 Azure 容器注册表”。

  6. 在“新建 Azure 容器注册表”屏幕中填写所需的值。

    设置 建议的值 描述
    DNS 前缀 全局唯一名称 用于唯一标识容器注册表的名称。
    订阅 选择订阅 要使用的 Azure 订阅。
    资源组 myResourceGroup 要在其中创建容器注册表的资源组的名称。 选择“新建” 创建新的资源组。
    SKU 标准 容器注册表的服务层
    注册表位置 靠近你的位置 在你附近或将使用容器注册表的其他服务附近的区域中,选择位置。

    Screenshot of Visual Studio's create Azure Container Registry dialog.

  7. 选择“创建”,然后选择“完成” 。

    Screenshot showing Select or create a new Azure Container Registry.

    发布过程结束时,你可查看发布设置并在需要时对其进行编辑,也可使用“发布”按钮再次发布该图像。

    Screenshot showing successful publish.

    若要使用“发布”对话框重新开始,请使用此页上的“删除”链接删除发布配置文件,然后再次选择“发布” 。

  1. 将配置下拉列表更改为“发布”,然后生成应用。

  2. 在解决方案资源管理器中右键单击项目,并选择“发布” 。

  3. 在“发布目标”对话框中,选择“Docker 容器注册表”。

    Screenshot showing Choose Docker Container Registry.

  4. 接下来,选择“Azure 容器注册表”。

    Screenshot showing Choose Azure Container Registry.

  5. 选择“新建 Azure 容器注册表”。

  6. 在“新建 Azure 容器注册表”屏幕中填写所需的值。

    设置 建议的值 描述
    DNS 前缀 全局唯一名称 用于唯一标识容器注册表的名称。
    订阅 选择订阅 要使用的 Azure 订阅。
    资源组 myResourceGroup 要在其中创建容器注册表的资源组的名称。 选择“新建” 创建新的资源组。
    SKU 标准 容器注册表的服务层
    注册表位置 靠近你的位置 在你附近或将使用容器注册表的其他服务附近的区域中,选择位置。

    Screenshot of Visual Studio's create Azure Container Registry dialog.

  7. 选择“创建”,然后选择“完成” 。

    Screenshot showing Select or create a new Azure Container Registry.

    发布过程结束时,你可查看发布设置并在需要时对其进行编辑,也可使用“发布”按钮再次发布该图像。

    Screenshot showing successful publish

    若要使用“发布”对话框重新开始,请使用此页上的“删除”链接删除发布配置文件,然后再次选择“发布” 。

后续步骤

现在可以将容器从注册表中拖放到任何能够运行 Docker 映像的主机上,例如Azure 容器实例

其他资源