Docker Ubuntu 镜像

2025年3月17日 | 阅读13分钟

容器化概念改变了应用程序的创建、开发、部署、测试、监控以及在生产环境中打包的方式。在引入容器技术之前,企业和组织在人力、时间和金钱方面花费了大量资源来设置物理服务器和虚拟机,并在其上部署应用程序组件和应用程序本身。

这个过程可以完成工作并且是安全的;然而,整个过程有点麻烦。开发人员需要经历创建环境、设置虚拟机和安装运行应用程序所需的二进制文件、包等的困难。通过虚拟机分发应用程序给多个开发人员也很困难。由于虚拟机运行在底层基础设施硬件之上,因此占用了大量资源。因此,需要一种更快、更有效的方式来改变整个开发生命周期。

  • 现在,开发人员可以创建容器化、便携式、隔离的打包环境来创建、测试、部署和开发他们的应用程序。
  • 这些环境包括运行应用程序所需的每个系统文件、包、二进制文件和其他文件。
  • 此外,由于容器运行在底层操作系统之上,我们可以轻松地在同一个操作系统上运行两个或多个容器,而不会相互干扰。
  • 因此,开发任何微服务架构都像在不同主机或同一台机器上构建多个集群容器一样容易。
  • 应用程序的更新以及共享容器中托管的应用程序也变得更加容易。

Docker 是一个开源且领先的容器服务提供商。自推出以来,它主导了整个市场。它易于理解,并使应用程序的部署和开发更加简单。

然而,当新手开始理解 Docker 容器化时,诸如注册表、docker-engine、docker hub、volumes、images、containers 等术语可能会让人感到困惑。

Docker 镜像简介

Docker 镜像可以描述为在 Docker 容器中执行代码的文件。Docker 镜像充当构建 Docker 容器的指令集,例如模板。此外,使用 Docker 时,Docker 镜像充当起点。在虚拟机环境中,快照类似于镜像。

Docker 用于在容器中创建、运行和部署应用程序。Docker 镜像包含应用程序代码、依赖项、工具、库以及运行任何应用程序所需的其他文件。如果用户执行镜像,它可以变成一个或多个容器实例。

Docker 镜像包含多个层,它们源自旧层但与之不同。

  • 这些层可以加快 Docker 的构建速度,同时减少磁盘使用量并提高可重用性。
  • 此外,镜像层是只读文件。
  • 在不可更改镜像的顶部添加了一个可写层,允许用户在建立容器后进行修改。
  • 在 Docker 容器和镜像中,对磁盘空间的引用可能会造成混淆。
  • 区分虚拟大小和正常大小非常重要。
  • 正常大小是指容器的可写层占用的磁盘空间,而虚拟大小是指可写层和容器使用的磁盘空间。
  • 来自相似镜像的镜像的只读层可以在容器之间共享。

Docker 镜像是我们创建的整个应用程序环境的蓝图。镜像也是只读的,这意味着我们无法对其进行修改;因此,镜像是不可变的。尽管如此,当我们创建相关的容器时,它们将是可写的。

  • 通常,有两种类型的 Docker 镜像 - 自定义镜像和官方基础镜像。
  • 自定义镜像使用基础镜像构建特定于应用程序的平台,而官方基础镜像预先构建好,可以通过注册表进行安装和拉取。
  • 此外,Docker 镜像之所以被称为 **快照**,是因为它们是不可变的。
  • 它包含了运行应用程序所需的每个配置文件、二进制文件、库等的定义。

**例如,** 假设我们想创建一个 Docker 容器和镜像来托管任何 Web 应用程序。我们需要遵循一个过程来做到这一点。但在深入研究这个过程之前,让我们先了解一些基本术语。

  • **Dockerfile:** 这些文件用于创建自定义的 Docker 镜像。它们包含逐步指南,例如拉取基础镜像、运行安装命令等。这些指南会创建一个镜像的中间层,并使用旧层的信息。
  • **Docker 注册表:** Docker 注册表类似于 GitHub 的存储库,其中包含预构建的 Docker 镜像,例如 Nginx、CentOS、Ubuntu、MySQL 等。官方 Docker 注册表是 Dockerhub。我们可以直接使用 Docker pull 命令从存储库中拉取镜像。
  • **Docker Volume:** Docker Volume 是解决持久化数据问题的方案。当我们删除容器或 Docker 镜像时,我们可能仍然需要与它们相关的一些数据。我们可以做的是在创建它们时将一些目录挂载到宿主机系统上,并在我们运行的与 Docker 镜像相关的容器中使用这些目录。

