基于 Debain11 构建 asp.net core 6.x 的基础运行时镜像

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 此处我们基于 Debian11 的 Linux 发行版,实现目标是编写 Dockerfile 构建 asp.net core 6.x 框架的 runtime 基础镜像。在 Docker 容器化运行环境中,应用程序运行中存在异常情况,此时可以借助一些常用的基础工具方便排查,因此我们需要在 asp.net core 6.x runtime 基础镜像添加 linux 环境常用的...

image.png

Linux 环境说明

此处我们基于 Debian11Linux 发行版,实现目标是编写 Dockerfile 构建 asp.net core 6.x 框架的 runtime 基础镜像。

在 Docker 容器化运行环境中,应用程序运行中存在异常情况,此时可以借助一些常用的基础工具方便排查,因此我们需要在 asp.net core 6.x runtime 基础镜像添加 linux 环境常用的基础工具。

注意:基础镜像的构建需要考虑镜像的体积和打包工具的安全隐患,此处不做过多讨论。

Debian 简介

1、Debian 是一个社区

来自世界各地的数以千计的志愿者共同为 Debian 操作系统工作,注重自由和开源软件。认识 Debian 计划。

2、Debian 是一个操作系统

Debian 是一个自由的操作系统,由 Debian 计划开发和维护。Debian 是一个自由的 Linux 发行版,添加了数以千计的应用程序以满足用户的需要。

关于 Debian 更多信息,请查看 => https://www.debian.org/intro/index.zh-cn.html

Debian 发行版本

Debian 一直维护着至少三个发行版本:稳定版(stable),测试版(testing)和不稳定版(unstable)

