我最近成功使用 docker-compose 上的原始源代码部署了 nopCommerce(版本 4.70.0)的实例。 然后我开发了一个自定义插件(这只是一个简单的插件,使用户能够通过手机和 OTP 登录)。但是当我尝试使用源代码并重新创建 docker image/container 来部署它时,我意识到我的插件没有被复制到容器中的 /app/published 文件夹中。那件事被通过了,因为我只是想让它发挥作用。因此,我通过管理面板上传了插件。 之后,我开发了一个简单的主题(只需复制默认主题)并尝试通过重新构建和重新创建 docker 映像和容器来发布它。但是,我再次意识到主题文件夹不会复制到容器中,这与我的自定义插件所发生的情况相同。我认为我做的一切都是对的,但就是行不通。这是我的
Nop.Web.csproj
:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Copyright>Copyright © Nop Solutions, Ltd</Copyright>
<Company>Nop Solutions, Ltd</Company>
<Authors>Nop Solutions, Ltd</Authors>
<Version>4.70.0</Version>
<Description>Nop.Web is also an MVC web application project, a presentation layer for public store and admin area.</Description>
<PackageLicenseUrl>https://www.nopcommerce.com/license</PackageLicenseUrl>
<PackageProjectUrl>https://www.nopcommerce.com/</PackageProjectUrl>
<RepositoryUrl>https://github.com/nopSolutions/nopCommerce</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<ImplicitUsings>enable</ImplicitUsings>
<!--Starting with the .NET 6 SDK, the [Appname].runtimesettings.dev.json file is no longer generated by default at compile time. If you still want this file to be generated, set the GenerateRuntimeConfigDevFile property to true.-->
<GenerateRuntimeConfigDevFile>true</GenerateRuntimeConfigDevFile>
<!--Set this parameter to true to get the dlls copied from the NuGet cache to the output of your project-->
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<!--When true, compiles and emits the Razor assembly as part of publishing the project-->
<RazorCompileOnPublish>false</RazorCompileOnPublish>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\Nop.Core\Nop.Core.csproj" />
<ProjectReference Include="..\..\Libraries\Nop.Data\Nop.Data.csproj" />
<ProjectReference Include="..\..\Libraries\Nop.Services\Nop.Services.csproj" />
<ProjectReference Include="..\Nop.Web.Framework\Nop.Web.Framework.csproj" />
</ItemGroup>
<ItemGroup>
<!-- We copy the entire \App_Data directory. But we ignore JSON files and data protection keys -->
<Content Include="App_Data\**" CopyToPublishDirectory="PreserveNewest" Exclude="App_Data\*.json" />
<Content Remove="App_Data\*.json" />
<Content Update="App_Data\DataProtectionKeys\*.xml" CopyToPublishDirectory="Never" />
<Compile Remove="Plugins\**;Themes\**" />
<Content Remove="Plugins\**;Themes\**" />
<EmbeddedResource Remove="Plugins\**;Themes\**" />
<None Remove="Plugins\**;Themes\**" />
<None Include="Plugins\**" CopyToPublishDirectory="PreserveNewest" Exclude="Plugins\**\runtimes\**;Plugins\**\ref\**;Plugins\**\*.pdb" />
<Content Include="Themes\**" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="Never" />
<!-- We copy the \Logs directory -->
<Content Include="Logs\**" CopyToPublishDirectory="PreserveNewest" />
<None Remove="Plugins\Uploaded\placeholder.txt" />
<Content Include="Plugins\Uploaded\placeholder.txt">
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<None Update="Areas\Admin\sitemap.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<!-- This setting fixes the problem caused by this update in the websdk in vs2019
https://github.com/aspnet/websdk/commit/7e6b193ddcf1eec5c0a88a9748c626775555273e#diff-edf5a48ed0d4aa5a4289cb857bf46a04
Therefore, we restore the standard configuration behavior (there was no copy to the output directory)
in order to avoid the "Duplicate dll" error during publication.
We can also use “ExcludeConfigFilesFromBuildOutput” according to https://github.com/aspnet/AspNetCore/issues/14017 -->
<Content Update="**\*.config;**\*.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
<!-- This target execute after "Build" target.
We use it to clean up folder with plugins from unnecessary and obsolete libraries. -->
<Target Name="NopTarget" AfterTargets="Build">
<ItemGroup>
<!-- Get plugin description files to get plugin paths -->
<PluginsDescription Include="$(MSBuildProjectDirectory)\Plugins\**\plugin.json;" />
<!-- Get paths for all plugins -->
<PluginsFolders Include="@(PluginsDescription->'%(relativedir)')" />
<!-- Get paths for ClearPluginAssemblies project -->
<ClearPluginAssemblies Include="$(MSBuildProjectDirectory)\..\..\Build\ClearPluginAssemblies.proj" />
</ItemGroup>
<PropertyGroup>
<PluginsFolders>@(PluginsFolders)</PluginsFolders>
</PropertyGroup>
<!-- When .NET Core builds a project, it copies all referenced libraries to the output folder.
For plugins it creates too many unnecessary files that just take up space.
At the moment you can't disable this behavior. That's why we have to manually delete all unnecessary libraries from plugin output directories. -->
<MSBuild Projects="@(ClearPluginAssemblies)" Properties="PluginPath=$(PluginsFolders)" Targets="NopClear" />
</Target>
<PropertyGroup>
<!--The common language runtime (CLR) supports two types of garbage collection:
workstation garbage collection, which is available on all systems, and server garbage collection,
which is available on multiprocessor systems.
For single-processor computers, the default workstation garbage collection should be the fastest option.
Either workstation or server can be used for two-processor computers.
Server garbage collection should be the fastest option for more than two processors.
More details about GC you can see here: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals-->
<ServerGarbageCollection>false</ServerGarbageCollection>
<!--In workstation or server garbage collection, you can enable concurrent garbage collection,
which enables threads to run concurrently with a dedicated thread that performs the garbage
collection for most of the duration of the collection.
Concurrent garbage collection enables interactive applications to be more responsive by
minimizing pauses for a collection. Managed threads can continue to run most of the time while
the concurrent garbage collection thread is running. This results in shorter pauses while
a garbage collection is occurring.
To improve performance when several processes are running, disable concurrent garbage collection.
More details here: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals#concurrent-garbage-collection-->
<ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>
</PropertyGroup>
</Project>
如你所见,这是原来的
csproj
,我没有改变任何东西。你可以看到这些行:
<Compile Remove="Plugins\**;Themes\**" />
<Content Remove="Plugins\**;Themes\**" />
<EmbeddedResource Remove="Plugins\**;Themes\**" />
<None Remove="Plugins\**;Themes\**" />
<None Include="Plugins\**" CopyToPublishDirectory="PreserveNewest" Exclude="Plugins\**\runtimes\**;Plugins\**\ref\**;Plugins\**\*.pdb" />
<Content Include="Themes\**" CopyToPublishDirectory="PreserveNewest" CopyToOutputDirectory="Never" />
理论上应该将主题文件夹中的所有内容复制到输出。它确实复制了默认主题(
DefaultClean
),但不是我的具有完全相同结构的自定义主题。 这也是我的 Dockerfile:
# create the build instance
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
WORKDIR /src
COPY ./src ./
WORKDIR /src/Presentation/Nop.Web
# build project
RUN dotnet build Nop.Web.csproj -c Release
# build plugins
WORKDIR /src/Plugins
RUN set -eux; \
for dir in *; do \
if [ -d "$dir" ]; then \
dotnet build "$dir/$dir.csproj" -c Release; \
fi; \
done
# publish project
WORKDIR /src/Presentation/Nop.Web
RUN dotnet publish Nop.Web.csproj -c Release -o /app/published
WORKDIR /app/published
RUN mkdir logs bin
RUN chmod 775 App_Data \
App_Data/DataProtectionKeys \
bin \
logs \
Plugins \
wwwroot/bundles \
wwwroot/db_backups \
wwwroot/files/exportimport \
wwwroot/icons \
wwwroot/images \
wwwroot/images/thumbs \
wwwroot/images/uploaded \
wwwroot/sitemaps
# create the runtime instance
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS runtime
# add globalization support
RUN apk add --no-cache icu-libs icu-data-full
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
# installs required packages
RUN apk add tiff --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/main/ --allow-untrusted
RUN apk add libgdiplus --no-cache --repository http://dl-3.alpinelinux.org/alpine/edge/community/ --allow-untrusted
RUN apk add libc-dev tzdata --no-cache
# copy entrypoint script
COPY ./entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh
WORKDIR /app
COPY --from=build /app/published .
ENV ASPNETCORE_URLS=http://+:80
EXPOSE 80
ENTRYPOINT "/entrypoint.sh"
此外,如果值得一提,我有这个简单的撰写文件:
services:
mynop:
container_name: mynop
hostname: mynop
image: jd/mynop
restart: always
build:
context: .
dockerfile: Dockerfile
volumes:
- mynop:/app
env_file:
- ./.env # some simple env values. nothing important
ports:
- "${WEB_EXPOSE_PORT}:80"
networks:
default:
infra:
volumes:
mynop:
name: mynop
您知道为什么我的自定义代码(插件和主题)无法到达最终运行目录吗?预先感谢。
好的。看来卷有问题。由于我正在安装应用程序的根目录(
/app
),docker 没有更改其中的项目 - 我猜。所以我像这样改变了音量,现在一切正常:
services:
mynop:
volumes:
- mynop_App_Data:/app/App_Data
- mynop_logs:/app/logs
- mynop_wwwroot__db_backups:/app/wwwroot/db_backups
- mynop_wwwroot__files__exportimport:/app/wwwroot/files/exportimport
- mynop_wwwroot__icons:/app/wwwroot/icons
- mynop_wwwroot__images:/app/wwwroot/images
- mynop_wwwroot__images__thumbs:/app/wwwroot/images/thumbs
- mynop_wwwroot__images__uploaded:/app/wwwroot/images/uploaded
- mynop_wwwroot__sitemaps:/app/wwwroot/sitemaps
你还必须修改
volumes
部分:
volumes:
mynop_App_Data:
name: mynop_App_Data
mynop_logs:
name: mynop_logs
mynop_wwwroot__db_backups:
name: mynop_wwwroot__db_backups
mynop_wwwroot__files__exportimport:
name: mynop_wwwroot__files__exportimport
mynop_wwwroot__icons:
name: mynop_wwwroot__icons
mynop_wwwroot__images:
name: mynop_wwwroot__images
mynop_wwwroot__images__thumbs:
name: mynop_wwwroot__images__thumbs
mynop_wwwroot__images__uploaded:
name: mynop_wwwroot__images__uploaded
mynop_wwwroot__sitemaps:
name: mynop_wwwroot__sitemaps