要构建用于托管任何 Web 应用程序的 Docker 镜像,我们必须使用 Nginx 服务器来提供页面。我们首先需要构建一个 dockerfile,其中包含创建镜像的指令。然后,通过描述指令 **"FROM UBUNTU"**,从 Dockerhub 拉取 Ubuntu Docker 基础镜像,这是第一次。

这意味着当我们创建镜像后创建一个容器时,我们可以使用 Ubuntu 操作系统并通过命令行在其上工作。之后,我们必须使用指令 **"Run <command>"** 来获取 Nginx Web 服务器。

在这里,我们可以定义任何命令。这意味着当容器构建完成时,命令将运行。通常,它用于安装包、更新操作系统等。我们必须以与在 Linux 机器上获取包相同的方式使用此命令来获取 Nginx。

Docker 的用例

Docker 镜像包含运行容器化应用程序所需的一切,例如库、运行时、环境变量、配置文件和代码。当镜像被部署到 Docker 环境中时,它就可以作为 Docker 容器运行。Docker 的 run 命令可以根据特定镜像创建一个容器。

Docker 镜像是一种可重用的资产,可以在主机上部署。开发人员可以从单个项目中获取静态镜像的层并将其应用于另一个项目。这节省了用户的时间,因为他们不需要从头开始重新创建任何镜像。

Docker 镜像与 Docker 容器的区别

Docker 容器可以被描述为用于应用程序开发中的虚拟化运行时环境。它用于创建、运行和部署与底层硬件隔离的应用程序。Docker 容器可以利用单个机器,共享其内核,并虚拟化操作系统以运行更多隔离的进程。因此,Docker 容器非常轻量级。

Docker 镜像与虚拟机环境中其他类型的快照相同。它是 Docker 容器在特定时间点的记录。此外,Docker 镜像是不可变的。它们可以被删除、共享或复制,但不能被修改。此功能有助于测试新的软件配置,因为无论发生什么,镜像都不会改变。

容器需要一个可运行的镜像才能存在。它们依赖于镜像,因为它们用于构建运行时环境并需要运行应用程序。

Docker 镜像的解剖

Docker 镜像包含多个层,所有镜像都包含配置容器环境所需的一切:依赖项、工具、系统库和其他文件。以下是一些镜像部分的说明和解释

Docker Ubuntu Image

1. 基础镜像

用户可以完全使用 build 命令从头开始创建此初始层。

2. 父镜像

父镜像可以是 Docker 镜像中的初始层,而不是基础镜像。它是一个被重用的镜像,充当所有其他镜像的基础。

3. 容器层

Docker 镜像不仅仅创建一个新容器,还创建一个容器或可写层。它托管对活动容器所做的修改,并保存新删除和写入的文件,以及对现有文件的修改。此外,此层用于自定义容器。

4. 层

许多层通过代码连接到基础镜像,这些代码允许它在容器中执行。所有 Docker 镜像层都可以在 **/var/lib/docker/aufs/diff** 目录中查看,或者通过 CLI (Command Line Interface) 的 docker history 命令查看。

Docker 的默认状态是显示所有顶层镜像,如文件大小、标签和仓库。中间层被缓存,便于顶层镜像查看。Docker 包含管理镜像层内容管理的存储驱动程序。

5. Docker manifest

此 Docker 镜像部分是一个额外文件。它使用 JSON 格式来描述镜像,包含数字签名和镜像标签等信息。

Docker 镜像仓库

Docker 镜像存储在公共或私有仓库中,例如 **Docker Hub** 的云注册表服务,所有用户都可以从中获取容器并共享和测试镜像。 **Docker Hub** 的 **Docker Trusted Registry** 还提供访问控制和镜像管理功能。

