学习 Docker - 从零开始,第四部分 docker-compose 基础

2025-06-04

学习 Docker - 从零开始,第四部分 docker-compose 基础

在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris

本文是系列文章的一部分:

  • Docker - 从第一部分开始,涵盖:为什么选择 Docker,它是如何工作的,以及镜像、容器和 Dockerfile 用法等基本概念。此外,它还介绍了一些用于管理上述概念的基本 Docker 命令。
  • Docker - 从第二部分开始,我们将学习有关卷的知识,了解它们是什么,它们如何为您工作,以及它们如何创建一个令人惊叹的开发环境
  • Docker - 从第三部分开始,本部分是关于如何在容器环境中使用数据库,为此我们需要了解链接和网络
  • Docker——从头开始,第四部分,我们在这里
  • Docker - 从头开始​​,第五部分,本部分是 Docker Compose 的第二部分,也是最后一部分,其中我们介绍了卷、环境变量以及如何使用数据库和网络

这部分内容是关于如何管理两个以上的 Docker 容器。当你需要管理的容器数量过多时,最终会感觉难以掌控。你只能不断地输入 docker run 直到某个点,一旦开始启动多个容器,你的头和手指就会感到酸痛。为了解决这个问题,我们推出了 Docker Compose。

简而言之:Docker Compose 是一个庞大的话题,因此本文分为两部分。第一部分,我们将阐述 Docker Compose 的原理以及它的亮点。第二部分,我们将探讨 Docker Compose 的更多高级主题,例如环境变量、卷和数据库。

在本部分中我们将介绍:

  • 为什么使用 docker compose,至少从高层次上理解,有两个主要架构:Monolith 和 Microservices,而 Docker Compose 确实有助于管理后者
  • 功能,我们将解释 Docker Compose 支持哪些功能,以便我们理解为什么它如此适合我们选择的微服务架构
  • 当 Docker 不够用时,我们将解释在什么时候使用 Docker 命令会变得乏味和痛苦,以及什么时候使用 Docker Compose 开始变得越来越有吸引力
  • 最后,我们将从头开始构建一个 docker-compose.yaml 文件,并学习如何使用 Docker Compose 和一些核心命令来管理我们的容器

资源

使用 Docker 和容器化就是将单体应用拆分成微服务。在本系列文章中,我们将学习掌握 Docker 及其所有命令。您迟早会想把容器部署到生产环境中。这个环境通常是云端。当您觉得自己拥有足够的 Docker 经验后,可以查看以下链接,了解如何在云端使用 Docker:

  • 云中的容器精彩的概述页面,展示了有关云中容器的其他信息
  • 在云中部署容器教程展示了如何轻松利用您现有的 Docker 技能并在云中运行您的服务
  • 创建容器注册表您的 Docker 镜像可以存储在 Docker Hub 中,也可以存储在云端的容器注册表中。将镜像存储在某个地方,然后只需几分钟就能从该注册表创建服务,岂不是很棒?

为什么使用 Docker Compose

Docker Compose 适用于需要独立管理多个服务的情况。我们所描述的正是所谓的微服务架构。

微服务架构

让我们定义这种架构的一些属性:

  • 松耦合,这意味着它们不依赖于其他服务运行,它们所需的所有数据都已存在。它们可以与其他服务交互,但需要通过调用外部 API,例如 HTTP 调用。
  • 独立部署,这意味着我们可以启动、停止和重建它们而不会直接影响其他服务。
  • 高度可维护和可测试,服务很小,因此需要理解的内容较少,并且由于没有依赖关系,测试变得更简单
  • 围绕业务能力进行组织,这意味着我们应该尝试寻找不同的主题,如预订、产品管理、计费等

我们或许应该先问自己一个问题:我们为什么需要这种架构?从上面列出的特性可以清楚地看出,它提供了很大的灵活性,几乎没有依赖关系等等。这些听起来都很棒,那么,这是否是所有应用都应该拥有的新架构呢?

一如既往,这取决于具体情况。有一些标准可以体现微服务相对于单体架构的优势,例如:

  • 不同的技术栈/新兴技术。我们有很多开发团队,他们都希望使用自己的技术栈,或者希望在不改变整个应用程序的情况下尝试新技术。让每个团队使用他们选择的技术构建自己的服务,作为微服务架构的一部分。
  • 复用,你确实希望一次性构建某个功能,例如计费功能,如果将其拆分成单独的服务,就能更容易地将其复用到其他应用程序中。此外,在微服务架构中,你可以轻松地组合不同的服务,并以此为基础创建许多应用程序。
  • 故障影响最小,当单体架构出现故障时,可能会导致整个应用程序崩溃,而使用微服务,您可以更好地保护自己免受故障的影响

关于为什么微服务优于单体架构,还有很多争论。感兴趣的读者可以查看以下链接 。

Docker Compose 案例

