Docker Compose是一种工具,旨在帮助定义和共享多容器应用程序。使用 Compose,我们可以创建一个 YAML 文件来定义服务,并且可以使用单个命令来启动或拆除所有内容。

使用 Compose的一优势是您可以在文件中定义应用程序堆栈,将其保存在项目存储库的根目录下(现在受版本控制),并且可以轻松地让其他人为您的项目做出贡献。有人只需要克隆您的存储库并启动撰写应用程序。事实上,你现在可能会在 GitHub/GitLab 上看到很多项目就是这样做的。

那么,我们如何开始呢?

安装 Docker Compose 

如果您为 Windows 或 Mac 安装了 Docker 桌面/工具箱,那么您已经拥有 Docker Compose!Play-with-Docker 实例也已经安装了 Docker Compose。如果您使用的是 Linux 机器,则需要安装 Docker Compose。

安装后,您应该能够运行以下命令并查看版本信息。

<span style="color:#33444d"><span style="background-color:#ffffff"><span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code>docker-compose version
</code></span></span></span></span>

创建 Compose 文件

  1. 在应用项目的根目录下,创建一个名为docker-compose.yml.
  2. 在撰写文件中,我们将首先定义架构版本。在大多数情况下,最好使用最新的受支持版本。文件参考 以了解当前架构版本和兼容性矩阵。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>
</code></span></span>
  1. 接下来,我们将定义要作为应用程序的一部分运行的服务(或容器)列表。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
</code></span></span>

现在,我们将开始一次将服务迁移到撰写文件中。

定义应用服务

请记住,这是我们用来定义应用程序容器的命令。

<span style="color:#33444d"><span style="background-color:#ffffff"><span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code>docker run <span style="color:#8b008b">-dp</span> 3000:3000 <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-w</span> /app <span style="color:#8b008b">-v</span> <span style="color:#cd5555">"</span><span style="color:#8b008b">$(</span><span style="color:#658b00">pwd</span><span style="color:#8b008b">)</span><span style="color:#cd5555">:/app"</span> <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">--network</span> todo-app <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-e</span> <span style="color:#00688b">MYSQL_HOST</span>=mysql <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-e</span> <span style="color:#00688b">MYSQL_USER</span>=root <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-e</span> <span style="color:#00688b">MYSQL_PASSWORD</span>=secret <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-e</span> <span style="color:#00688b">MYSQL_DB</span>=todos <span style="color:#cd5555">\</span>
  node:12-alpine <span style="color:#cd5555">\</span>
  sh <span style="color:#8b008b">-c</span> <span style="color:#cd5555">"yarn install && yarn run dev"</span>
</code></span></span></span></span>

如果您使用的是 PowerShell,请使用此命令。

<span style="color:#33444d"><span style="background-color:#ffffff"><span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code>docker run -dp 3000:3000 <span style="color:#cd5555">`</span>
  -w /app -v <span style="color:#cd5555">"</span><span style="color:#8b008b">$(</span><span style="color:#658b00">pwd</span><span style="color:#8b008b">)</span><span style="color:#cd5555">:/app"</span> <span style="color:#cd5555">`</span>
  --network todo-app <span style="color:#cd5555">`</span>
  -e <span style="color:#00688b">MYSQL_HOST</span>=mysql <span style="color:#cd5555">`</span>
  -e <span style="color:#00688b">MYSQL_USER</span>=root <span style="color:#cd5555">`</span>
  -e <span style="color:#00688b">MYSQL_PASSWORD</span>=secret <span style="color:#cd5555">`</span>
  -e <span style="color:#00688b">MYSQL_DB</span>=todos <span style="color:#cd5555">`</span>
  node:12-alpine <span style="color:#cd5555">`</span>
  sh -c <span style="color:#cd5555">"yarn install && yarn run dev"</span>
</code></span></span></span></span>


  1. 首先,让我们为容器定义服务条目和图像。我们可以为服务选择任何名称。该名称将自动成为网络别名,这在定义我们的 MySQL 服务时会很有用。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">node:12-alpine</span>