1、稳定版(stable

  • 稳定版包含了 Debian 官方最近一次发行的软件包。
  • 作为 Debian 的正式发行版本,它是我们优先推荐给用户您选用的版本。
  • 当前 Debian 的稳定版版本号是 11,开发代号为 bullseye。最初版本为 11.0,于 2021 年 08 月 14 日发布,其更新 11.6 已于 2022 年 12 月 17 日发布。

2、测试版(testing)

  • 测试版包含了那些暂时未被收录进入稳定版的软件包,但它们已经进入了候选队列。使用这个版本的最大益处在于它拥有更多版本较新的软件。
  • 想要了解 什么是测试版以及 如何成为稳定版的更多信息,请看 Debian FAQ
  • 当前的测试版版本代号是 bookworm

3、不稳定版(unstable)

  • 不稳定版存放了 Debian 现行的开发工作。通常,只有开发者和那些喜欢过惊险刺激生活的人选用该版本。推荐使用不稳定版的用户订阅 debian-devel-announce 邮件列表,以接收关于重大变更的通知,比如有可能导致问题的升级。
  • 不稳定版的版本代号永远都被称为 sid。

4、发行生命周期

Debian 通常会按照一定的规律每隔一段时间发布一个新稳定版。 对每个稳定发行版本,用户可以得到三年的完整支持以及额外两年的长期支持。

请查看 Debian Releases 维基页面和 Debian LTS 维基页面以了解详细信息。

更多详细信息,请查看 => https://www.debian.org/releases/

关于 Debian 11

Debian 11 带有 Linux 5.10 内核,这是一个长期支持(LTS)版本。一个新的内核显然意味着对硬件有更好的支持,特别是较新的硬件以及性能的改进。

image.png


这里我们使用 Debian 11,代号为 bullseye,网络安装, 用于 64 位 PC(amd64) debian-11.6.0-amd64-netinst.iso

关于 Debian 11 更多信息:

Linux 常用基础工具

当在 Linux 服务器执行 telnet 命令时,如果提示 command not found: telnet,说明服务器上并未安装 telnet 命令,需要安装此命令。

下面介绍在 linux 服务器如何安装 telnet、curl、ifconfig、vim、ping 等工具。

首先,介绍一个安装工具时必须的命令 apt installapt install 是应用程序管理器,用于一键安装软件包,与源码安装不同的是,该指令会自动检测并安装依赖,而且用 apt 安装的包都是成熟的软件包,基本不存在安装包有严重 bug 或者文件缺失的情况。

# 1、首先执行如下命令,更新相关资源。将所有包的来源更新,也就是提取最新的包信息,这一命令使用率非常高。
apt update

# 2、安装 telnet
apt install telnet

# 3、安装 curl
apt install curl

# 4、安装 ifconfig
apt install net-tools

# 5、安装 vim
apt install vim

# 6、安装ping
apt install inetutils-ping

# 7、安装 ipaddr
apt install iproute2

上面这些基础工具的安装,可以整合一条命令,执行操作如下:

apt update && apt install -y net-tools iproute2 iputils-ping telnet curl vim

执行上面命令,如果不是 root 用户,需在前面添加 sudo 提权,继续执行操作。

Dockerfile 中 RUN 指令

上面我们介绍了 linux 环境中常用的基础工具,此处我们 app 应用程序是容器化运行环境,为了方便排查异常信息,通常会在 runtime 基础镜像中添加一些常用工具。

在编写 Dickerfile 构建 asp.net core runtime 镜像环境时,我们先来了解下 Dockerfile 中的 RUN 指令。

RUN 语法格式

DockerfileRUN 指令的编写格式有两种:

  • shell 形式】,命令在 shell 中运行,默认情况下,Linux/bin/sh -cWindowscmd /S /C
  • exec 形式】,按照 JSON Array 格式解析,意味着必须使用双引号【"】包含参数,而不能使用单引号【’】;

RUN 语义说明

RUN 指令在当前镜像的顶层上新建层执行命令,同时提交执行结果。提交的结果会在接下来的 Dockerfile 处理。

分层 RUN 指令和生成提交符合 Docker 的核心理念,即:提交便利,容器可以依据任意历史镜像构建,像源代码管理一样。

  • exec 形式能够避免 shell 形式表达含义模糊的问题,同时能够在一个不包含 shell 命令的基础镜像上执行 RUN 指令。
  • shell 形式的默认 shell 可以通过 SHELL 修改。
  • shell 形式中,若是指令参数过长,可以使用符号【\】换行显示。
# RUN 参数不换行.
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
# RUN 参数换行.
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
  • exec 形式是按照 JSON Array 格式解析,必须使用双引号【"】包含参数。

与 shell 形式不同,exec 形式不会调用 shell 命令行,意味着不会进行 shell 处理。

=> 例如:运行 `RUN ["echo", "$HOME"]` 不会对 `$HOME` 进行变量替换。
如果需要 shell 处理,那么可以使用 shell 形式或直接执行 shell;
=> 例如:`RUN["sh","-c","echo $HOME"]`。
当使用 exec 形式直接执行 shell 时,与 shell 形式类似,应用的 shell 是宿主机而非 Docker。
  • exec 形式中的 JSON,必须转译反斜杠【\】。Windows 系统中,反斜杠【\】是路径分隔符,是需要特别关注的。否则,由于不是有效的 JSON,执行时会出现异常从而失败。
# 错误写法
RUN ["c:\windows\system32\tasklist.exe"]

# 正确写法
RUN ["c:\\windows\\system32\\tasklist.exe"]
  • RUN 指令的缓存不会在下次构建时自动失效。
RUN apt dist-upgrade -y 指令的缓存将在下次构建时重用。
RUN 指令的缓存可以通过使用 `--no-cache` 标志置为无效,例如:docker build --no-cache
  • RUN 指令的缓存可由 ADDCOPY 指令置为无效。

编写 Dockerfile 构建 Runtime 基础镜像

Docker 中,编写 Dockerfile 是有个细节需要注意,RUN 指令执行多个命令时,可以合并写成一个,在 Dockerfile 中每执行一个指令都会对应的生成一个层,相应的构建镜像的体积也会随之增加。

ASP.NET Core Runtime 基础镜像

  • 微软 MCR 容器镜像仓库,ASP.NET Core Runtime

image.png

访问地址: https://mcr.microsoft.com/en-us/product/dotnet/aspnet/about

Dockerfile 编写

上面我们介绍了 RUN 指令的语法格式,同样的这里我们为了尽量建设镜像构建的层,通常情况我们会把多个命令整合为一个 RUN 指令执行,完整 Dockerfile 编写如下:

FROM mcr.microsoft.com/dotnet/aspnet:6.0
# Debian 源添加参考
# https://developer.aliyun.com/mirror/debian?spm=a2c6h.13651102.0.0.3e221b1137LtM1
# https://mirrors.ustc.edu.cn/help/debian.html
# https://mirrors.tuna.tsinghua.edu.cn/help/debian/

# RUN 使用 shell 语法
RUN sed -i -E 's/(deb|security).debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN sed -i 's/snapshot.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt update && apt install -y net-tools iproute2 iputils-ping telnet curl vim

# RUN 使用 exec 语法
#RUN ["apt", "update"]
#RUN ["apt","install","-y","vim","curl","telnet","iputils-ping","iproute2","net-tools"]

Windows 环境使用 WSL2 安装 Docker Desktop 工具

注意:在 windows 环境使用 Dockerfile 构建镜像,需要安装 Docker Desktop 工具并启动运行。

Windows 环境安装 Docker Desktop 工具,推荐使用 WSL2 模式运行。此处不过多讲解安装细节,请自行查看资料镜像安装。

image.png

Docker Engine 添加如下信息:

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "dns": [
    "8.8.8.8",
    "8.8.4.4"
  ],
  "experimental": false,
  "features": {
    "buildkit": true
  },
  "insecure-registries": [
    "https://hub.atguigu.com"
  ],
  "registry-mirrors": [
    "https://registry.docker-cn.com",
    "http://hub-mirror.c.163.com",
    "https://mirror.ccs.tencentyun.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://cr.console.aliyun.com/"
  ]
}

