将 ASP.Net Core WebApi 应用打包至 Docker 镜像

运行环境为 Windows 10 专业版 21H1, Docker Desktop 3.6.0(67351),Docker Engine 20.10.8

1. ASP.Net Core Runtime 还是 .Net Core Runtime

在这里首先要区分一下 SDK 和 Runtime 的区别。SDK (Software Development Kit)主要是在开发过程中使用的,而 Runtime 是在实际运行的时候使用的(类似于 JDK 和 JRE 的关系)。所以对于我们这种发布后运行的情况,Runtime 就足够了。

一开始没有分清楚 ASP.Net Core Runtime,和 .Net Core Runtime 的区别,导致自己的网站项目虽然拷贝进了镜像但一直提示缺少运行时。ASP 的全称是 Active Server Pages,顾名思义,是用于动态网页的,所以网站应用要使用 ASP.Net Core Runtime;而 .NET Core Runtime 一般是用于控制台应用的;还有一个类似的 .NET Desktop Runtime 一般是用于 Windows 桌面应用的。详细可以参见微软的 .NET 下载页面

2. ASP.NET Core WebApi 应用的编译

虽然前两天 .NET 6.0 发布了,也是 LTS,但此处还是使用 .NET Core 3.1 哈

新建一个 ASP.NET Core WebApi 应用,在 Controllers 文件夹里面添加一个 HelloWorldController,并且在 appSettings.json 中添加一个配置项 WelcomeStr

HelloWorldController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; namespace HelloWorldWebApplication.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class HelloWorldController
{
private readonly IConfiguration Configuration; public HelloWorldController(IConfiguration configuration)
{
this.Configuration = configuration;
} [HttpGet]
public string Hello()
{
return Configuration.GetSection("WelcomeStr").Value;
}
}
}

appSettings.json

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"WelcomeStr": "Hello ASP.NET Core 3.1!" # 新增部分
}

功能也比较简单,返回一个在配置文件中定义的欢迎语。控制器中的依赖注入相关内容在此处就不细讲了。运行一下看一下本地的效果:

接下来就是本地发布了,右键项目选择发布,选择发布到文件夹。配置项的 Debug 和 Release、目标框架 自不用多说。关于“部署模式”,框架依赖 的意思是,发布的内容必须要在安装了相应运行环境的机器上才能运行(正是我们打包至Docker想要的),而独立 的意思是,即使机器没有安装相应的运行环境,也可以运行。对于目标运行时,如果我们要打包到 Docker 的 Linux x64 镜像中,应当选择 linux-x64。点击“发布”,在项目的根目录中,依次进入 bin\Release\netcoreapp3.1\publish,这里面的文件就是发布后的文件,我们要将它们打包进镜像。

3. Dockerfile 的创建与打包

准备工作的最后一步了。注意文件名称一定要是 Dockerfile,鄙人一开始使用 VS Code 新建了一个 .dockerfile 文件,在使用 docker 构建命令时一直提示没有构建文件。

Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:3.1-focal
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
RUN mkdir /HelloWorldWebApplication
COPY ./ /HelloWorldWebApplication
EXPOSE 80
WORKDIR /HelloWorldWebApplication
CMD ["/bin/bash","-c","./HelloWorldWebApplication"]

这里面的注意点就比较多了,我们逐个来说

第 1 行,使用 From 选择基础镜像。所有的选项可以参见 ASP.NET Core Runtime 的 DockerHub 页面。此处选用的是基于 Ubuntu、 运行时版本是 3.1 的镜像。后面的 focal 其实对应的操作系统的代号,即 Ubuntu 20.04 Focal Fossa(类似的 Buster 是 Debian 10 的代号)。如果希望镜像尽可能的小,可以使用 alpine 镜像(这里选用 Ubuntu 镜像主要是为了个人的操作方便,比如按下别名 ll 就可以执行对应命令 ls -l,alpine 镜像虽然小,但很多常用命令、功能都没有)

第 2 ~ 3 行设置时区。如果使用的是 alpine 镜像,需要手动拷贝时区文件

第 4 行,在容器中创建目录。一开始的时候没写这行,导致后面的 COPY 找不到文件夹了。这可不像是 docker cp 可以自动在容器中创建文件夹啊。

第 5 行,使用 COPY 命令复制。切记在 源路径中不要使用 *,如 COPY * /HelloWorldWebApplication,因为这会忽略第一层的文件夹。假设我们当前目录是这样的(多了wwwroot):

│ appsettings.Development.json

│ appsettings.json

│ Dockerfile

│ HelloWorldWebApplication

│ HelloWorldWebApplication.deps.json

│ HelloWorldWebApplication.dll

