docker 个容器上的 Blazor
Blazor on docker containers
有人设法在 docker 容器上 运行 服务器端托管的 Blazor 应用程序吗?
我在 运行 时遇到以下异常:
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
No XML encryptor configured. Key {c1fe0008-8b2b-46a3-9f80-233ae59e5d17} may be persisted to storage in unencrypted form.
crit: Microsoft.AspNetCore.Hosting.Internal.GenericWebHostService[6]
Application startup exception
System.InvalidOperationException: Could not load the embedded file manifest 'Microsoft.Extensions.FileProviders.Embedded.Manifest.xml' for assembly 'Microsoft.AspNetCore.Components.Server'.
at Microsoft.Extensions.FileProviders.Embedded.Manifest.ManifestParser.Parse(Assembly assembly, String name)
at Microsoft.Extensions.FileProviders.ManifestEmbeddedFileProvider..ctor(Assembly assembly)
at Microsoft.AspNetCore.Components.Server.ConfigureStaticFilesOptions.PostConfigure(String name, StaticFileOptions options)
at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware..ctor(RequestDelegate next, IWebHostEnvironment hostingEnv, IOptions`1 options, ILoggerFactory loggerFactory)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass4_0.<UseMiddleware>b__0(RequestDelegate next)
at Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.Internal.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Unhandled Exception: System.InvalidOperationException: Could not load the embedded file manifest 'Microsoft.Extensions.FileProviders.Embedded.Manifest.xml' for assembly 'Microsoft.AspNetCore.Components.Server'.
at Microsoft.Extensions.FileProviders.Embedded.Manifest.ManifestParser.Parse(Assembly assembly, String name)
at Microsoft.Extensions.FileProviders.ManifestEmbeddedFileProvider..ctor(Assembly assembly)
at Microsoft.AspNetCore.Components.Server.ConfigureStaticFilesOptions.PostConfigure(String name, StaticFileOptions options)
at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware..ctor(RequestDelegate next, IWebHostEnvironment hostingEnv, IOptions`1 options, ILoggerFactory loggerFactory)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass4_0.<UseMiddleware>b__0(RequestDelegate next)
at Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.Internal.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at BlazorUI.ServerSided.Program.Main(String[] args) in /src/BlazorUI.ServerSided/Program.cs:line 19
编辑: 这是一个干净的项目,由 Visual Studio 在创建新的 ASP.Net 核心 Web 应用程序 > Blazor(服务器端)时添加。没有对项目进行其他更改。
通过选择项目(右键单击)> 添加 > docker 支持创建了 Dockerfile:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-stretch-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-stretch AS build
WORKDIR /src
COPY ["BlazorUI.ServerSided/BlazorUI.ServerSided.csproj", "BlazorUI.ServerSided/"]
RUN dotnet restore "BlazorUI.ServerSided/BlazorUI.ServerSided.csproj"
COPY . .
WORKDIR "/src/BlazorUI.ServerSided"
RUN dotnet build "BlazorUI.ServerSided.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "BlazorUI.ServerSided.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "BlazorUI.ServerSided.dll"]
我正在使用 .net-core 3-preview4-011223 和 linux 容器。
图像已发布 here。
您遇到了影响 Linux 版本的预览版 4 中的众所周知的问题
参见 https://github.com/aspnet/AspNetCore/issues/9402
Asp.NET 团队声称会在预览版 5 中修复该问题
要解决您的问题,您应该使用自 2019 年 5 月 5 日起的每日构建的预览版 5。
您可以从 https://github.com/aspnet/AspNetCore/blob/master/docs/DailyBuilds.md
获取 Preview5 的构建
这是我到目前为止所发现的,目前可以使用(使用 https 和子域):
在 Startup.cs 中设置子域 -> 配置:
string basePath = Environment.GetEnvironmentVariable("ASPNETCORE_BASEPATH");
if (!string.IsNullOrEmpty(basePath))
{
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next();
});
app.Use((context, next) =>
{
context.Request.PathBase = new PathString(basePath);
if (context.Request.Path.StartsWithSegments(basePath, out var remainder))
{
context.Request.Path = remainder;
}
return next();
});
}
app.UseForwardedHeaders(new ForwardedHeadersOptions
Apache 配置,例如子域“helloapp”和 docker 端口 9124 aspnetcore-3.0#configure-apache
<VirtualHost *:*>
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
ServerAlias example.com
ErrorLog ${APACHE_LOG_DIR}helloapp-error.log
CustomLog ${APACHE_LOG_DIR}helloapp-access.log common
UseCanonicalName On
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCipherSuite HIGH
SSLProxyEngine On
ProxyPreserveHost On
ProxyRequests Off
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /helloapp/(.*) wss://localhost:9124/ [P,QSA,L]
<Location /helloapp >
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
ProxyPreserveHost On
ProxyPass https://127.0.0.1:9124
ProxyPassReverse https://127.0.0.1:9124
</Location>
</VirtualHost>
假设您有一个 letsencrypt SSLCertificate,您必须转换它以便 Kestrel 可以使用它。在您的 Linux 服务器 运行 终端上执行以下命令。可以在您的 apache 配置中找到私钥、证书和链文件的路径。这将创建一个 certificate.pfx – 您必须输入 Kestrel 的有效密码。
openssl pkcs12 -export -out certificate.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem
从 hub.docker e.g. bionic/amd64/Dockerfile 获取 Dockerfile
在 Dockerfile 底部添加此行:
COPY ./certificate.pfx /root/certificate.pfx
将 certificate.pfx 文件和 Dockerfile 复制到一个空文件夹中。创建文件 docker-compose.yml:
version: '3.3'
services:
helloapp:
build: .
#restart: always
ports:
- "9123:80"
- "9124:443"
environment:
ASPNETCORE_BASEPATH: /helloapp
ASPNETCORE_HTTPS_PORT: 9124
ASPNETCORE_URLS: "https://+:443;http://+:80"
Kestrel__Certificates__Default__Path: /root/certificate.pfx
Kestrel__Certificates__Default__Password: mycertificatesecret
volumes:
- ./helloapp:/helloapp
working_dir: /helloapp
command: ["dotnet", "helloapp.dll"]
创建一个子文件夹 helloapp 并将您发布的 WebApp 复制到其中。
然后你可以启动容器,它应该在 www.example.com/helloapp
可用
docker-compose build
docker-compose up
有人设法在 docker 容器上 运行 服务器端托管的 Blazor 应用程序吗?
我在 运行 时遇到以下异常:
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
No XML encryptor configured. Key {c1fe0008-8b2b-46a3-9f80-233ae59e5d17} may be persisted to storage in unencrypted form.
crit: Microsoft.AspNetCore.Hosting.Internal.GenericWebHostService[6]
Application startup exception
System.InvalidOperationException: Could not load the embedded file manifest 'Microsoft.Extensions.FileProviders.Embedded.Manifest.xml' for assembly 'Microsoft.AspNetCore.Components.Server'.
at Microsoft.Extensions.FileProviders.Embedded.Manifest.ManifestParser.Parse(Assembly assembly, String name)
at Microsoft.Extensions.FileProviders.ManifestEmbeddedFileProvider..ctor(Assembly assembly)
at Microsoft.AspNetCore.Components.Server.ConfigureStaticFilesOptions.PostConfigure(String name, StaticFileOptions options)
at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware..ctor(RequestDelegate next, IWebHostEnvironment hostingEnv, IOptions`1 options, ILoggerFactory loggerFactory)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass4_0.<UseMiddleware>b__0(RequestDelegate next)
at Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.Internal.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Unhandled Exception: System.InvalidOperationException: Could not load the embedded file manifest 'Microsoft.Extensions.FileProviders.Embedded.Manifest.xml' for assembly 'Microsoft.AspNetCore.Components.Server'.
at Microsoft.Extensions.FileProviders.Embedded.Manifest.ManifestParser.Parse(Assembly assembly, String name)
at Microsoft.Extensions.FileProviders.ManifestEmbeddedFileProvider..ctor(Assembly assembly)
at Microsoft.AspNetCore.Components.Server.ConfigureStaticFilesOptions.PostConfigure(String name, StaticFileOptions options)
at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
at Microsoft.Extensions.Options.OptionsManager`1.<>c__DisplayClass5_0.<Get>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
at Microsoft.Extensions.Options.OptionsManager`1.Get(String name)
at Microsoft.Extensions.Options.OptionsManager`1.get_Value()
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware..ctor(RequestDelegate next, IWebHostEnvironment hostingEnv, IOptions`1 options, ILoggerFactory loggerFactory)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass4_0.<UseMiddleware>b__0(RequestDelegate next)
at Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
at Microsoft.AspNetCore.Hosting.Internal.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at BlazorUI.ServerSided.Program.Main(String[] args) in /src/BlazorUI.ServerSided/Program.cs:line 19
编辑: 这是一个干净的项目,由 Visual Studio 在创建新的 ASP.Net 核心 Web 应用程序 > Blazor(服务器端)时添加。没有对项目进行其他更改。
通过选择项目(右键单击)> 添加 > docker 支持创建了 Dockerfile:
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-stretch-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-stretch AS build
WORKDIR /src
COPY ["BlazorUI.ServerSided/BlazorUI.ServerSided.csproj", "BlazorUI.ServerSided/"]
RUN dotnet restore "BlazorUI.ServerSided/BlazorUI.ServerSided.csproj"
COPY . .
WORKDIR "/src/BlazorUI.ServerSided"
RUN dotnet build "BlazorUI.ServerSided.csproj" -c Release -o /app
FROM build AS publish
RUN dotnet publish "BlazorUI.ServerSided.csproj" -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "BlazorUI.ServerSided.dll"]
我正在使用 .net-core 3-preview4-011223 和 linux 容器。
图像已发布 here。
您遇到了影响 Linux 版本的预览版 4 中的众所周知的问题 参见 https://github.com/aspnet/AspNetCore/issues/9402 Asp.NET 团队声称会在预览版 5 中修复该问题
要解决您的问题,您应该使用自 2019 年 5 月 5 日起的每日构建的预览版 5。
您可以从 https://github.com/aspnet/AspNetCore/blob/master/docs/DailyBuilds.md
获取 Preview5 的构建这是我到目前为止所发现的,目前可以使用(使用 https 和子域):
在 Startup.cs 中设置子域 -> 配置:
string basePath = Environment.GetEnvironmentVariable("ASPNETCORE_BASEPATH");
if (!string.IsNullOrEmpty(basePath))
{
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next();
});
app.Use((context, next) =>
{
context.Request.PathBase = new PathString(basePath);
if (context.Request.Path.StartsWithSegments(basePath, out var remainder))
{
context.Request.Path = remainder;
}
return next();
});
}
app.UseForwardedHeaders(new ForwardedHeadersOptions
Apache 配置,例如子域“helloapp”和 docker 端口 9124 aspnetcore-3.0#configure-apache
<VirtualHost *:*>
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
ServerAlias example.com
ErrorLog ${APACHE_LOG_DIR}helloapp-error.log
CustomLog ${APACHE_LOG_DIR}helloapp-access.log common
UseCanonicalName On
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCipherSuite HIGH
SSLProxyEngine On
ProxyPreserveHost On
ProxyRequests Off
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /helloapp/(.*) wss://localhost:9124/ [P,QSA,L]
<Location /helloapp >
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
ProxyPreserveHost On
ProxyPass https://127.0.0.1:9124
ProxyPassReverse https://127.0.0.1:9124
</Location>
</VirtualHost>
假设您有一个 letsencrypt SSLCertificate,您必须转换它以便 Kestrel 可以使用它。在您的 Linux 服务器 运行 终端上执行以下命令。可以在您的 apache 配置中找到私钥、证书和链文件的路径。这将创建一个 certificate.pfx – 您必须输入 Kestrel 的有效密码。
openssl pkcs12 -export -out certificate.pfx -inkey privkey.pem -in cert.pem -certfile chain.pem
从 hub.docker e.g. bionic/amd64/Dockerfile 获取 Dockerfile 在 Dockerfile 底部添加此行:
COPY ./certificate.pfx /root/certificate.pfx
将 certificate.pfx 文件和 Dockerfile 复制到一个空文件夹中。创建文件 docker-compose.yml:
version: '3.3'
services:
helloapp:
build: .
#restart: always
ports:
- "9123:80"
- "9124:443"
environment:
ASPNETCORE_BASEPATH: /helloapp
ASPNETCORE_HTTPS_PORT: 9124
ASPNETCORE_URLS: "https://+:443;http://+:80"
Kestrel__Certificates__Default__Path: /root/certificate.pfx
Kestrel__Certificates__Default__Password: mycertificatesecret
volumes:
- ./helloapp:/helloapp
working_dir: /helloapp
command: ["dotnet", "helloapp.dll"]
创建一个子文件夹 helloapp 并将您发布的 WebApp 复制到其中。
然后你可以启动容器,它应该在 www.example.com/helloapp
可用docker-compose build
docker-compose up