</code></span></span>
  1. 通常,您会看到command接近image定义,尽管对订购没有要求。所以,让我们继续把它移到我们的文件中。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">node:12-alpine</span>
     <span style="color:#658b00">command</span>: <span style="color:#cd5555">sh -c "yarn install && yarn run dev"</span>
</code></span></span>
  1. 让我们-p 3000:3000通过ports为服务定义来迁移命令的一部分。我们将在这里使用 短语法,但也有更详细的 长语法可用。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">node:12-alpine</span>
     <span style="color:#658b00">command</span>: <span style="color:#cd5555">sh -c "yarn install && yarn run dev"</span>
     <span style="color:#658b00">ports</span>:
       - <span style="color:#cd5555">3000:3000</span>
</code></span></span>
  1. 接下来,我们将使用和定义迁移工作目录 ( -w /app) 和卷映射 ( -v "$(pwd):/app") 。Volumes 也有短句和长句。working_dirvolumesDocker Compose 卷定义的优点之一是我们可以使用当前目录的相对路径。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">node:12-alpine</span>
     <span style="color:#658b00">command</span>: <span style="color:#cd5555">sh -c "yarn install && yarn run dev"</span>
     <span style="color:#658b00">ports</span>:
       - <span style="color:#cd5555">3000:3000</span>
     <span style="color:#658b00">working_dir</span>: <span style="color:#cd5555">/app</span>
     <span style="color:#658b00">volumes</span>:
       - <span style="color:#cd5555">./:/app</span>
</code></span></span>
  1. 最后,我们需要使用environment密钥迁移环境变量定义。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">node:12-alpine</span>
     <span style="color:#658b00">command</span>: <span style="color:#cd5555">sh -c "yarn install && yarn run dev"</span>
     <span style="color:#658b00">ports</span>:
       - <span style="color:#cd5555">3000:3000</span>
     <span style="color:#658b00">working_dir</span>: <span style="color:#cd5555">/app</span>
     <span style="color:#658b00">volumes</span>:
       - <span style="color:#cd5555">./:/app</span>
     <span style="color:#658b00">environment</span>:
       <span style="color:#658b00">MYSQL_HOST</span>: <span style="color:#cd5555">mysql</span>
       <span style="color:#658b00">MYSQL_USER</span>: <span style="color:#cd5555">root</span>
       <span style="color:#658b00">MYSQL_PASSWORD</span>: <span style="color:#cd5555">secret</span>
       <span style="color:#658b00">MYSQL_DB</span>: <span style="color:#cd5555">todos</span>
</code></span></span>

定义 MySQL 服务

现在,是时候定义 MySQL 服务了。我们用于该容器的命令如下:

<span style="color:#33444d"><span style="background-color:#ffffff"><span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code>docker run <span style="color:#8b008b">-d</span> <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">--network</span> todo-app <span style="color:#8b008b">--network-alias</span> mysql <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-v</span> todo-mysql-data:/var/lib/mysql <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-e</span> <span style="color:#00688b">MYSQL_ROOT_PASSWORD</span>=secret <span style="color:#cd5555">\</span>
  <span style="color:#8b008b">-e</span> <span style="color:#00688b">MYSQL_DATABASE</span>=todos <span style="color:#cd5555">\</span>
  mysql:5.7
</code></span></span></span></span>

如果您使用的是 PowerShell,请使用此命令。