│ HelloWorldWebApplication.pdb

│ HelloWorldWebApplication.runtimeconfig.json

│ web.config



└─wwwroot

                  index.html

复制进去后,wwwroot 文件夹已经没了:

root@f659a7e407e1:/HelloWorldWebApplication# ll

total 264

drwxr-xr-x 1 root root 4096 Nov 12 02:54 ./

drwxr-xr-x 1 root root 4096 Nov 12 02:55 ../

-rwxr-xr-x 1 root root 216 Nov 12 02:54 Dockerfile*

-rwxr-xr-x 1 root root 90680 Nov 12 02:24 HelloWorldWebApplication*

-rwxr-xr-x 1 root root 114406 Nov 12 02:24 HelloWorldWebApplication.deps.json*

-rwxr-xr-x 1 root root 8704 Nov 12 02:24 HelloWorldWebApplication.dll*

-rwxr-xr-x 1 root root 19932 Nov 12 02:24 HelloWorldWebApplication.pdb*

-rwxr-xr-x 1 root root 311 Nov 12 02:24 HelloWorldWebApplication.runtimeconfig.json*

-rwxr-xr-x 1 root root 162 Nov 12 01:49 appsettings.Development.json*

-rwxr-xr-x 1 root root 236 Nov 12 01:56 appsettings.json*

-rwxr-xr-x 1 root root 0 Nov 12 02:47 index.html*

-rwxr-xr-x 1 root root 545 Nov 12 02:24 web.config*

第 6 行,使用 EXPOSE 指明应当映射的端口。为什么这个端口一定是 80 呢,我就是想使用 8001 呢,这是在 ASP.NET Core 3.1 Runtime 镜像中定义的环境变量。可以进入容器,使用 env 命令查看,可以发现:

所以如果想修改端口,在 Dockerfile 添加如下指令即可

ENV ASPNETCORE_URLS=http://+:5000

第 7 行,使用 WORKDIR 切换工作路径。如果不切换工作路径,则会找不到配置文件。如修改 Dockerfile,删除该行,并修改最后一行(需要指定执行文件的路径)为:

CMD ["/bin/bash","-c","./HelloWorldWebApplication/HelloWorldWebApplication"]

再次访问,可以看到没有获取到配置文件的内容:

第 8 行,使用 CMD 执行命令。我们可以直接执行 ./HelloWorldWebApplication,可别忘了是在 shell 中,所以要指定 /bin/bash 或 /bin/sh(和使用的具体操作系统镜像有关,在 Ubuntu 中是 /bin/bash)。也尝试过使用 alpine,似乎直接执行并不奏效,需要执行的命令为 /bin/sh dotnet ./HelloWorldWebApplication.dll。

4. 运行

终于到最后的执行步骤了,在 Windows 的终端中切换目录到项目的 publish 文件夹中,执行 docker build -t helloworld_web:v1 . 生成最终的镜像。使用 docker run -itd -p 5002:80 helloworld_web:v1 创建并运行容器(映射到 5002 端口),可以看到得到了与本地同样的效果:

后记:

这一路操作下来,虽然主要的思路没毛病,但细节的东西还是不少的,终于把之前的 Docker 内容实际运用上了。

Docker Desktop 的功能也越来越完备了,现在可以查看构建 image 的 Dockerfile 文件:

另外无意间看到了 Visual Studio 2019 中可以直接使用发布到 Docker 的功能, 有空尝试下。

参考:

.NET Core 官方下载

https://dotnet.microsoft.com/download/dotnet/3.1

Asp.net core在docker容器中的端口问题

https://www.cnblogs.com/RandyField/p/13059985.html

Linux 下执行本目录的可执行文件(命令)为什么需要在文件名前加“./”

https://www.cnblogs.com/fortunel/p/8663669.html

Docker COPY 复制文件夹的诡异行为

https://www.jianshu.com/p/9b7da9aacd8a

Dockerfile复制时如何保留子目录的结构

https://www.pkslow.com/archives/dockerfile-copy-keep-subdirectory-structure

linux的显示全部环境变量

https://blog.csdn.net/weixin_39880318/article/details/116864978

ASP.NET Core 2.1 使用Docker运行

https://www.cnblogs.com/stulzq/p/9201830.html