微服务架构的描述告诉我们,我们需要围绕业务功能组织一系列服务。此外,它们需要可独立部署,并且需要能够使用不同的技术栈等等。在我看来,Docker 通常非常适合。我们之所以选择 Docker Compose 而不是 Docker,仅仅是因为它的规模庞大。如果我们有两个以上的容器,需要输入的命令数量就会急剧增加。下一节我们将解释 Docker Compose 的哪些特性使其在服务数量增加时能够如此出色地扩展。

Docker Compose 功能概述

现在,Docker Compose 使我们能够很好地扩展,因为我们可以轻松地一次构建多个镜像、启动多个容器等等。完整的功能列表如下:

  • 管理整个应用程序生命周期。
  • 启动、停止和重建服务
  • 查看正在运行的服务的状态
  • 流式输出正在运行的服务的日志
  • 在服务上运行一次性命令

我们可以看到,当我们需要管理由许多服务组成的微服务架构时,它可以处理我们可能需要的一切。

当普通的 Docker 不再足够时

让我们回顾一下 Docker 的运行方式和我们需要的命令,并看看当我们添加一两个服务时它会带我们去哪里。

为了将某些东西docker化,我们知道我们需要:

  • 定义一个 Dockerfile,其中包含我们需要的操作系统映像、需要安装的库、需要设置的环境变量、需要打开的端口以及最后如何启动我们的服务
  • 构建镜像或从 Docker Hub 下载现有镜像
  • 创建并运行容器

现在,使用 Docker Compose,我们仍然需要使用 Dockerfile 来完成部分工作,但 Docker Compose 将负责构建镜像和管理容器。让我们用普通的 Docker 来演示一下这些命令:

docker build -t 某个镜像名称。

其次是

docker run -d -p 8000:3000 --name 某个容器名称 某个镜像名称

现在这并不是一个可怕的编写量,但想象一下您需要为三种不同的服务执行此操作,然后它突然变成六个命令,然后您需要拆除这又两个命令,这实际上无法扩展。

替代文本

输入docker-compose.yaml

这就是 Docker Compose 真正闪耀的地方。你无需为每个要构建的服务都输入两行命令,而是可以将项目中的所有服务定义在一个文件中,我们称之为docker-compose.yaml。你可以在文件中配置以下主题docker-compose.yaml

  • Build,我们可以指定构建上下文和 Dockerfile 的名称,不应该叫标准名称吗
  • 环境,我们可以根据需要定义和赋值任意数量的环境变量
  • 图像,我们可以定义想要从 Docker Hub 下载并用于解决方案的现成图像,而不是从头开始构建图像
  • 网络,我们可以创建网络,还可以为每个服务指定它应该属于哪个网络(如果有的话)
  • 端口,我们还可以定义端口转发,即哪个外部端口应该与容器中的哪个内部端口匹配
  • Volumes,当然我们也可以定义volumes

Docker Compose 实际操作

好的,现在我们明白了 Docker Compose 可以处理我们在命令行上可以做的几乎所有事情,并且它还依赖于文件docker-compose.yaml来知道要执行什么操作。

编写 docker-compose.yml 文件

让我们实际尝试创建这样一个文件,并给出一些说明。首先,我们快速回顾一下典型的项目文件结构。下面是一个包含两个服务的项目,每个服务都有自己的目录。每个目录都有一个 目录,Dockerfile其中包含有关如何构建服务的说明。

它看起来像这样:

docker-compose.yaml
/product-service
  app.js
  package.json
  Dockerfile
/inventory-service
  app.js
  package.json
  Dockerfile
Enter fullscreen mode Exit fullscreen mode

上面值得注意的是我们如何docker-compose.yaml在项目根目录下创建文件。这样做的原因是,我们要构建的所有服务以及如何构建和启动它们都应该在一个文件中定义,即我们的docker-compose.yml
好的,让我们打开docker-compose.yaml并输入第一行:

// docker-compose.yaml
version: '3'
Enter fullscreen mode Exit fullscreen mode

现在,你在这里指定的内容实际上很重要。目前,Docker 支持三个不同的主要版本。3 是最新的主要版本,点击此处了解更多不同版本之间的区别,因为它们确实支持不同的功能,并且它们之间的语法甚至可能有所不同 Docker 版本官方文档
接下来,让我们定义我们的服务:

// docker-compose.yaml
version: '3'
services:
  product-service:
    build:
      context: ./product-service
    ports:
      - "8000:3000"
Enter fullscreen mode Exit fullscreen mode

好的,一下子说了这么多,让我们分解一下:

  • services:,整个 docker-compose.yaml 文件中应该只有一个。另外,请注意我们以 结尾 :,我们需要它,否则它将不再是有效的语法,这通常适用于任何命令。
  • 产品服务,这是我们自己为我们的服务选择的名称
  • build:,指示 Docker Compose 如何构建镜像。如果我们已经有一个现成的镜像,则无需指定此参数。
  • context:,这需要告诉 Docker Compose 我们的位置Dockerfile,在这种情况下,我们说它需要下一级到product-service目录
  • ports:,这是端口转发,我们首先指定外部端口,然后指定内部端口

