.net core3.x发布到Docker运行

.net core3.x发布到Docker运行

我们开发完之后,需要进行发布部署,一般高端的公司是采用CI/CD方式自动发布,但是我所处的公司都是使用手动发布,之前我都是输入命令的方式:

1
dotnet publish -c Release -r win7-x64 -o ./bin/output

执行之后就会在相应目录生成所有dll

随迎时代潮流,我们也该有些骚气的操作了,这次咱们就把.net core3.x采用docker发布,因为我的电脑无法安装docker:
诺

那么就想到要么先publish然后把DLL构建成docker镜像,要么就直接通过源码构建镜像,我就偷偷懒,选择后者。那么首先在vs添加【Docker支持】->【Linux】就会生成一个Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
# 相当于cd /src
WORKDIR /src
# 将当前本地Web/Web.csproj 复制到/src/Web/目录下
COPY ["Web/Web.csproj", "Web/"]
# 还原项目依赖库
RUN dotnet restore "Web/Web.csproj"
将当前本地目录复制到/src
COPY . .
WORKDIR "/src/Web"
RUN dotnet build "Web.csproj" -c Release -o /app/build

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

FROM base AS final
WORKDIR /app
# 从编译阶段的中的publish层镜像拷贝/app/publish目录到/app目录下
COPY --from=publish /app/publish .
COPY ["Web/Web.xml", "."]
ENTRYPOINT ["dotnet", "Web.dll"]

如果你是提前编译好的,那么可以将Dockerfile修改一下:

1
2
3
4
5
6
7
8
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim 
EXPOSE 80
EXPOSE 443

COPY . /app
WORKDIR /app

ENTRYPOINT ["dotnet", "Web.dll"]

我们将整个源码复制到Centos服务器上,cd到dockerfile目录执行命令:

1
docker build -t core3.x-swagger -f Dockerfile .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
Sending build context to Docker daemon  40.45kB
Step 1/17 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
---> 880d85db3775
Step 2/17 : WORKDIR /app
---> Using cache
---> 2686a6832749
Step 3/17 : EXPOSE 80
---> Using cache
---> f910a2eacda4
Step 4/17 : EXPOSE 443
---> Using cache
---> a157473c89ee
Step 5/17 : FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
---> a345b68a725e
Step 6/17 : WORKDIR /src
---> Using cache
---> 8b2a2b0743f5
Step 7/17 : COPY ["Web/Web.csproj", "Web/"]
---> 29f558699c69
Step 8/17 : RUN dotnet restore "Web/Web.csproj"
---> Running in 31e08f04df6c
Restore completed in 1.4 min for /src/Web/Web.csproj.
Removing intermediate container 31e08f04df6c
---> ed0f20f4056a
Step 9/17 : COPY . .
---> 1999712c7ece
Step 10/17 : WORKDIR "/src/Web"
---> Running in 6d81af8f98dc
Removing intermediate container 6d81af8f98dc
---> b31d42182d2a
Step 11/17 : RUN dotnet build "Web.csproj" -c Release -o /app/build
---> Running in b2c16188ce9a
Microsoft (R) Build Engine version 16.3.2+e481bbf88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 29.82 ms for /src/Web/Web.csproj.
Web -> /app/build/Web.dll

Build succeeded.
0 Warning(s)
0 Error(s)

Time Elapsed 00:00:04.89
Removing intermediate container b2c16188ce9a
---> b249fe8e976b
Step 12/17 : FROM build AS publish
---> b249fe8e976b
Step 13/17 : RUN dotnet publish "Web.csproj" -c Release -o /app/publish
---> Running in 43766cf2eb2d
Microsoft (R) Build Engine version 16.3.2+e481bbf88 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 35.91 ms for /src/Web/Web.csproj.
Web -> /src/Web/bin/Release/netcoreapp3.0/Web.dll
Web -> /app/publish/
Removing intermediate container 43766cf2eb2d
---> e07c5fc08616
Step 14/17 : FROM base AS final
---> a157473c89ee
Step 15/17 : WORKDIR /app
---> Running in 3ab7aca5e289
Removing intermediate container 3ab7aca5e289
---> 0b7196de9a3f
Step 16/17 : COPY --from=publish /app/publish .
---> 6178981834ae
Step 17/17 : ENTRYPOINT ["dotnet", "Web.dll"]
---> Running in 488f804c2854
Removing intermediate container 488f804c2854
---> 5aa2ed7e047f
Successfully built 5aa2ed7e047f
Successfully tagged core3.x-swagger:latest

