Podman 简介
Podman
是 Red Hat
开发的一款容器管理工具,它允许用户在没有守护进程的情况下运行、构建、管理和推送容器。Podman
是一个无守护进程的容器引擎,这意味着它不需要一个持续运行的后台进程来管理容器,这与 Docker
的守护进程模式不同。Podman
支持 Open Container Initiative (OCI)
标准,可以与 Docker
镜像兼容,并且可以在大多数 Linux
平台上使用,包括 RHEL、Fedora、CentOS、Debian、Ubuntu、openEuler
等。
Podman
的主要特点包括:
- 无守护进程:
Podman
不需要守护进程,可以直接通过命令行工具控制容器。 - 非
root
用户权限(Rootless
):Podman
允许非root
用户运行容器,只需要适当配置SELinux
和AppArmor
。 - 容器组(
Pods
):Podman
支持容器组的概念,可以将多个容器作为一个整体进行管理,类似于Kubernetes
的Pod
概念。 - 容器持久化:即使重启系统,
Podman
管理的容器状态也会被保存。 Podman
可以很好的过渡到k8s
或k8s yaml
文件转换到Podman
环境。
构建镜像知识回顾
Alpine 镜像及其常用工具简介
Alpine Linux
是一个基于 musl libc
和 BusyBox
的轻量级 Linux
发行版,因此它的默认镜像非常小,只包含了运行系统所必需的基本工具和库。
Alpine
的默认镜像通常包括以下一些常用工具:
ash shell
- 默认的shell
,它是BusyBox
的一部分。BusyBox
- 包含了多种Unix
工具的单个可执行文件,如cat, cp, ls, grep, find, ifconfig, netstat, ping, telnet, wget, curl
等。apk
-Alpine
的包管理器,用于安装和升级软件包。OpenSSH
- 提供SSH
服务,用于远程登录和文件传输。mke2fs
和e2fsprogs
- 用于管理ext2, ext3
和ext4
文件系统的工具。iproute2
- 提供网络配置工具,如ip
命令。DNS resolver
- 用于DNS
查询的工具,如host
。libc6-compat
- 提供glibc
兼容性层,使得某些需要glibc
的二进制文件可以运行。ca-certificates
- 提供预装的SSL/TLS
证书,用于HTTPS
连接验证。musl
-Alpine
使用的libc
实现,提供了标准C
库的功能。Alpine
的镜像默认是非常精简的,如果需要额外的工具或库,你需要使用 apk add 命令来安装它们。例如,如果需要Python
,可以运行apk add python3
。
由于 Alpine
的小尺寸和低资源消耗,它在容器和嵌入式设备中非常受欢迎。然而,它的轻量级特性也意味着对于某些复杂的应用场景可能需要手动安装更多的工具和库。
基镜像【aspnet:8.0-alpine】简介
mcr.microsoft.com/dotnet/aspnet:8.0-alpine
镜像是 Microsoft
提供的一个基于 Alpine Linux
的 .NET Runtime
镜像,用于运行 .NET 8.0
的 ASP.NET Core
应用。这个镜像主要包含了运行 .NET 8.0
应用所需的运行时组件,以及 Alpine Linux
的基础工具集。
使用 podman pull
命令下载镜像:
podman pull mcr.microsoft.com/dotnet/aspnet:8.0-alpine
具体来说,这个镜像会包含但不限于以下组件:
.NET 8.0
运行时 - 用于执行.NET 8.0
的应用程序。- Alpine Linux - 一个轻量级的
Linux
发行版,它使用musl libc
和BusyBox
。 BusyBox
- 一个集合了众多常见Unix
工具的小型可执行文件,例如:cat, cp, ls, grep, find, ifconfig, netstat, ping, telnet, wget, curl
等。APK - Alpine
的包管理器,用于安装和管理软件包。OpenSSH
- 提供SSH
服务,用于远程登录和文件传输。DNS Resolver
- 用于DNS
查询的工具。CA Certificates
- 用于HTTPS
连接验证的预装SSL/TLS
证书。musl libc
-Alpine
使用的libc
实现,提供了标准C
库的功能。iproute2
- 提供网络配置工具,如ip
命令。
请注意,这个镜像主要关注于提供运行
.NET 8.0
应用所需的基础环境,因此它不会包含大量额外的工具或库。如果需要其他工具或库,比如数据库驱动、额外的编程语言或构建工具,你可能需要在Containerfile
或Dockerfile
中使用RUN apk add
命令进行安装。
为了确保镜像的轻量化和安全性,Microsoft
的官方镜像通常会避免包含不必要的软件,这样可以减少镜像的大小并降低潜在的安全风险。
如何构建 .NET 轻量级镜像?
构建轻量级的 .NET Core
镜像通常涉及到几个关键步骤,主要是选择正确的基础镜像、使用多阶段构建、优化文件结构以及清理不必要的文件。以下是详细的步骤:
- 选择基础镜像
- 选择一个轻量级的基础镜像非常重要,因为它直接影响最终镜像的大小。对于
.NET Core
,推荐使用以下基础镜像之一:
# 用于构建阶段,包含 SDK。
mcr.microsoft.com/dotnet/sdk:<version>-alpine
# 用于最终运行时镜像,仅包含运行时。
mcr.microsoft.com/dotnet/aspnet:<version>-alpine
Alpine Linux
版本的镜像通常比基于Debian
或Ubuntu
的镜像更小,因为它们使用了更小的libc
实现(musl libc
)和BusyBox
工具集。
- 多阶段构建
- 多阶段构建允许你使用不同的
Dockerfile
阶段来构建和打包你的应用,这样可以将构建过程产生的中间文件和缓存从最终镜像中剔除,从而减小镜像大小。示例演示请查看后面的【镜像构建步骤】。
- 使用
.dockerignore
文件
.dockerignore
文件可以排除不需要的文件或目录,避免它们被添加到镜像中。例如,你可以排除.git
目录、obj
和bin
文件夹等。
- 清理不必要的文件
- 在每个阶段的末尾,使用
RUN
命令来清理任何不再需要的文件,例如编译缓存或构建工具。
- 最终镜像优化
- 确保最终镜像只包含运行应用程序所需的文件。使用
-o
参数指定输出目录,然后在最终镜像中只复制这个目录。
通过以上步骤,你可以构建出轻量级的 .NET Core
镜像,这对于云原生环境和资源受限的部署场景尤其重要。
镜像构建步骤
要使用 Containerfile
(或 Dockerfile
)构建 .NET Core
或 .NET Framework
的应用(app
)镜像,你可以遵循以下步骤。这里以 .NET Core
为例,因为 .NET Framework
的容器化通常需要更复杂的 Windows
基础镜像,而 .NET Core
则有轻量级的 Linux
镜像可供选择。
说明:
.net core /.net8
使用alpine
构建镜像可以减少一半镜像体积。
步骤 1: 创建 Containerfile
在你的项目根目录下创建一个名为 Containerfile
的文件(也可以命名为 Dockerfile
)。这个文件将包含用于构建 Podman/Docker
镜像的所有指令。
步骤 2: 编写 Containerfile
下面是一个基本的 Containerfile
示例,用于构建 .NET Core
应用:
# 第一阶段:构建
# 使用官方的 .NET Core SDK 镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build-env
# 设置工作目录
WORKDIR /app
# 指定后续指令的用户上下文
USER app
# 将当前目录的内容复制到容器中的 /app 目录
COPY ["./", "/app/"]
# 运行 dotnet restore 命令来下载所有依赖项
RUN dotnet restore
# 使用 dotnet publish 命令构建应用程序发布文件
RUN dotnet publish -c Release -o out
# 第二阶段:最终镜像
# 使用更小的运行时镜像来部署应用
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
# 添加镜像的元数据,使用键值对的形式。为了在 LABEL 的值里面可以包含空格,你可以在命令行解析中使用引号和反斜杠
LABEL maintainer=“chait@qq.com” \
description=“This is my .net app”
# 设置工作目录
WORKDIR /app
# 复制从第一阶段构建的输出
COPY --from=build-env /app/out .
# 声明容器运行时监听的特定网络端口,指定监听协议是TCP还是UDP,若未指定协议,则默认为TCP。
EXPOSE [8080/tcp, 443/tcp]
# 在容器内部设置环境变量
ENV ASPNETCORE_ENVIRONMENT=Production \
ASPNETCORE_URLS=http://+:8080;https://+:443;
# 设置时间
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 创建匿名数据卷挂载点
VOLUME ["/wwwroot/resource","/AppData/Configuration","/AppData/Database"]
# 设置入口点,容器创建时的主要命令(不可被覆盖)
ENTRYPOINT ["dotnet", "YourAppName.dll"]
- 命令解释(
LABEL/ENV/RUN
)
一个镜像可以有多个 labels
(ENV/RUN
类似)。你可以组合多个 labels
在一个 LABEL
里来指定多重 labels
。在Docker 1.10
之前,这种做法可以降低最终镜像的大小,但现在不是这样。你仍然可以选择一个指令指定多个labels
,使用以下的 2
种方法中其中一种:
LABEL maintainer=“chait@qq.com” \
description=“This is my .net app”
# or
LABEL maintainer=“chait@qq.com” description=“This is my .net app”
Labels
包含在基镜像或者父母镜像(在 FROM
行的镜像)继承到你的镜像。如果 label
本身已经存在但是值不一样,最后的赋值将会覆盖前面的复制。
如果要查看镜像的 labels
,可以使用 podman inspect
命令。
"Labels": {
"com.example.vendor": "ACME Incorporated"
"com.example.label-with-value": "foo",
"version": "1.0",
"description": "This text illustrates that label-values can span multiple lines.",
"multi.label1": "value1",
"multi.label2": "value2",
"other": "value3"
},
- 命令解释(
VOLUME
)
运行容器时可以从本地主机或其他容器挂载数据卷,一般用来存放数据库和需要保持的数据等;
VOLUME ["/wwwroot/resource","/AppData/Configuration","/AppData/Database"]
注意:必须使用双引号,不能使用单引号。
这里的 ["/wwwroot/resource","/AppData/Configuration","/AppData/Database"]
目录就会在运行时自动挂载为匿名卷,任何向 ["/wwwroot/resource","/AppData/Configuration","/AppData/Database"]
中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。
容器运行时使用,可以覆盖这个挂载设置。
# 命令语法
podman run -v <主机目录>:<容器目录>
# 举例说明
podman run -v app/data/resource:/wwwroot/resource \
-v app/data/config:/AppData/Configuration \
-v app/data/database:/AppData/Database
说明:在目标主机上面提前创建好
app/data/resource,app/data/config,app/data/database
三个文件目录,此处依据.net core
应用自身情况,这里只是举例说明。
- 重新发布
.net app
程序
之前在本机发布的时候,运行时选的是 linux-x64
,这样发布出来的可执行文件是依赖 glibc
的,但是 alpine
基础镜像里是 musl libc
。所以需要选择 linux-musl-x64
这个运行时,然后重新发布。
dotnet publish -r linux-musl-x64 -c Release -o out
如果使用 .net app
应用程序编译发布文件,Containerfile
可以简化如下:
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
LABEL maintainer=“chait@qq.com” \
description=“This is my .net app”
USER app
RUN sudo dnf update && sudo dnf upgrade
WORKDIR /app
COPY . .
EXPOSE [8080/tcp, 443/tcp]
ENV ASPNETCORE_ENVIRONMENT=Production \
ASPNETCORE_URLS=http://+:8080;https://+:443 \
TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
VOLUME ["/wwwroot/resource","/AppData/Configuration","/AppData/Database"]
ENTRYPOINT ["dotnet", "YourAppName.dll"]
步骤 3: 构建 Podman 镜像
在包含 Containerfile
的目录中,运行以下命令来构建 Podman
镜像:
podman build -t your-image-name:[tag] .
这将创建一个名为 your-image-name
的 Podman
镜像。
# 不指定 tag,默认是 latest
podman run -it --rm -p 8080:8080 your-image-name:[tag]
这将启动一个容器,并将宿主机的 8080
端口(左边)映射到容器的 8080
端口(右边)。
注意事项:
- 确保你的 .NET Core 应用支持跨平台,这样它才能在 Podman 容器中正确运行。
- 如果你的应用依赖于环境变量或配置文件,确保在Containerfile 中正确处理这些依赖。
- 考虑使用多阶段构建来减小最终镜像的大小,如上例所示。
- 测试你的 Podman 镜像,确保在不同的环境中都能正常运行。
关于 .net8 对云原生的支持
.NET 8
在云原生方面的支持有了显著的增强,这些改进旨在提高性能、减少资源消耗、简化部署流程以及提升应用程序的可观察性和可维护性。以下是 .NET 8
在云原生方面的一些关键特性和改进:
1、Garbage Collection (GC) 改进
.NET 8
的GC
堆对云原生环境进行了优化,能够更好地在多租户和资源受限的环境中运行,如 Kubernetes 集群。GC
操作现在更加高效,减少了对其他线程的影响,从而提高了应用程序的响应速度和吞吐量。
2、Native AOT (Ahead-Of-Time) 编译
.NET 8
引入了更完善的Native AOT
支持,允许在部署前将应用程序编译成本地机器代码,而不是在运行时进行 JIT 编译。- 这样做可以显著减少应用程序的启动时间和内存占用,同时减小程序的可执行文件大小,非常适合云原生环境的快速部署和资源效率需求。
3、性能提升
- 根据
TechEmpower
的基准测试,.NET 8
在JSON API
方案中性能提高了18%
,并且使用ASP.NET Core Minimal API
能够达到每秒近100
万个请求的处理能力。 - 这些性能提升有助于云原生应用在高并发场景下保持稳定和高效。
4、可观察性和可监测性
.NET 8
改进了云原生ASP.NET Core
程序的可观察性和可监测性,这对于分布式应用程序的调试和故障排查至关重要。- 改进的日志记录、健康检查、指标收集和追踪机制使得开发人员能够更好地理解应用程序在生产环境中的行为。
5、云原生工具和框架集成
.NET 8
支持与云原生工具和框架的深度集成,如:Kubernetes、Docker、Service Meshes
等,简化了在云环境中的部署和管理流程。
6、云原生安全
.NET 8
强调了安全性和合规性,提供了更强大的安全功能,如TLS 1.3
支持、安全的默认配置和加密算法,以及与云安全最佳实践的紧密集成。
这些改进共同作用,使 .NET 8
成为构建和部署云原生应用的理想选择,无论是对于微服务架构还是无服务器架构,.NET 8
都能提供强大的支持。