02 加速构建netcore react app docker镜像 - xiaoxin01/Blog GitHub Wiki
本文介绍如何加速构建.netcore创建的react app 镜像
.net core react app默认创建的dockerfile有2个问题:
- build镜像没有安装node
- 每次都是在publish动作中同时构建react app,即使js没有变化也会重新构建,非常耗时
默认的dockerfile大致如下:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ["src/projecta/projecta.csproj", "src/projecta/"]
RUN dotnet restore "src/projecta/projecta.csproj"
COPY ./src ./src
WORKDIR /src/src/projecta
RUN dotnet build "projecta.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "projecta.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "projecta.dll"]
检查.csproj文件,发现每次在publish的时候会执行npm build动作:
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
为了优化构建过程,我们从上述的2个问题出发:
- 创建新的build stage,用来构建前端react app
- 移除默认的在publish的时候构建动作
为此我们修改dockerfile如下:
LABEL maintainer="Jinxin Chen <[email protected]>"
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM node:12.14.0-alpine3.9 AS nodeBuild
# add node registry for speed up
RUN npm config set registry https://registry.npm.taobao.org --global && \
npm config set disturl https://npm.taobao.org/dist --global
WORKDIR /app
COPY ./src/projecta/ClientApp/package.json /app/package.json
RUN npm install --production
COPY ./src/projecta/ClientApp /app
RUN npm run build
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ["src/projecta/projecta.csproj", "src/projecta/"]
RUN dotnet restore "src/projecta/projecta.csproj"
COPY ./src ./src
WORKDIR /src/src/projecta
RUN dotnet build "projecta.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "projecta.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
COPY --from=nodeBuild /app/build/. ./ClientApp/build/
ENTRYPOINT ["dotnet", "projecta.dll"]
移除.csproj工程文件的<Target Name="PublishRunWebpack"节点
最后别忘了加上.dockerignore文件:
.dockerignore
**/Dockerfile
**/obj
**/bin
**/*.md
.vs/
.vscode/
.git/
在构建后端时有如下步骤:
COPY ./src ./src
这步也会把前端的ClientApp也加入进去,导致如果只是修改前端的code,也会让后端的这段重新build,这里是可以再继续优化的地方,未来再进行
有尝试做进一步优化,希望能够缓存node_modules的内容,让每次构建的时候不用重复下载。
首先,在构建的时候为nodeBuild stage创建一个tag:
docker build --target nodeBuild -t projecta-build:latest .
然后在构建脚本中,每次构建完成,都将node_modules从build镜像中复制出来,以供下次build使用
CID=$(docker create projecta-build:latest)
docker cp ${CID}:/app/node_modules/. node_modules/
docker rm ${CID}
在dockerfile中添加:
COPY node_modules/. /app/node_modules/