生成之后便可以查询到我们的镜像文件:

1
2
3
[root@VM_175_142_centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
core3.x-swagger latest 5aa2ed7e047f 2 minutes ago 237MB

我们可以运行我们的image镜像文件了:

1
2
# 将容器80端口映射到宿主机的9999端口
docker run --name swagger -d -p 9999:80 core3.x-swagger

但是当我访问的时候并没有给我惊喜,而是令人头皮发麻的服务端500错误,那么我们就去看看容器的日志吧:

1
docker logs 083d0c79c078

错误日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://[::]:80
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: /app
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLRJSUAI4BAT", Request id "0HLRJSUAI4BAT:00000001": An unhandled exception was thrown by the application.
System.IO.FileNotFoundException: Could not find file '/app/Web.xml'.
File name: '/app/Web.xml'
at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirectory, Func`2 errorRewriter)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String path, OpenFlags flags, Int32 mode)
at System.IO.FileStream.OpenHandle(FileMode mode, FileShare share, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCachePolicy cachePolicy)
at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
at System.Xml.XmlTextReaderImpl.OpenUrl()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XPath.XPathDocument.LoadFromReader(XmlReader reader, XmlSpace space)
at System.Xml.XPath.XPathDocument..ctor(String uri, XmlSpace space)
at System.Xml.XPath.XPathDocument..ctor(String uri)
at Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.<>c__DisplayClass23_0.<IncludeXmlComments>b__0()
at Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.IncludeXmlComments(SwaggerGenOptions swaggerGenOptions, Func`1 xmlDocFactory, Boolean includeControllerXmlComments)
at Microsoft.Extensions.DependencyInjection.SwaggerGenOptionsExtensions.IncludeXmlComments(SwaggerGenOptions swaggerGenOptions, String filePath, Boolean includeControllerXmlComments)
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 Swashbuckle.AspNetCore.SwaggerGen.ConfigureSchemaGeneratorOptions..ctor(IServiceProvider serviceProvider, IOptions`1 swaggerGenOptionsAccessor)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitNoCache(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.GetService(IServiceProvider sp, Type type, Type middleware)
at lambda_method(Closure , Object , HttpContext , IServiceProvider )
at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass4_1.<UseMiddleware>b__2(HttpContext context)
at Microsoft.AspNetCore.Mvc.Versioning.ApiVersioningMiddleware.InvokeAsync(HttpContext context)
at Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Hosting.HostingApplication.ProcessRequestAsync(Context context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
fail: Microsoft.AspNetCore.Server.Kestrel[13]

很明显,是因为publish的时候没有把我们的Web.xml文件复制进去,那么我们在Dockerfile中添加一条

1
COPY ["Web/Web.xml", "."]

在把之前是容器删除掉:

1
docker rm 083d0c79c078

然后重新build一次

1
docker build -t core3.x-swagger -f Dockerfile .

重启启动容器,很好,是想要的结果:
docker_swagger

1
2
3
[root@VM_175_142_centos Swagger.Demo]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b475841bece6 core3.x-swagger "dotnet Web.dll" 3 minutes ago Up 3 minutes 443/tcp, 0.0.0.0:9999->80/tcp swagger

后面,我们尝试使用腾讯云容器服务(Tencent Kubernetes Engine ,TKE)或者阿里容器服务 Kubernetes 版(简称 ACK)来部署我们的Docker镜像

You forgot to set the qrcode for Alipay. Please set it in _config.yml.
You forgot to set the qrcode for Wechat. Please set it in _config.yml.
You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×