将 ASP.Net Core WebApi 应用打包至 Docker 镜像的更多相关文章

  1. 将 ASP.NET Core 1.0 应用作为 docker 镜像发布 (Linux版)

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  2. Asp.Net Core WebAPI+PostgreSQL部署在Docker中

     PostgreSQL是一个功能强大的开源数据库系统.它支持了大多数的SQL:2008标准的数据类型,包括整型.数值值.布尔型.字节型.字符型.日期型.时间间隔型和时间型,它也支持存储二进制的大对像, ...

  3. 【Azure Developer】已发布好的.NET Core项目文件如何打包为Docker镜像文件

    问题描述 在博文([Azure App Service For Container]创建ASP.NET Core Blazor项目并打包为Linux镜像发布到Azure应用服务)中我们通过VS 201 ...

  4. 记一次使用Asp.Net Core WebApi 5.0+Dapper+Mysql+Redis+Docker的开发过程

    #前言 我可能有三年没怎么碰C#了,目前的工作是在全职搞前端,最近有时间抽空看了一下Asp.net Core,Core版本号都到了5.0了,也越来越好用了,下面将记录一下这几天以来使用Asp.Net ...

  5. asp.net core webapi 使用ef 对mysql进行增删改查,并生成Docker镜像构建容器运行

    1.构建运行mysql容器,添加数据库user 参考Docker创建运行多个mysql容器,地址 http://www.cnblogs.com/heyangyi/p/9288402.html 添加us ...

  6. 品尝阿里云容器服务:初步尝试ASP.NET Core Web API站点的Docker自动化部署

    部署场景是这样的,我们基于 ASP.NET Core 2.0 Preview 1 开发了一个用于管理缓存的 Web API ,想通过阿里云容器服务基于 Docker 部署为内网服务. 在这篇博文中分享 ...

  7. asp.net core webapi之跨域(Cors)访问

    这里说的跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作 ...

  8. ASP.NET Core WebAPI 开发-新建WebAPI项目

    ASP.NET Core WebAPI 开发-新建WebAPI项目, ASP.NET Core 1.0 RC2 即将发布,我们现在来学习一下 ASP.NET Core WebAPI开发. 网上已经有泄 ...

  9. Asp.net Core WebApi 使用Swagger做帮助文档,并且自定义Swagger的UI

    WebApi写好之后,在线帮助文档以及能够在线调试的工具是专业化的表现,而Swagger毫无疑问是做Docs的最佳工具,自动生成每个Controller的接口说明,自动将参数解析成json,并且能够在 ...

随机推荐

  1. oracle常见命令

    1.权限 (1)系统权限 系统权限是指对数据库系统的权限和对象结构控制的权限. 如grant create session to 用户名 -赋予用户登录的权限 (2)对象权限 访问其它用户对象的权利 ...

  2. mysql的一次意外

    打开navcat连接本地mysql数据库的时候说mysql服务无法连接,切换到cmd用命令行来启动报错,发生系统错误5,查看百度,需用管理员权限运行, 用管理员运行依旧不好使 C:\WINDOWS\s ...

  3. Python:PNG图像生成MP4

    Python:PNG图像生成MP4 需求 需要将多张*.PNG图像,生成mp4格式的视频文件. 实现 利用Python中image库生成*.gif格式图像,但是图片未经压缩,文件体量较大. movie ...

  4. 数据库MHA原理

    一.数据库的高可用MHA (1):详细的步骤 1.master mysql宕机了,MHA manager :无法连接master 2.MHA在S1 S2找一个延迟最小的slave,确定为未来的mast ...

  5. CSS写一个圣诞树Chrome浏览器小插件

    一时兴起,突然想写一个Chrome浏览器插件,不知道写啥,就写了一个圣诞树小插件.项目源码>> Chrome浏览器插件 Chrome浏览器插件最主要的是:index.html.manife ...

  6. 这几种Java异常处理方法,你会吗?

    摘要:我们在软件开发的过程中,任何语言的开发过程中都离不开异常处理. 本文分享自华为云社区<Java异常处理学习总结>,作者: zekelove . 我们在软件开发的过程中,任何语言的开发 ...

  7. LeetCode352 将数据流变为多个不相交区间

    LeetCode352 将数据流变为多个不相交区间 1 题目 给你一个由非负整数 a1, a2, ..., an 组成的数据流输入,请你将到目前为止看到的数字总结为不相交的区间列表. 实现 Summa ...

  8. Visual Studio Debug only user code with Just My Code

    Debug only user code with Just My Code By default, the debugger skips over non-user code (if you wan ...

  9. 《JavaScript DOM编程艺术》:innerHTML

    来源:第七章 动态创建标记 innerHTML: 1.HTML页面建立空白div: <div id="testdiv"> </div> <script ...

  10. SpringCloud-初见

    目录 前言 微服务概述 微服务与微服务架构 微服务优缺点 微服务技术栈 为什么选择SpringCloud作为微服务架构 SpringCloud入门 SpringCloud和SpringBoot的关系 ...