一、前言
最近在进行OS国产化交流中,了解到部分业务迁移到BClinux 8.2或Anolis 8.2时,原有docker业务需要迁移到新的容器平台:Podman,来完成容器的新的管理。Podman(全称 Pod Manager)是一款用于在 Linux® 系统上开发、管理和运行容器的开源工具。Podman 最初由红帽® 工程师联合开源社区一同开发,它可利用 lipod 库来管理整个容器生态系统。官方声称:Podman - The next generation of Linux container tools,它不仅可以管理 OCI 容器,还可以管理 pod 。
Podman 是一个 RedHat 公司发布的开源容器管理工具,初衷就是 Docker 的替代品,在使用上与 Docker 的相似,但又有着很大的不同。它与 Docker 的最大区别是架构,Docker 是以 C/S 架构运行的,我们平时使用的 docker 命令只是一个命令行前端,它需要调用 dockerd 来完成实际的操作,而 dockerd 默认是一个有 root 权限的守护进程。而Podman 不需要守护进程,直接通过 fork/exec 的形式启动容器,不需要 root 权限。这也是Podman其中一个较大优势,它采用了无守护进程的包容性架构,可以更安全、更简单地对容器进行管理,再加上 Buildah 和 Skopeo 等与之配套的工具和功能,开发人员能够按照自身需求来量身定制容器环境。 它实际与Docker扮演相同的角色,并且在很大程度上与 Docker 兼容,提供几乎相同的命令。总之,Podman是一个基于libpod库开发的容器运行时,用于在Linux操作系统上管理和运行容器。与传统的Docker容器运行时不同,Podman无需依赖Docker守护进程,它可以在不同的Linux发行版中独立运行。它支持常见的容器管理功能,如启动、停止、重启和删除容器,以及构建、推送和拉取容器镜像等。Podman还支持容器的网络和存储管理,可以使用CNI插件创建和管理容器的网络,支持使用多种存储驱动程序,如overlayfs、btrfs和zfs等。
Podman的一个显著特点是它使用的是rootless模式,这意味着它可以在普通用户权限下运行,而不需要root权限。这有助于提高容器运行的安全性和可移植性。同时,Podman支持通过Pods来管理一组相关的容器,这样可以方便地管理复杂的应用程序。
另外,Podman还支持使用systemd来管理容器,这使得它可以更好地集成到Linux系统中,与其他系统服务一起运行和管理。但无论怎样,它作为运行时,Podman的底层主要也是基于Linux的Cgroup和Namespace等技术。
Podman 可以帮助我能实现如下:
相关资料:containerd、Podman、Podman介绍、官网、Podman项目
二、架构和功能
2.1、运行时runtime
"运行时"就是程序运行的时候,也就是指令加载到内存并由CPU执行的时候,实际它就是一套比较底层的纯C语言API,是1个C语言库,包含了很多底层的C语言API,从而更好与Linux内核通信。与之相对应的是“编译时”,其指代码编译的时候,也就是C代码编译成可执行文件的时候,此时指令没有被CPU执行。对应的运行时库就是程序运行的时候所需要依赖的库。
每个环境都有自己的运行时,这里我们主要回顾容器的运行时(runtime),就是运行和管理容器进程、镜像的工具,可以把进程运行在容器中,并可通过SDK或命令来调用Linux的内核功能,从而创建出容器或其他关联容器底层的东西。runtime是在一个OCI(Open Container Initiative)组织中被明确定义的。OCI 发布了两个规范:runtime spec 和 image format spec;这样不同组织和厂商依据该规范开发的容器能够在不同的 runtime 上运行,保证了容器的可移植性和互操作性。 这个规范规定了容器之中应用被放到什么样的环境下、如何运行,比如说容器的根文件系统上哪个可执行文件会被执行,是用什么用户执行,需要什么样的 CPU,有什么样的内存资源、外置存储,还有什么样的共享需求等等。正如前文所述,runtime 就是容器(可理解就是一个独立的进程)真正运行的地方。整个过程中 需要跟操作系统 kernel 紧密协作,为容器提供运行环境。比如:那常见的Java环境举例,Java 程序就可看做是个容器,JVM 则好比是 runtime。JVM 为 Java 程序提供运行环境。同样的道理,容器只有在 runtime 中才能运行。
OCI规范概览:
目前主流的有三种容器 runtime:
当前后来随着发展,也出现了其他runtime,比如Kata Container、CRI-O等;最先,Docker使用的是LXC但是层次隔离不太完整,所以后来Docker开发了libcontainer,最后演变为了runC。
Runtime 主 要 定 义 了 以 下 规 范 , 并 以 json 格 式 保 存 在/run/docker/runtime-runc/moby/容器 ID/state.json 文件,此文件会根据容器的状态实时更新内容:
OCI 容器镜像主要包含以下内容:
容器运行时具有掌控容器运行的整个生命周期,包括镜像的构建和管理、容器的运行和管理等功能。容器运行时接口(Container Runtime Interface, CRI),是指上层应用无需编译就可以支持多种容器运行时的插件接口,通过插件的切换方式应用不同封装的容器。容器运行时向上提供容器调用接口,包括容器生成与销毁的全生命周期管理的功能,向下提供调用接口,负责具体的容器操作事项,例如一个典型的Kubernetes集群中,Kubernetes对具体的容器类型不感知,而通过Kubernetes节点代理kubelet实现了 CRI客户端 API,可以使用任何实现 CRI 服务器 API的容器运行时来管理其节点上的容器和 Pod。
根据容器运行时提供功能,可以将容器运行时分为低层运行时和高层运行时。
1)低层运行时主要负责与宿主机操作系统打交道,根据指定的容器镜像在宿主机上运行容器的进程,并对容器的整个生命周期进行管理。而这个低层运行时,正是负责执行我们前面讲解过的设置容器 Namespace、Cgroups等基础操作的组件。常见的低层运行时种类有:
2)高层运行时主要负责镜像的管理、转化等工作,为容器的运行做前提准备。主流的高层运行时主要containerd和CRI-O。
高层运行时与低层运行时各司其职,容器运行时一般先由高层运行时将容器镜像下载下来,并解压转换为容器运行需要的操作系统文件,再由低层运行时启动和管理容器。
另外这里还要注意的一个容器引擎containerd,2020年CNCF基金会宣布Kubernetes 1.20版本将不再仅支持Docker容器管理工具;早前Docker 1.11的Docker Engine里就包含了containerd,而现在则是把containerd从Docker Engine里彻底剥离出来,作为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础设施。在Docker Engine里containerd相比,独立的containerd将具有更多的功能,可以涵盖整个容器运行时管理的所有需求。另外独立之后containerd的特性演进可以和Docker Engine分开,专注容器运行时管理,可以更稳定。
Containerd是一个工业标准的容器运行时,重点是它简洁,健壮,便携,在Linux和window上可以作为一个守护进程运行,它可以管理主机系统上容器的完整的生命周期:镜像传输和存储,容器的执行和监控,低级别的存储和网络。每个containerd只负责一台机器,Pull镜像,对容器的操作(启动、停止等),网络,存储都是由containerd完成。具体运行容器由runC负责,实际上只要是符合OCI规范的容器都可以支持。
Containerd和docker不同,containerd重点是集成在大规模的系统中,例如kubernetes、Swarm、Mesos等【对于容器编排服务来说,运行时只需要使用containerd+runC,更加轻量,容易管理。】。Containerd 被设计成嵌入到一个更大的系统中,而不是直接由开发人员或终端用户使用。
2.2、Podman 是如何管理容器的?
用户可以通过命令行调用 Podman,从存储库拉取容器并运行它们。Podman 调用配置好的容器运行时来创建运行的容器。由于没有专门的守护进程,Podman 使用 systemd(一种用于 Linux 操作系统的系统和服务管理器)来进行更新并让容器在后台保持运行。通过将 systemd 和 Podman 集成,我们可以为容器生成控制单元,并通过自动启用 systemd 的前提下运行它们。
用户可以在系统上管理自有的存储库,也可通过 systemd 单元来控制自有容器的自动启动和管理。允许用户管理自己的资源并使容器以无根方式运行,可以阻止诸如使 /var/lib/containers 目录可被写入等不良做法,或防范可能会导致应用暴露于额外安全问题的其他系统管理做法。这样也可确保每一用户具有单独的容器和镜像集合,并可在同一主机上同步使用 Podman,而不会彼此干扰。用户完成自己的工作时,可将变更推送到共有的镜像仓库,将他们的镜像共享给其他人。
Podman 也可部署 RESTful API(REST API)来管理容器。REST 是表述性状态传递的英文缩写。REST API 是遵循 REST 架构规范的应用编程接口,支持与 RESTful Web 服务进行交互。借助 REST API,您可以从 cURL、Postman 和 Google 的 Advanced REST 客户端等许多平台调用 Podman。
三、部署配置
四、工具应用
4.1
4.2、Podman 桌面管理工具
Podman Desktop 使你能够轻松地使用本地环境中的容器,Podman Desktop 无守护进程,它利用 Podman Engine 提供轻量级且无守护程序的容器工具。该工具允许浏览、管理容器的生命周期、检查容器、来自不同容器引擎的镜像等。另,它专注于将 Podman 作为默认打包的容器引擎的同时,还兼容了其他容器引擎。Podman Desktop 具有以下一些特性:
资源获取:二进制包
五、附录:
5.1、Containerd回顾
如上图所示,docker为我们提供了抽象的容器调用接口,而其内部功能的具体实现却是调用的contanierd;2016年,docker 把负责容器生命周期的模块 containerd拆分出来,并将其捐赠给了社区。
Containerd的特点:
Containerd的作用:
Containerd架构:Containerd 采用标准的 C/S 架构:服务端通过 GRPC 协议提供稳定的 API;客户端通过调用服务端的 API 进行高级的操作。为了实现解耦,Containerd 将不同的职责划分给不同的组件,每个组件就相当于一个子系统(subsystem)。连接不同子系统的组件被称为模块。containerd 需要调用 runC,所以在安装 containerd 之前请先安装 runC。
containerd 的技术架构:
Containerd 被分为三个大块: Storage 、 Metadata 和 Runtime。
Containerd 两大子系统为:
【几个概念】:
1)containerd 是一个高级容器运行时,又名容器管理器。简单来说,它是一个守护进程,在单个主机上管理完整的容器生命周期:创建、启动、停止容器、拉取和存储镜像、配置挂载、网络等。
2)ctr 是作为 containerd 项目的一部分提供的命令行客户端。该ctr界面 [显然] 与 Docker CLI不兼容,乍一看,可能看起来不太用户友好。因为它的主要受众是测试守护进程的容器开发人员。ctr + containerd比docker + dockerd更接近实际的容器。
3)nerdctl 是一个相对较新的containerd命令行客户端。与ctr不同,nerdctl的目标是用户友好和docker兼容。在某种程度上,nerdctl + containerd可以无缝地替代docker + dockerd。
4)crictl 是一个命令行客户端,用于 [kubernetes] CRI兼容的容器运行时。引入 Kubernetes 容器运行时接口 (CRI)以使 Kubernetes 容器运行时不可知。Kubernetes节点代理kubelet实现了 CRI客户端 API,可以使用任何实现 CRI 服务器 API的容器运行时来管理其节点上的容器和 Pod。
相关资源:containerd官网、containerd官方安装步骤
5.2、Docker、containerd的关系
1)就docker本身而言,包括docker client和dockerd,是一个客户端工具,用来把用户的请求发送给docker daemon(dockerd)。dockerd:dockerd是对容器相关操作的最上层封装,直接面向操作用户。Docker daemon,一般也会被称为docker engine。dockerd启动时会启动containerd 子进程。
containerd-shim是一个真实运行容器的载体,为了能够支持多种OCI Runtime,containerd内部使用containerd-shim,每启动一个容器都会起一个新的containerd-shim的进程。它通常指定三个因素:容器ID、bundle目录(对应某个容器生成的目录,一般位于:/var/run/docker/containerd/containerID)
2)containerd囊括了单机运行一个容器时所需要的一切;containerd是一个工业级别标准的容器运行时,它强调简单性、健壮性和可移植性,几乎囊括了单机运行一个容器运行时所需要的一切:执行、分发、监控、网络、构建、日志等。主要作用是:
dockerd实际真实调用的还是containerd的api接口,containerd是dockerd和runC之间的一个中间交流组件。runC是一个轻量级的工具,用来运行容器的,我们可以不用通过docker引擎,直接运行容器。