利用Dockerfile将ASP.NET Core Web应用部署到Docker容器
前言
想必各位对ASP.NET Core容器化部署,特别是微软非常喜欢强调的 微服务(Micro-Service) 概念有一定的兴趣。
这一过程需要使用到ASP.NET Core, Docker, Nginx三个组件,要让它们相互良好地配合起来,还是需要精心编写一下配置文件的。
然而,当真的开始着手实操的时候,假如阅读微软文档给出的一些文章或者链接,例如:
- Hosting ASP.NET Core image in container using docker compose with HTTPS | Microsoft Docs
- Docker images for ASP.NET Core | Microsoft Docs
- Configure ASP.NET Core to work with proxy servers and load balancers | Microsoft Docs
- Host ASP.NET Core on Linux with Nginx | Microsoft Docs
- ASP.NET Core Runtime by Microsoft | Docker Hub
或许对于幼儿园的小朋友来说,这些文章可能显得比较幼稚。但对我这种饭来张口衣来伸手的大学生来说,这些文章只能说刚刚好。把文章拼起来就是需要的答案,可惜在尝试的过程中会显得有些不适。所以不妨总结一下,如何将一个ASP.NET Core Web应用部署到Docker中,然后用Nginx做反向代理进行访问。
准备
- 已经开发好的ASP.NET Core Web应用程序(Razor Pages, Blazor, MVC, Web API啥的,都可以)
- Docker
- Nginx
这里,我们会使用最新的.NET 6.0进行部署。
ASP.NET Core代码的适配
在本教程中,我们由于需要使用Nginx配置反向代理,这需要我们对ASP.NET Core应用进行响应的修改。
关闭HTTPS重定向
ASP.NET Core项目默认会重定向所有HTTP请求到HTTPS,但在反向代理的场景下,HTTPS不是容器中的ASP.NET Core程序该操心的事情。我们应该在Nginx这样的Web服务器部分完成HTTPS相关的配置,包括HTTP重定向HTTPS。
打开Program.cs
,找到如下代码:
1 | app.UseHttpsRedirection(); |
将app.UseHttpsRedirection()
一句删除或注释掉,关闭HTTPS重定向。
设置反向代理使用的响应标头
为了能正确跟踪请求的来源,处理重定向、认证等关键的事件,我们还需要配置转发响应标头。
同样是在Program.cs
中,我们在其他中间件之前,加入UseForwardedHeaders
代码段:
1 | ...... |
关于中间件先后顺序的讨论,可以参考ASP.NET Core Middleware | Microsoft Docs.
配置步骤
第1步-创建文件夹
创建一个新文件夹,用来存放构建镜像所需的文件,包括Dockerfile
等。我们假设这个新文件夹名为myapp
。
第2步-发布ASP.NET Core应用
这一步我们要将编写的ASP.NET Core应用发布,生成生产环境下的二进制代码。
打开终端,切换到项目根目录,运行:
1 | dotnet publish -c Release -o publish --no-restore |
其中-o publish
的意思是将发布的二进制代码放入名为publish
的文件夹中。发布完成后,进入该文件夹,可以找到与当前项目同名的一个.dll
文件,这就是你的项目编译生成的二进制代码。我们这里假设该文件名为MyWebApp.dll
。
发布完成后,将publish
文件夹复制到myapp
文件夹中。
第3步-编写Dockerfile
在myapp
文件夹中,新建一个Dockerfile
文件,编写内容:
1 | FROM mcr.microsoft.com/dotnet/aspnet:6.0 |
依次解释上述语句含义:
FROM mcr.microsoft.com/dotnet/aspnet:6.0
指定了基础的镜像文件,我们选用的是微软发布的最新ASP.NET Core Runtime镜像,不包含SDK。WORKDIR /app
指定接下来容器中的操作,基础目录是/app
。COPY publish statics ./
会将 本机publish
文件夹下的所有文件 复制到 容器当前目录下。ENTRYPOINT ["dotnet", "MyWebApp.dll"]
放在最后,容器将执行这一命令,即通过dotnet
命令运行上一行语句中复制到/app
目录下的MyWebApp.dll
文件。这将会保持该Web程序一直运行,直到被要求退出。
第4步-构建并运行Docker镜像
在myapp
文件夹中,运行命令:
1 | docker build -t mywebapp . |
-t mywebapp
指定了生成镜像的标签(tag)为mywebapp
,当然你也可以写成mywebapp:0.1.2
这样的形式来指定一个版本号。
运行命令,Docker会拉取最新的ASP.NET Core Runtime镜像,然后执行我们在Dockerfile中指定的操作,构建成一个新的镜像,放在系统中。
接下来我们就可以启动我们的应用了。执行命令:
1 | docker run -d -p 12345:80 --name mywebapp-123 mywebapp |
参数的解释:
-d
表示容器在后台运行(daemon)-p 12345:80
表示将主机的12345
端口映射到容器的80
端口上,即可以通过主机的12345
端口直接访问容器内ASP.NET Core应用。由于我们需要设置反向代理,出于安全考虑,我们可以设置只映射来自本机的访问,即写成-p 127.0.0.1:12345:80
这样的形式,此时即便没有防火墙,外界直接访问12345
端口也无法访问到我们的ASP.NET Core应用程序。--name mywebapp-123
,给你的容器起一个名字。mywebapp
,选择运行容器使用的镜像Tag。(和上面容器名字可以相同,也可以不同,但这个名字来源于上面构建Docker镜像中指定的Tag,如果设置了版本号,还应当指明版本号。)
如果没有意外情况,执行上述命令后,我们的应用就运行在机器上了。可以通过docker ps
查看正在运行的容器,看我们刚刚建立的容器是否正常运行。
第5步-设置反向代理
在现代的网站中,我们不是很喜欢通过端口号访问网站,更多情况下,我们需要借助如Nginx等Web服务器的反向代理等功能,完成更复杂的工作。因此,我们现在看看怎么使用Nginx为我们的应用设置反向代理。
再次确认
执行本步骤前,请确保容器中运行的程序已经按照 ASP.NET Core代码的适配 部分修改并生成。
这里,我们使用Debian/Ubuntu系Linux发行版的配置文件目录习惯,如果使用的是Fedora/RedHat系发行版,需要自行确定下Nginx配置文件的目录,并创建对应的文件。
我们在/etc/nginx/sites-available/
下创建一个新的站点配置文件,可以起名为myapp.conf
。编写如下内容:
1 | server { |
其他部分大同小异,我们主要需要注意的是以下几点。
- 如果你的服务器上还运行了其他域名的应用,请确认
server_name
后正确指定了需要转发给ASP.NET Core应用程序的域名,本例中为myapp.example.com
proxy_pass
后需要正确指定 第4步-构建并运行docker镜像 中映射到容器80
端口的本机端口号。
(可选)第6步-设置HTTPS重定向
现在绝大部分网站都已经使用了HTTPS,我们为了安全理应同样使用HTTPS。当然,这里我们不讨论如何获得HTTPS证书,我们稍微提一提怎么做重定向。
将第五步中的Nginx配置文件修改为:
1 | server { |
上述Nginx的TLS配置仅供参考。我们选取了一个相对较为安全的配置。
第7步-启动Nginx并测试访问
执行命令:
1 | nginx -s reload |
Nginx将会重新读取配置文件,设置好DNS解析(如果使用了域名的话),就可以通过绑定的域名访问到容器中的ASP.NET Core Web应用了。