这一切对应着以下两个命令:

docker build -t [default name]/product-service .
docker run -p 8000:3000 --name [default name]/product-service
Enter fullscreen mode Exit fullscreen mode

嗯,几乎可以肯定,我们还没有明确告诉 Docker Compose 去构建镜像,或者创建并运行容器。让我们先从如何构建镜像开始学习如何操作:

docker-compose构建

上述命令将构建你在 中指定的每个服务docker-compose.yaml。让我们看看命令的输出:

替代文本

上面我们可以看到我们的镜像正在构建,并且它被赋予了全名compose-experiments_product-service:latest,如最后一行所示。全名来源于我们所在的目录,compose-experiments另一部分是我们在docker-compose.yaml文件中为服务指定的名称。
好了,接下来我们输入以下内容:

docker-compose up

这将再次读取我们的docker-compose.yaml文件,但这次它将创建并运行一个容器。我们还需要确保容器在后台运行,因此我们添加了标志-d,因此完整命令现在是:

docker-compose up -d

好的,上面我们可以看到我们的服务正在创建。让我们运行一下docker ps,验证一下新创建的容器的状态:
它似乎已经在端口 上启动并运行了8000。让我们来验证一下:
好的,现在我们转到终端,可以看到我们创建了一个容器。我们知道可以使用 docker stop 或 docker kill 来关闭它,但让我们用 docker-compose 的方式来做:

docker-compose down

正如我们在上面的日志中看到的,它正在停止并删除容器,它似乎正在为我们做这两件事,很甜蜜:)docker stop [id]应该 说,如果我们想要做的就是停止容器,我们可以这样做:docker rm [id]

docker-compose 停止

我不知道你是怎么想的,但就目前而言,我已经准备停止使用、和docker build。Docker docker runCompose似乎可以处理整个生命周期 :)docker stopdocker rm

Docker Compose 炫耀

让我们简单回顾一下到目前为止的内容。Docker Compose 负责我们管理服务的完整生命周期。让我们列出最常用的 Docker 命令,以及 Docker Compose 中相应的命令:

  • docker build变成docker-compose build,Docker Compose 版本能够构建指定的所有服务,docker-compose.yaml但我们也可以指定它来构建单个服务,因此如果我们想要的话,我们可以有更精细的控制
  • docker build + docker run变成docker-compose up,这会同时做很多事情,如果你的图像之前没有构建过,它会构建它们,并且还会从图像中创建容器
  • docker stop变成docker-compose stop,这又是一个 Docker Compose 中的命令,可以用来停止所有容器,或者如果我们给它一个容器作为参数,则可以停止特定的容器
  • docker stop && docker rm变成docker-compose down,这将首先停止容器,然后删除它们,以便我们可以重新开始

上述内容本身已经非常棒了,但更棒的是,我们可以轻松地继续扩展解决方案并添加越来越多的服务。

构建我们的解决方案

让我们添加另一项服务,看看它有多简单以及它的扩展性如何。我们需要执行以下操作:

  • 在我们docker-compose.yaml
  • 建立我们的形象docker-compose build
  • 跑步 docker-compose up

让我们看一下我们的docker-compose.yaml文件并为下一个服务添加必要的信息:

// docker-compose.yaml

version: '3'
services:
  product-service:
    build:
      context: ./product-service
    ports:
      - "8000:3000"
  inventory-service:
    build:
      context: ./inventory-service
    ports:
        - "8001:3000"
Enter fullscreen mode Exit fullscreen mode

好的,让我们启动并运行这些容器,包括我们的新服务:

docker-compose up

等等,你不是应该运行吗docker-compose build ?嗯,实际上我们不需要docker-compose up它帮我们做所有事情,构建镜像、创建和运行容器。

替代文本

注意:这种方法并不简单,对于首次构建并运行且之前没有镜像的人来说,效果并不好。但是,如果您要对服务进行更改,并且需要重新构建,则意味着您需要先运行 docker-compose build,然后再运行 docker-compose up。

概括

到这里,我们需要结束对 Docker Compose 的前半部分介绍,否则篇幅就太大了。我们已经讲解了 Docker Compose 背后的动机,并对微服务架构进行了轻量级的讲解。此外,我们还讨论了 Docker 与 Docker Compose 的区别,最后,我们将 Docker Compose 命令与普通的 Docker 命令进行了对比。
希望通过这种方式,我们能够展示使用 Docker Compose 并在一个文件中指定所有服务是多么容易docker-compose.yaml
我们之前提到过 Docker Compose 还有很多其他功能,例如环境变量、网络和数据库,但这些将在下一部分中介绍。

文章来源:https://dev.to/azure/docker-from-the-beginning-partiv-mi6
PREV
关于无服务器的五件事
NEXT
使用 .NET Core 3.1 开发 Azure Functions