docker build 构建 image 镜像

  • 执行 docker build 构建命令:
docker build -t aspnet:6.0-debian11-amd64 ./
  • 输出如下 image 镜像构建步骤信息:
[+] Building 0.6s (9/9) FINISHED
 => [internal] load build definition from Dockerfile                                                               0.0s
 => => transferring dockerfile: 32B                                                                                0.0s
 => [internal] load .dockerignore                                                                                  0.0s
 => => transferring context: 2B                                                                                    0.0s
 => [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:6.0                                               0.4s
 => [1/5] FROM mcr.microsoft.com/dotnet/aspnet:6.0@sha256:a4ac0ac8b96842c3d4161339e641d335e44f52647bdeb4ed619ac83  0.0s
 => CACHED [2/5] RUN sed -i -E 's/(deb|security).debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list            0.0s
 => CACHED [3/5] RUN sed -i 's/snapshot.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list                    0.0s
 => CACHED [4/5] RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list                         0.0s
 => CACHED [5/5] RUN apt update && apt install -y net-tools iproute2 iputils-ping telnet curl vim                  0.0s
 => exporting to image                                                                                             0.0s
 => => exporting layers                                                                                            0.0s
 => => writing image sha256:8e4e01b9340eef513279899468870ff57826a1e4f3a6f0b3689212d88f3119eb                       0.0s
 => => naming to docker.io/library/aspnet:6.0-debian11-amd64                                                       0.0s

Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them

从上面输出的信息可以看出,Dockerfile 文件中每一行单独编写的命令,都会当做一个步骤执行,一共执行 [5/5] 个步骤。

查看 docker 镜像信息

此时我打开 Docker Desktop 桌面端工具,选择 Images ,搜索框输入 tag 名称【aspnet-debian11-amd64:6.0】就可以看到刚才构建的镜像,体积 270.54 MB

image.png

和原生【mcr.microsoft.com/dotnet/aspnet:6.0】镜像相比,体积增加 170.51 MB,新增的这部分体积,主要是我们在这个镜像的基础上,添加了一些 linux 环境的常用小工具(net-tools、iproute2、iputils-ping、telnet、curl、vim)。

我们可以点击【aspnet-debian11-amd64:6.0】镜像,即可进入镜像查看构建的层信息,如下所示:

image.png

查看上面的镜像层信息,同样的我们也可以使用命令操作查看,操作如下:

docker inspect : 获取容器/镜像的元数据。
docker inspect [OPTIONS] NAME|ID [NAME|ID...]

OPTIONS 说明:

  • -f :指定返回值的模板文件。
  • -s :显示总的文件大小。
  • --type :为指定类型返回JSON。

具体命令如下:

 docker inspect aspnet:6.0-debian11-amd64

输出如下信息:

[
    {
        "Id": "sha256:8e4e01b9340eef513279899468870ff57826a1e4f3a6f0b3689212d88f3119eb",
        "RepoTags": [
            "aspnet:6.0-debian11-amd64"
        ],
        "RepoDigests": [],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2023-02-19T07:44:04.106566658Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": null,
            "Cmd": null,
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "ASPNETCORE_URLS=http://+:80",
                "DOTNET_RUNNING_IN_CONTAINER=true",
                "DOTNET_VERSION=6.0.14",
                "ASPNET_VERSION=6.0.14"
            ],
            "Cmd": [
                "bash"
            ],
            "Image": "",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 270542384,
        "VirtualSize": 270542384,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/z1zc2q5ucw0srd1q6fz9dv5zs/diff:/var/lib/docker/overlay2/4vf1uowirpwps4nw4guvfr610/diff:/var/lib/docker/overlay2/xzob6lo9w8ita21r9o6qdowh3/diff:/var/lib/docker/overlay2/1a04b4cea9f8ea832c5f91a20d4ddd4f29f6ec5acb8ebbda6848282ec8159590/diff:/var/lib/docker/overlay2/5036b7ee8c50e873affdb40f9d1fd0e37573631587ed6b1f45347a10995ad935/diff:/var/lib/docker/overlay2/f7d1f588113cb3de37d0cd574614db511a098ba64e18f02ade45cb4b1d431fb6/diff:/var/lib/docker/overlay2/f0c4b961c76c425d8383575ca78c176a890d78d871a5cf60daab2ddc96ffee8d/diff:/var/lib/docker/overlay2/f7c839b494ad006d157084d919c15e812e10e57a8ac1c5cdda4d0150bf494f21/diff",
                "MergedDir": "/var/lib/docker/overlay2/9zxjyc54rcaf107f6cj6fhiax/merged",
                "UpperDir": "/var/lib/docker/overlay2/9zxjyc54rcaf107f6cj6fhiax/diff",
                "WorkDir": "/var/lib/docker/overlay2/9zxjyc54rcaf107f6cj6fhiax/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:4695cdfb426a05673a100e69d2fe9810d9ab2b3dd88ead97c6a3627246d83815",
                "sha256:f30d150c01520fbbbdd1bedcef3f940d809c82a46e08301dcc713903d7272ba3",
                "sha256:fe674e2b138caf1ef6a67419d5fb0a9081ca0759d97ce711be80d5d4d67145e1",
                "sha256:ff13768cb51ea8fe1831d93c2d18690c3fdca8cfee40b75a738f62b133413573",
                "sha256:355b7bb8c23e0d867141b0af69ecb6df39730bcd1b6c754cfae9ad36ca3f5572",
                "sha256:8d56eaae8bfea0a5eac4caf4350fa1987c162cd7dba828aa292cc15c3e90d91b",
                "sha256:b7d0c701d1f04294b2b98d3103c3856c9cbabc592cde48d3e07eb03bff7cb18a",
                "sha256:46ef367d7575beda39ffd3774b4d47b29c2fe0b628f1269b4626053ca44169d5",
                "sha256:6809bcac556f83ca4489ba09980a5bef05c9bc7463a45e4dac7fb600beec1c4e"
            ]
        },
        "Metadata": {
            "LastTagTime": "2023-02-19T08:46:50.196739744Z"
        }
    }
]

