容器技术相关概念讲解

容器和开放容器倡议 (OCI) 镜像是重要的开源应用程序打包和交付技术,受到 Docker 和 Kubernetes 等项目的欢迎。你越了解它们,你就越能使用它们来增强项目的一致性和可扩展性。

在本文中,我将用简单的术语描述这项技术,重点介绍镜像和容器的基本方面以供开发人员理解,然后讨论开发人员可以遵循的一些最佳实践,以使他们的容器可移植。

什么是镜像?

镜像只不过是软件的一种打包格式。一个很好的类比是 Java 的 JAR 文件或 Python wheel。JAR(或 EAR 或 WAR)文件只是具有不同扩展名的 ZIP 文件,Python wheel作为 gzip 压缩包分发。它们都在内部符合标准的目录结构。

镜像被打包为tar.gz(gzipped tarball),它们包括您正在构建和/或分发的软件,但这就是与 JAR 和wheel的类比结束的地方。一方面,镜像不仅包含您的软件,还包含运行您的软件所需的所有支持依赖项,包括完整的操作系统。wheel和 JAR 通常构建为依赖项,但可以执行,而镜像几乎总是构建为执行,很少作为依赖项构建。

了解镜像中内容的详细信息对于了解如何使用镜像或为它们编写和设计软件(如果您有兴趣,请阅读“什么是容器镜像?”)。从您的角度,尤其是从您的软件的角度来看,重要的是要了解您创建的镜像将包含一个完整的操作系统。因为从您希望运行的软件的角度来看,镜像被打包成一个完整的操作系统,所以它们必然比以更传统方式打包的软件大得多。

请注意,镜像是不可变的。它们一旦构建就无法更改。如果您修改镜像上运行的软件,您必须构建一个全新的镜像并替换旧镜像。

 

标签

创建镜像时,它们使用唯一的哈希创建,但它们通常使用人类可读的名称来标识,例如ubi、ubi-minimal、openjdk11等。但是,每个名称都可以有不同版本的镜像,并且通常通过标签来区分。例如,openjdk11镜像可能被标记为jre-11.0.14.1_1-ubi并表示分别安装在 Red Hat和镜像
jre-11.0.14.1_1-ubi-minimal,上的 openjdk11 软件包版本 11.0.14.1_1 的镜像构建。ubiubi minimal

什么是容器?

容器是在主机系统上实现并执行的镜像。从镜像运行容器分为两步:创建和启动。Create 获取镜像并为其提供自己的 ID 和文件系统。创建(docker create例如,在 中)可以重复多次,以创建运行镜像的多个实例,每个实例都有自己的 ID 和文件系统。启动容器将在主机上启动一个隔离进程,在该进程中,在容器内运行的软件的行为就像在其自己的虚拟机中运行一样。因此,容器是主机上的一个独立进程,具有自己的 ID 和独立的文件系统。

从软件开发人员的角度来看,使用容器有两个主要原因:一致性和可扩展性。这些是相互关联的,它们共同允许项目使用近年来最有前途的软件开发创新之一,即一次构建,多次部署的原则。

一致性

因为镜像是不可变的,并且包含从操作系统开始运行软件所需的所有依赖项,所以无论您选择部署它,您都可以获得一致性。这意味着无论您在开发、测试或任何数量的生产环境中将镜像作为容器启动,容器都将以完全相同的方式运行。作为软件开发人员,您不必担心这些环境中的任何一个是否运行在不同的主机操作系统或版本上,因为容器每次都运行相同的操作系统。这就是将您的软件与其完整的运行时环境一起打包的好处,而不仅仅是您的软件没有运行它所需的完整依赖项集。

这种一致性意味着在几乎所有情况下,当在一个环境(例如,生产环境)中发现问题时,您可以确信自己能够在开发或其他环境中重现该问题,因此您可以确认行为并专注于修复它。你的项目不应该再次陷入可怕的“但它可以在我的机器上工作”的问题。

可扩展性

镜像不仅包含您的软件,还包含运行您的软件所需的所有依赖项,包括底层操作系统。这意味着在容器内运行的所有进程都将容器视为宿主系统,宿主系统对容器内运行的进程是不可见的,并且从宿主系统的角度来看,容器只是它管理的另一个进程。当然,虚拟机做的事情几乎一样,这就提出了一个合理的问题:为什么要使用容器技术而不是虚拟机?答案在于速度和大小。

容器只运行支持独立主机所需的软件,而无需模拟硬件的开销。虚拟机必须包含完整的操作系统并模仿底层硬件。后者是一个非常重量级的解决方案,它也会产生更大的文件。因为从主机系统的角度来看,容器只是另一个正在运行的进程,所以它们可以在几秒钟内而不是几分钟内启动。当您的应用程序需要快速扩展时,容器每次都会在资源和速度上击败虚拟机。容器也更容易缩减。

