多容器应用程序
解释
启动单容器应用程序很容易。例如,一个执行特定数据处理任务的 Python 脚本,可以在一个容器内运行,并包含其所有依赖项。同样,一个为静态网站提供服务的 Node.js 应用程序,带有一个小型 API 端点,也可以有效地将其所有必要的库和依赖项容器化。然而,随着应用程序规模的增长,将它们作为单个容器进行管理变得更加困难。
想象一下,数据处理 Python 脚本需要连接到数据库。突然之间,你不仅要管理脚本,还要在同一个容器内管理数据库服务器。如果该脚本需要用户登录,你就需要一个身份验证机制,这会进一步增加容器的大小。
容器的一个最佳实践是,每个容器应该做好一件事,并且做得很好。虽然这条规则也有例外,但应避免让一个容器做多件事情的倾向。
现在你可能会问:“我需要分开运行这些容器吗?如果我分开运行它们,我该如何将它们连接在一起?”
虽然 `docker run` 是一个方便启动容器的工具,但用它来管理不断增长的应用程序堆栈会变得困难。原因如下:
- 想象一下,为开发、测试和生产环境运行几个 `docker run` 命令(前端、后端和数据库),并带有不同的配置。这容易出错且耗时。
- 应用程序通常相互依赖。随着堆栈的扩展,手动按特定顺序启动容器和管理网络连接变得困难。
- 每个应用程序都需要自己的 `docker run` 命令,这使得扩展单个服务变得困难。扩展整个应用程序意味着可能会在不需要提升的组件上浪费资源。
- 为每个应用程序持久化数据需要在每个 `docker run` 命令中进行单独的卷挂载或配置。这造成了一种分散的数据管理方法。
- 通过单独的 `docker run` 命令为每个应用程序设置环境变量既繁琐又容易出错。
这时 Docker Compose 就派上用场了。
Docker Compose 在一个名为 `compose.yml` 的 YAML 文件中定义了整个多容器应用程序。该文件指定了所有容器的配置、它们的依赖关系、环境变量,甚至卷和网络。使用 Docker Compose:
- 你不需要运行多个 `docker run` 命令。你只需要在一个 YAML 文件中定义整个多容器应用程序。这集中了配置并简化了管理。
- 你可以按特定顺序运行容器,并轻松管理网络连接。
- 你可以在多容器设置中简单地扩展或缩减单个服务。这允许根据实时需求进行高效分配。
- 你可以轻松实现持久卷。
- 在 Docker Compose 文件中一次性设置环境变量非常简单。
通过利用 Docker Compose 运行多容器设置,你可以构建具有模块化、可扩展性和一致性的复杂应用程序。
试一试
在这个实践指南中,你将首先看到如何使用 `docker run` 命令构建和运行一个基于 Node.js、Nginx 反向代理和 Redis 数据库的计数器 Web 应用程序。你还将看到如何使用 Docker Compose 简化整个部署过程。
设置
获取示例应用程序。如果你有 Git,可以克隆示例应用程序的仓库。否则,你可以下载示例应用程序。选择以下选项之一。
在终端中使用以下命令克隆示例应用程序仓库。
$ git clone https://github.com/dockersamples/nginx-node-redis进入 `nginx-node-redis` 目录
$ cd nginx-node-redis在这个目录中,你会发现两个子目录 - `nginx` 和 `web`。
下载源代码并解压。
进入 `nginx-node-redis-main` 目录
$ cd nginx-node-redis-main在这个目录中,你会发现两个子目录 - `nginx` 和 `web`。
下载并安装 Docker Desktop。
构建镜像
进入 `nginx` 目录,运行以下命令来构建镜像:
$ docker build -t nginx .进入 `web` 目录并运行以下命令来构建第一个 Web 镜像:
$ docker build -t web .
运行容器
在运行多容器应用程序之前,你需要为它们创建一个网络以便它们之间进行通信。你可以使用 `docker network create` 命令来完成:
$ docker network create sample-app通过运行以下命令启动 Redis 容器,这会将其附加到先前创建的网络并创建一个网络别名(对 DNS 查找很有用):
$ docker run -d --name redis --network sample-app --network-alias redis redis通过运行以下命令启动第一个 Web 容器:
$ docker run -d --name web1 -h web1 --network sample-app --network-alias web1 web通过运行以下命令启动第二个 Web 容器:
$ docker run -d --name web2 -h web2 --network sample-app --network-alias web2 web通过运行以下命令启动 Nginx 容器:
$ docker run -d --name nginx --network sample-app -p 80:80 nginx注意Nginx 通常用作 Web 应用程序的反向代理,将流量路由到后端服务器。在这种情况下,它将流量路由到 Node.js 后端容器(web1 或 web2)。
通过运行以下命令验证容器是否已启动:
$ docker ps你将看到类似以下的输出:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2cf7c484c144 nginx "/docker-entrypoint.…" 9 seconds ago Up 8 seconds 0.0.0.0:80->80/tcp nginx 7a070c9ffeaa web "docker-entrypoint.s…" 19 seconds ago Up 18 seconds web2 6dc6d4e60aaf web "docker-entrypoint.s…" 34 seconds ago Up 33 seconds web1 008e0ecf4f36 redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp redis如果你查看 Docker Desktop 仪表盘,可以看到这些容器并深入了解它们的配置。

一切正常运行后,你可以在浏览器中打开 https:// 来查看网站。多次刷新页面,可以看到处理请求的主机以及请求总数。
web2: Number of visits is: 9 web1: Number of visits is: 10 web2: Number of visits is: 11 web1: Number of visits is: 12注意你可能已经注意到,作为反向代理的 Nginx 可能会以轮询的方式在两个后端容器之间分配传入的请求。这意味着每个请求可能会以轮流的方式被导向到不同的容器(web1 和 web2)。输出显示 web1 和 web2 容器的连续增量,而存储在 Redis 中的实际计数器值仅在响应发送回客户端后才会更新。
你可以使用 Docker Desktop 仪表盘,通过选择容器并点击 删除 按钮来移除容器。

使用 Docker Compose 简化部署
Docker Compose 为管理多容器部署提供了一种结构化和简化的方法。如前所述,使用 Docker Compose,你不需要运行多个 `docker run` 命令。你只需要在一个名为 `compose.yml` 的 YAML 文件中定义整个多容器应用程序。让我们看看它是如何工作的。
导航到项目目录的根目录。在这个目录中,你会找到一个名为 `compose.yml` 的文件。这个 YAML 文件是所有魔法发生的地方。它定义了构成你应用程序的所有服务及其配置。每个服务都指定了其镜像、端口、卷、网络以及其功能所需的任何其他设置。
使用 `docker compose up` 命令启动应用程序:
$ docker compose up -d --build当你运行此命令时,你应该会看到类似以下的输出:
Running 5/5 ✔ Network nginx-nodejs-redis_default Created 0.0s ✔ Container nginx-nodejs-redis-web1-1 Started 0.1s ✔ Container nginx-nodejs-redis-redis-1 Started 0.1s ✔ Container nginx-nodejs-redis-web2-1 Started 0.1s ✔ Container nginx-nodejs-redis-nginx-1 Started如果你查看 Docker Desktop 仪表盘,可以看到这些容器并深入了解它们的配置。

或者,你可以使用 Docker Desktop 仪表盘,通过选择应用程序堆栈并点击 删除 按钮来移除容器。

在本指南中,你学习了与容易出错且难以管理的 `docker run` 相比,使用 Docker Compose 启动和停止多容器应用程序是多么简单。