多容器应用程序
解释
启动单个容器应用程序很容易。例如,执行特定数据处理任务的 Python 脚本可以在包含所有依赖项的容器内运行。类似地,使用小型 API 端点提供静态网站的 Node.js 应用程序可以使用其所有必要库和依赖项进行有效地容器化。但是,随着应用程序规模的增长,将它们作为单个容器进行管理变得越来越困难。
想象一下,数据处理 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 Dashboard,你可以看到容器,并深入了解它们的配置。
在一切启动并运行之后,你可以在浏览器中打开 https://127.0.0.1,查看网站。刷新页面几次,查看处理请求的主机和请求的总数
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 Dashboard 通过选择容器并选择删除按钮来删除容器。
使用 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 Dashboard,你可以看到容器,并深入了解它们的配置。
或者,你可以使用 Docker Dashboard 通过选择应用程序堆栈并选择删除按钮来删除容器。
在本指南中,你了解了与 docker run
相比,使用 Docker Compose 启动和停止多容器应用程序是多么容易,而 docker run
容易出错且难以管理。