官方镜像是 Docker 生成的,而社区镜像是 Docker 用户制作的镜像。**CoScale agent** 可以被描述为 Docker 的一个官方镜像,用于检查 Docker 应用程序。**Docker-dd-agent/Datadog** 是一个 Docker 容器,用于 Datadog 的日志管理程序中的代理。

这是社区 Docker 镜像的一个例子。

  • 此外,用户可以通过现有镜像制作新镜像,并使用 Docker 的 push 命令将自定义镜像上传到 Docker Hub。
  • Docker 促进了在发布前向生产者提供反馈,以确保社区镜像的质量。
  • 发布镜像后,生产者负责更新。
  • 生产者应谨慎从其他方获取镜像,因为所有攻击者都可以通过模仿镜像来访问计算机,诱使用户认为它们来自受信任的来源。
  • 最新的镜像概念也可能引起混淆。标题为 **".latest"** 的 Docker 镜像不一定是通常意义上的最新版本。
  • latest 标签并不指代镜像的最新发布版本;它只是一个默认标签。

如何制作 Docker 镜像?

所有 Docker 镜像都可以从 **Dockerfile** 或 **交互式** 方法创建。这两种方法列出并解释如下:

Docker Ubuntu Image

Dockerfile 方法

此方法需要创建一个纯文本 **Dockerfile**。这个 **Dockerfile** 建立了创建镜像的规范。此过程耗时且复杂,但在持续交付环境中效果很好。该过程包括创建 **Dockerfile** 并包含镜像所需的命令。

用户构建一个文件,即 **dockerignore**,用于在 **Dockerfile** 开始后排除最终框架不需要的文件。文件,即 **Dockerignore**,位于根目录。Docker 的 build 命令用于创建 Docker 镜像,设置镜像名称和标签。Docker images 命令用于查看创建的镜像。

交互式方法

用户使用现有的 Docker 镜像执行一个容器,并在保存镜像之前手动进行任何必要的环境修改。此方法是创建 Docker 镜像的最简单方法之一。第一步是打开任何终端会话并启动 Docker。

然后,应用 Docker 的 run 命令,即 **image_name:tag_name**。这会启动一个 shell 会话,以及通过镜像启动的容器。如果省略标签名称,Docker 将使用镜像的最新版本。镜像必须出现在结果中。

交互式方法的优点

这是创建 Docker 镜像最简单快捷的方法。它非常适合测试和排除故障确定的依赖项以及非常规的过程。

交互式方法的缺点

它具有复杂的生命周期管理,需要手动重新配置(易出错)许多实时交互式过程。使用不必要的层设计未优化镜像很容易。

Docker 镜像命令

根据 Docker,有一组主要的 Docker 镜像命令。这些命令分为许多子命令。其中一些命令列出并解释如下:

  • Docker image build: 使用 **Dockerfile** 构建镜像。
  • Docker image load: 使用 tar 存档或流加载镜像以接收或读取输入 **(STDIN)**。
  • Docker image inspect: 显示关于多个镜像的信息。
  • Docker image prune: 删除未使用的镜像。
  • Docker image push: 将仓库或镜像推送到注册表。
    Docker image pull: 从注册表拉取仓库或镜像。
  • Docker image save: 将多个镜像保存到 tar 存档(默认流式传输到 **STDOUT**)。
  • Docker image rm: 删除多个镜像。
  • Docker image tag: 创建一个指向 **SOURCE_IMAGE** 的 **TARGET_IMAGE** 标签。

Docker 的命令行界面提供了许多用于自定义许多 Docker 镜像的命令。下面列出并解释了一些 Docker 镜像命令的示例:

  • Docker images history: 显示镜像的历史,包括对其进行的修改及其层。
  • Docker tag: 创建一个像 **TARGET_IMAGE** 标签一样的标签,它允许所有用户对容器镜像进行分组和组织。
  • Docker update: 允许用户更新容器的配置。
  • Docker save: 允许用户将镜像保存到存档。
  • Docker search: 在 **Docker Hub** 中搜索用户所需的内容。
  • Docker compose: 用于处理环境的变量。
    对于在 Docker 中创建容器化环境中的应用程序,Docker 镜像是一个重要的工具和概念。