镜像构建后,此时如果有镜像仓库(腾讯云平台准备 Docker 私有镜像仓库或者 IDC 机房搭建),确保 vm 和宿主机之间通信可以正常登录访问,此处以腾讯云 Docker 私有镜像仓库为例:

# 登录腾讯云docker registry
sudo docker login --username=[user] ccr.ccs.tencentyun.com
# 提示输入对应的密码即可
 
# 从 registry 拉取镜像
sudo docker pull ccr.ccs.tencentyun.com/dotnet/image-name:[tag]
 
# 将镜像推送到 registry
sudo docker login --username=[user] ccr.ccs.tencentyun.com
sudo docker tag [ImageId|image-name:tag] ccr.ccs.tencentyun.com/dotnet/aspnet:6.0-debian11-amd64
sudo docker push ccr.ccs.tencentyun.com/dotnet/aspnet:6.0-debian11-amd64

到这里我们就演示完 Dockerfile 的编写,以及 image 镜像构建的全过程。

总结

掌握 Dockerfile 文件语法格式的编写,熟悉 RUN 指令中多个命令的编写方式(减少 image 镜像构建层,相应的减少镜像体积大小),顺便熟悉下 Docker 镜像的构建 docker build 和 镜像的 push(推送)和 pull(拉取) 基本操作,感兴趣的小伙伴可以跟随上面描述动手实践起来,可以加深对 Docker 镜像构建的理解。

相关实践学习
通过workbench远程登录ECS,快速搭建Docker环境
本教程指导用户体验通过workbench远程登录ECS,完成搭建Docker环境的快速搭建,并使用Docker部署一个Nginx服务。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
17天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
3月前
|
开发框架 前端开发 JavaScript
盘点72个ASP.NET Core源码Net爱好者不容错过
盘点72个ASP.NET Core源码Net爱好者不容错过
71 0
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
63 0
|
2月前
|
开发框架 前端开发 .NET
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
为了便于大家查找,特将之前开发的.Net Core相关的五大案例整理成文,共计440页,32w字,免费提供给大家,文章底部有PDF下载链接。
35 1
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
|
2月前
|
算法 BI API
C#/.NET/.NET Core优秀项目和框架2024年1月简报
C#/.NET/.NET Core优秀项目和框架2024年1月简报
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
42 0
|
1月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
29 0
|
1月前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
5 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
99 5