面向开发人员的镜像和容器实践指南

译者:崔莹峰

了解镜像和容器背后的关键概念。然后尝试演示一个构建和运行镜像和容器的实验。

容器和开放容器计划(OCI)镜像是重要的开源应用程序打包和交付技术,Docker和Kubernetes等项目使其流行起来。您对它们理解得越好,就越能够使用它们来增强项目的一致性和可伸缩性。

在本文中,我将用简单的术语描述这项技术,重点介绍镜像和容器的基本方面以供开发人员理解,然后讨论开发人员可以遵循的一些最佳实践,以使他们的容器可移植。我还将引导您完成一个简单的实验,该实验将演示如何构建和运行镜像和容器。

什么是镜像?

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

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

了解镜像中内容的详细信息对于了解如何使用镜像或为它们编写和设计软件并不是必要的。从软件的角度来看,重要的是要理解您创建的镜像将包含一个完整的操作系统。因为从您希望运行的软件的角度来看,镜像被打包成一个完整的操作系统,所以它们必然比以更传统方式打包的软件大得多。

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

标签

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

什么是容器?

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

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

一致性

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

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

可伸缩性

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

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

从功能的角度来看,可伸缩性超出了本文的范围,因此本实验不会演示该特性,但是为了理解为什么容器技术代表了软件打包和部署方面的重大进步,理解该原理是很必要的。

注意:虽然可以运行不包含完整操作系统的容器,但很少这样做,因为可用的最小镜像可能会引发其它问题。

如何发现和存储镜像

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

以下是互联网上可用的不同镜像注册表的例子:

DockerHub:最初的Docker注册表,托管了许多在世界各地项目中广泛使用的Docker官方镜像,并为个人提供托管自己镜像的机会。如adoptopenjdk就是在DockerHub上托管镜像的组织之一;可以点击openjdk11查看其存储仓库以获取该组织项目镜像和标签示例。

RedHatImageRegistry:红帽的官方镜像注册表,为那些有效红帽订阅者提供镜像。

Quay:RedHat的公共镜像注册表托管了许多RedHat的公共可用镜像,并为个人提供了托管自己的镜像的机会。

使用镜像和容器

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

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

子命令

下面是你会经常使用或引用的Podman和Docker子命令的例子:

build:构建镜像

例子:podmanbuild-torg/some-image-repo-fDockerfile

image:本地镜像管理

例子:podmanimagerm-a删除所有本地镜像

images:列出本地存储的镜像

tag:为镜像打标签

container:容器管理

例子:podmancontainerrm-a删除所有已停止的容器

run:创建并启动一个容器

还有stopandrestart

pull/push:从/向注册表上的存储库拉/推和镜像

Dockerfiles

Dockerfile是定义镜像的源文件,并使用build子命令进行处理。该文件将定义一个父镜像或基础镜像,复制或安装您希望在镜像中运行的任何额外软件,定义在构建或运行软件过程中使用到的任何额外元数据,并有可能指定一个命令,该命令在镜像实例化为容器后会立即执行。下面的实验对Dockerfile的结构以及其中使用的一些更常用的命令进行了更详细的描述。

Docker和Podman的根本区别

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

这使得Podman对系统资源更安全、更高效。根据定义,以root权限运行任何东西都不太安全。在云端使用镜像时,托管容器的云可以更安全地管理镜像和容器。

Skopeo和Buildah

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

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

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

Dockerfiles实验

以下是一个非常短的实验(大约10分钟),它将教您如何使用Dockerfiles构建镜像并将这些镜像作为容器运行。它还将演示如何将容器配置外部化,以实现容器开发的全部优势和“一次构建,多次部署”。

安装

以下实验室是在本地运行Fedora并在已安装Podman和Git的RedHat沙盒环境中创建和测试的。我相信在RedHat沙箱环境中运行它会让您从这个实验中获得最大的收获,但是在本地运行它也是完全可以接受的。

您还可以在自己的工作站上安装Docker或Podman并在本地工作。提醒一下,如果您安装了Docker,podman和docker对于这个实验来说是完全可以互换的。

构建镜像

1.从GitHub克隆Git存储库:

复制

$gitclone


转载请注明:http://www.aierlanlan.com/rzfs/4991.html