从功能的角度来看,扩展超出了本文的范围,因此实验室不会演示此功能,但重要的是要了解原理,以便了解为什么容器技术代表了软件打包和部署方面的如此重大进步。

注意:虽然可以运行不包含完整操作系统的容器,但很少这样做,因为可用的最小镜像通常是一个不足的起点。

如何查找和存储镜像

与所有其他类型的软件打包技术一样,容器需要一个可以共享、查找和重用包的地方。这些被称为镜像注册表,类似于 Java Maven 和 Python wheel存储库或 npm 注册表。

这些是 Internet 上可用的不同镜像注册表的示例:

  • Docker Hub:原始的 Docker 注册表,托管了许多在全球项目中广泛使用的 Docker 官方镜像,并为个人提供了托管自己的镜像的机会。在 Docker Hub 上托管镜像的组织之一是采用openjdk;查看他们的存储库以获取openjdk11项目的镜像和标签示例。
  • 红帽镜像注册表:红帽的官方镜像注册表为那些拥有有效红帽订阅的人提供镜像。
  • Quay:Red Hat 的公共镜像注册中心托管了许多 Red Hat 的公共可用镜像,并为个人提供了托管自己的镜像的机会。

使用镜像和容器

有两个实用程序用于管理镜像和容器:Docker和Podman。它们可用于 Windows、Linux 和 Mac 工作站。从开发人员的角度来看,它们在执行命令时是完全等价的。它们可以被认为是彼此的别名。您甚至可以在许多系统上安装一个包,它会自动将 Docker 更改为 Podman 别名。在本文档中提到 Podman 的任何地方,都可以安全地替换 Docker,而不会改变结果。

 

您会立即注意到这些实用程序与Git非常相似,因为它们执行标记、推送和拉取。您将定期使用或参考此功能。然而,它们不应与 Git 混淆,因为 Git 也管理版本控制,而镜像是不可变的,并且它们的管理实用程序和注册表没有变更管理的概念。如果您将两个具有相同名称和标签的镜像推送到同一个存储库,则第二个镜像将覆盖第一个镜像,而无法查看或理解发生了什么变化。

子命令

以下是您将常用或参考的 Podman 和 Docker 子命令的示例:

  • build: 建立一个镜像例子:podman build -t org/some-image-repo -f Dockerfile
  • image:在本地管理镜像示例:podman image rm -a将删除所有本地镜像。
  • images: 列出本地存储的镜像
  • tag:标记镜像
  • container: 管理容器示例:podman container rm -a将删除所有已停止的本地容器。
  • run:和一个容器 createstartstoprestart
  • pull/ push:从/向注册表上的存储库拉/推和镜像

Dockerfiles

Dockerfile 是定义镜像的源文件,并使用build子命令进行处理。他们将定义父镜像或基础镜像,复制或安装您希望在镜像中运行的任何额外软件,定义要在构建和/或运行时使用的任何额外元数据,并可能指定在何时运行的命令由您的镜像定义的容器正在运行。

Docker 和 Podman 的根本区别

Docker 是类 Unix 系统中的守护进程和 Windows 中的服务。这意味着它一直在后台运行,并且以 root 或管理员权限运行。Podman 是二进制的。这意味着它仅按需运行,并且可以作为非特权用户运行。

这使得 Podman 更安全、更高效地使用系统资源(如果不需要,为什么要一直运行?)。根据定义,以 root 权限运行任何东西都不太安全。在云上使用镜像时,托管容器的云可以更安全地管理镜像和容器。

Skopeo 和 Buildah

虽然 Docker 是一个单一的实用程序,但 Podman 在 GitHub 上还有两个由 Containers 组织维护的相关实用程序:Skopeo和Buildah。两者都提供 Podman 和 Docker 不具备的功能,并且都属于容器工具包组的一部分,Podman 用于安装在 Red Hat 系列 Linux 发行版上。

在大多数情况下,构建可以通过 Docker 和 Podman 执行,但 Buildah 存在以防需要更复杂的镜像构建。这些更复杂的构建的细节远远超出了本文的范围,你很少会遇到对它的需求,但为了完整起见,我在这里提到了这个实用程序。

Skopeo 提供了 Docker 没有的两个实用功能:将镜像从一个注册表复制到另一个注册表的能力以及从远程注册表中删除镜像的能力。同样,此功能超出了本次讨论的范围,但该功能最终可能对您有用,尤其是在您需要编写一些 DevOps 脚本时。

分类: 默认 标签: 发布于: 2022-05-31 09:37:51, 更新于: 2022-05-31 09:39:27