<span style="color:#33444d"><span style="background-color:#ffffff"><span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code>docker run -d <span style="color:#cd5555">`</span>
  --network todo-app --network-alias mysql <span style="color:#cd5555">`</span>
  -v todo-mysql-data:/var/lib/mysql <span style="color:#cd5555">`</span>
  -e <span style="color:#00688b">MYSQL_ROOT_PASSWORD</span>=secret <span style="color:#cd5555">`</span>
  -e <span style="color:#00688b">MYSQL_DATABASE</span>=todos <span style="color:#cd5555">`</span>
  mysql:5.7
</code></span></span></span></span>


  1. 我们将首先定义新服务并为其命名,mysql以便它自动获取网络别名。我们将继续并指定要使用的图像。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#228b22"># The app service definition</span>
   <span style="color:#658b00">mysql</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">mysql:5.7</span>
</code></span></span>
  1. 接下来,我们将定义卷映射。当我们使用 运行容器时docker run,会自动创建命名卷。但是,使用 Compose 运行时不会发生这种情况。我们需要在顶级volumes:部分定义卷 ,然后在服务配置中指定挂载点。通过仅提供卷名,使用默认选项。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#228b22"># The app service definition</span>
   <span style="color:#658b00">mysql</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">mysql:5.7</span>
     <span style="color:#658b00">volumes</span>:
       - <span style="color:#cd5555">todo-mysql-data:/var/lib/mysql</span>

 <span style="color:#658b00">volumes</span>:
   <span style="color:#658b00">todo-mysql-data</span>:
</code></span></span>
  1. 最后,我们只需要指定环境变量。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> <span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

 <span style="color:#658b00">services</span>:
   <span style="color:#658b00">app</span>:
     <span style="color:#228b22"># The app service definition</span>
   <span style="color:#658b00">mysql</span>:
     <span style="color:#658b00">image</span>: <span style="color:#cd5555">mysql:5.7</span>
     <span style="color:#658b00">volumes</span>:
       - <span style="color:#cd5555">todo-mysql-data:/var/lib/mysql</span>
     <span style="color:#658b00">environment</span>:
       <span style="color:#658b00">MYSQL_ROOT_PASSWORD</span>: <span style="color:#cd5555">secret</span>
       <span style="color:#658b00">MYSQL_DATABASE</span>: <span style="color:#cd5555">todos</span>

 <span style="color:#658b00">volumes</span>:
   <span style="color:#658b00">todo-mysql-data</span>:
</code></span></span>

此时,我们的完整docker-compose.yml应该是这样的:

<span style="color:#33444d"><span style="background-color:#ffffff"><span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code><span style="color:#658b00">version</span>: <span style="color:#cd5555">"</span><span style="color:#cd5555">3.7"</span>

<span style="color:#658b00">services</span>:
  <span style="color:#658b00">app</span>:
    <span style="color:#658b00">image</span>: <span style="color:#cd5555">node:12-alpine</span>
    <span style="color:#658b00">command</span>: <span style="color:#cd5555">sh -c "yarn install && yarn run dev"</span>
    <span style="color:#658b00">ports</span>:
      - <span style="color:#cd5555">3000:3000</span>
    <span style="color:#658b00">working_dir</span>: <span style="color:#cd5555">/app</span>
    <span style="color:#658b00">volumes</span>:
      - <span style="color:#cd5555">./:/app</span>
    <span style="color:#658b00">environment</span>:
      <span style="color:#658b00">MYSQL_HOST</span>: <span style="color:#cd5555">mysql</span>
      <span style="color:#658b00">MYSQL_USER</span>: <span style="color:#cd5555">root</span>
      <span style="color:#658b00">MYSQL_PASSWORD</span>: <span style="color:#cd5555">secret</span>
      <span style="color:#658b00">MYSQL_DB</span>: <span style="color:#cd5555">todos</span>

  <span style="color:#658b00">mysql</span>:
    <span style="color:#658b00">image</span>: <span style="color:#cd5555">mysql:5.7</span>
    <span style="color:#658b00">volumes</span>:
      - <span style="color:#cd5555">todo-mysql-data:/var/lib/mysql</span>
    <span style="color:#658b00">environment</span>:
      <span style="color:#658b00">MYSQL_ROOT_PASSWORD</span>: <span style="color:#cd5555">secret</span>
      <span style="color:#658b00">MYSQL_DATABASE</span>: <span style="color:#cd5555">todos</span>

<span style="color:#658b00">volumes</span>:
  <span style="color:#658b00">todo-mysql-data</span>:
</code></span></span></span></span>

运行应用程序栈

现在我们有了我们的docker-compose.yml文件,我们可以启动它了!

  1. 确保没有其他 app/db 副本首先运行(docker psdocker rm -f <ids>)。
  2. 使用docker-compose up命令启动应用程序堆栈。我们将添加-d标志以在后台运行所有内容。
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> docker-compose up <span style="color:#8b008b">-d</span>
</code></span></span>

当我们运行它时,我们应该看到这样的输出:

<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> Creating network "app_default" with the default driver
 Creating volume "app_todo-mysql-data" with default driver
 Creating app_app_1   ... done
 Creating app_mysql_1 ... done
</code></span></span>

您会注意到创建了卷以及网络!默认情况下,Docker Compose 会自动为应用程序堆栈创建一个网络(这就是我们没有在 compose 文件中定义网络的原因)。

  1. 让我们使用docker-compose logs -f命令查看日志。您将看到来自每个服务的日志交错到一个流中。当您想观察与时序相关的问题时,这非常有用。该-f标志“跟随”的日志,因为它产生这样会给你现场输出。
    如果您已经运行了该命令,您将看到如下所示的输出:
<span style="color:#0c5176 !important"><span style="background-color:#f5f8fa !important"><code> mysql_1  | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections.
 mysql_1  | Version: '5.7.27'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
 app_1    | Connected to mysql db at host mysql
 app_1    | Listening on port 3000
</code></span></span>

服务名称显示在行首(通常是彩色的)以帮助区分消息。如果要查看特定服务的日志,可以在logs 命令的末尾添加服务名称(例如, docker-compose logs -f app)。

提示:在启动应用程序之前等待数据库

当应用程序启动时,它实际上会等待 MySQL 启动并准备好,然后再尝试连接到它。Docker 没有任何内置支持在启动另一个容器之前等待另一个容器完全启动、运行和准备就绪。对于基于 Node 的项目,您可以使用等待端口 依赖项。其他语言/框架也存在类似的项目。

  1. 此时,您应该能够打开您的应用程序并看到它正在运行。嘿!我们只需要一个命令!

在 Docker Dashboard 中查看应用程序堆栈

如果我们查看 Docker 仪表板,我们会看到有一个名为app的组。这是来自 Docker Compose 的“项目名称”,用于将容器组合在一起。默认情况下,项目名称只是所在目录的名称 docker-compose.yml

docker cp 模糊匹配 docker compose image_f5

如果您向下旋转应用程序,您将看到我们在撰写文件中定义的两个容器。这些名称也更具描述性,因为它们遵循<project-name>_<service-name>_<replica-number>. 因此,很容易快速查看哪个容器是我们的应用程序,哪个容器是 mysql 数据库。

docker cp 模糊匹配 docker compose image_docker cp 模糊匹配_02

全部撕下来

当您准备将其全部拆除时,只需docker-compose down在 Docker 仪表板上运行或点击整个应用程序的垃圾桶即可。容器将停止,网络将被移除。

警告

删除卷

默认情况下,运行docker-compose down. 如果要删除卷,则需要添加--volumes标志。

泊坞窗仪表盘并没有在删除应用程序堆栈中删除卷。

拆除后,您可以切换到另一个项目,运行docker-compose up并准备好为该项目做出贡献!真的没有比这更简单的了!

回顾

在本节中,我们了解了 Docker Compose 以及它如何帮助我们显着简化多服务应用程序的定义和共享。我们通过将我们正在使用的命令转换为适当的撰写格式来创建一个撰写文件。

在这一点上,我们开始结束本教程。但是,我们想要介绍一些有关镜像构建的最佳实践,因为我们一直在使用的 Dockerfile 存在一个大问题。那么,让我们来看看吧!