镜像层

构成 Docker 镜像的所有文件称为一个层。这些层构成了中间镜像的系列,在各个阶段一个接一个地创建,其中每个层都依赖于其正下方的层。我们层的层次结构是我们 Docker 镜像方便生命周期管理的关键。

父镜像

在大多数情况下,Docker 镜像的初始层称为父镜像。它是所有其他层在其下创建的基础,并为我们的容器环境提供了通用的构建块。我们可以在公共容器注册表 Docker Hub 上看到大量现成的应用程序镜像作为我们的父镜像。

此外,我们可以在少量第三方服务(如 **Google Container Registry**)上看到它们。我们也可以选择使用我们现有的一个镜像作为基础来创建新的镜像。一个普通的父镜像可能是 Linux 的精简发行版,或者提供预装的服务,如内容管理系统(CMS)或数据库管理系统(DBMS)。

基础镜像

简单来说,基础镜像可以被描述为一个空的初始层,它允许我们从头开始创建自己的 Docker 镜像。这些镜像为我们提供了对镜像内容的完全控制,但基本上是为更高级的 Docker 用户设计的。

容器注册表

容器注册表是存储目录的存储位置,称为仓库,我们可以在其中推送和拉取容器镜像。

下面列出并讨论了三种主要的注册表类型:

Docker Ubuntu Image
  • Docker Hub: 这是 Docker 的官方镜像资源,我们可以访问由软件供应商、Docker 用户社区和开源项目分发的 100,000 多个容器镜像。此外,我们可以使用该服务来托管和管理我们的私有镜像。
  • 自托管注册表: 这是许多组织推荐的注册表模型,这些组织主要出于低延迟要求、合规性问题或安全性考虑,偏好在自己的本地基础设施上托管容器镜像。我们需要使用注册表服务器来运行我们的自托管注册表。我们也可以选择设置我们自己的私有、虚拟和远程 Docker 注册表。
  • 第三方注册表服务: 这个注册表是完全托管的服务,为我们的容器镜像提供了一个中心访问点,使得我们能够存储、管理和保护它们,而无需运行本地注册表的运维烦恼。提供 Docker 镜像支持的第三方注册表服务实例,例如 **JFrog Container Registry**、Google Container Registry、Azure Container Registry、Amazon ECR 和 Red Hat Quay。

Dockerfile 方法

**Dockerfile** 方法是企业级和真实世界容器部署的首选方法。它是构建 Docker 镜像的一种更高效、更灵活、更系统的方法,是实现安全、可靠和紧凑容器环境的关键。

**Dockerfile** 方法简而言之是一个三步过程,我们在其中创建 Dockerfile 并包含组装镜像所需的命令。

下表展示了我们最常使用的 **Dockerfile** 语句。

命令目的
FROM此命令用于指定父镜像。
WORKDIR它用于设置后续在 **Dockerfile** 中命令的工作目录。
RUN它用于安装容器所需的任何包和应用程序。
COPY它用于将目录或文件从特定位置复制过去。
ADD它与 **COPY** 命令相同,但还可以解压压缩文件和处理远程 URL。
ENTRYPOINT当容器启动时,这将始终是运行的命令。如果未指定,默认值为 **/bin/sh/ -c**。
CMD所有参数都将传递给入口点命令。如果 **ENTRYPOINT** 命令未设置,**CMD** 将是容器执行的命令(默认为 **/bin/sh/-c**)。
EXPOSE它用于定义从哪个端口访问我们的容器应用程序。
LABEL它用于向任何镜像添加元数据。

Dockerfile 方法的优点

它提供了可重复、紧凑和干净的基于配方的镜像。它提供了方便的生命周期管理,并方便集成到持续交付 (CD) 和持续集成 (CI) 流程中。此外,此方法包含一个相当自文档化的步骤记录,用于组装镜像。

Dockerfile 方法的缺点

对于初学者来说更复杂。此外,从头开始创建镜像非常耗时。