Docker Compose 是一款旨在帮助定义和共享多容器应用程序的工具。通过 Compose,我们可以创建一个 YAML 文件来定义需要使用的所有服务,并且只需要一个命令就可以启动或停止所有服务。
使用 Compose 的最大优点是你只需在一个文件中定义自己的应用程序栈(即应用程序需要用到的所有服务),然后把这个 YAML 文件放在项目的根目录下,与源码一起受版本控制。其他人只需 clone 你的项目源码之后就可以快速启动服务。实际上,在 GitHub 或 GitLab 上已经有很多项目正在这样做。
我们也来为 todo 应用创建一个 YAML 文件吧。
安装 Docker Compose
如果你使用的是 Windows 或者 Mac 桌面操作系统,在安装 Docker Desktop 之后就已经内置了 Docker Compose。如果你使用的是 Linux 系统,可以参照 此处的说明 安装 Docker Compose
安装完成之后,可以执行以下命令查看它的版本信息:
docker-compose version
创建我们的 Compose 文件
- 在
todo-app项目的根目录下,创建一个名为docker-compose.yml的文件 在
docker-compose.yml文件的第一行定义 schema version。在大多数情况下,最好使用最新的受支持 schema version。你可以查看 Compose file reference 以获得最新的 schema version 和兼容性列表。version: "3.7"
接下来,我们将定义
todo-app应用程序依赖的一系列服务(或容器)列表。version: "3.7"services:
接着,我们开始将之前通过命令行执行的命令,翻译成 compose 文件支持的格式。
定义
todo-app应用服务回顾一下之前使用过的命令:
docker run -dp 3000:3000 \-w /app \-v "$(pwd):/app" \--network todo-app \-e MYSQL_HOST=mysql \-e MYSQL_USER=root \-e MYSQL_PASSWORD=secret \-e MYSQL_DB=todos \node:12-alpine \sh -c "yarn install && yarn run dev"
如果使用的是 PowerShell,之前使用的是下面这条命令(只是
多行输入的分隔符不一样而已)docker run -dp 3000:3000 `-w /app `-v "$(pwd):/app" `--network todo-app `-e MYSQL_HOST=mysql `-e MYSQL_USER=root `-e MYSQL_PASSWORD=secret `-e MYSQL_DB=todos `node:12-alpine `sh -c "yarn install && yarn run dev"
首先,定义
todo-app应用服务名称和使用的镜像,可以为它取任何名称,这里简单取成同名todo-app。该名称将自动作为网络的别名,在后续定义 MySQL 服务时将很有用。version: "3.7"services:todo-app:image: node:12-alpine
接着我们把容器启动之后要执行的命令写在靠近定义
image的地方,尽管不一定按照这样的顺序书写,但是通常都这样做。类似下面这样:version: "3.7"services:todo-app:image: node:12-alpinecommand: sh -c "yarn install && yarn run dev"
接着定义端口映射
version: "3.7"services:todo-app:image: node:12-alpinecommand: sh -c "yarn install && yarn run dev"ports:- 3000:3000
再来将
-w /app工作目录 和-v "$(pwd):/app"volume 通过working_dir和volumes这两个属性来定义。
在 Docker Compose 配置文件中定义 volume 的一个优点是我们可以使用基于docker-compose.yml文件所在目录的相对路径。version: "3.7"services:todo-app:image: node:12-alpinecommand: sh -c "yarn install && yarn run dev"ports:- 3000:3000working_dir: /appvolumes:- ./:/app
最后,通过
environment定义todo-app需要使用到的环境变量。version: "3.7"services:todo-app:image: node:12-alpinecommand: sh -c "yarn install && yarn run dev"ports:- 3000:3000working_dir: /appvolumes:- ./:/appenvironment:MYSQL_HOST: mysqlMYSQL_USER: rootMYSQL_PASSWORD: secretMYSQL_DB: todos
定义 MySQL 服务
现在,是时候定义 MySQL 服务了。同样先回顾之前启动 MySQL 容器时使用的命令:
docker run -d \--network todo-app --network-alias mysql \-v todo-mysql-data:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=secret \-e MYSQL_DATABASE=todos \mysql:5.7
如果使用的是 PowerShell,之前使用的是下面这条命令(只是
多行输入的分隔符不一样而已)docker run -d `--network todo-app --network-alias mysql `-v todo-mysql-data:/var/lib/mysql `-e MYSQL_ROOT_PASSWORD=secret `-e MYSQL_DATABASE=todos `mysql:5.7
先定义一个新服务并将它命名为
mysql,接着指定该服务使用的镜像。version: "3.7"services:todo-app:# The app service definitionmysql:image: mysql:5.7
接着定义
named volume的映射关系。当我们使用docker run运行容器时,Docker 会自动创named volume。但是,使用 Compose 运行时不会自动创建,所以我们需要在配置文件的顶层使用volumes属性定义named volume,然后在 MySQL 服务下的volumes指定它的实际挂载点。备注:这两个
volumes出现的位置不一样。第一个是在 compose 文件的顶层,另外一个是在 MySQL 这个服务之下。
version: "3.7"services:todo-app:# The app service definitionmysql:image: mysql:5.7volumes:- todo-mysql-data:/var/lib/mysqlvolumes:todo-mysql-data:
最后,指定启动 MySQL 服务需要的环境变量
version: "3.7"services:todo-app:# The app service definitionmysql:image: mysql:5.7volumes:- todo-mysql-data:/var/lib/mysqlenvironment:MYSQL_ROOT_PASSWORD: secretMYSQL_DATABASE: todosvolumes:todo-mysql-data:
此时,完整的
docker-compose.yml看起来像这样:version: "3.7"services:todo-app:image: node:12-alpinecommand: sh -c "yarn install && yarn run dev"ports:- 3000:3000working_dir: /appvolumes:- ./:/appenvironment:MYSQL_HOST: mysqlMYSQL_USER: rootMYSQL_PASSWORD: secretMYSQL_DB: todosmysql:image: mysql:5.7volumes:- todo-mysql-data:/var/lib/mysqlenvironment:MYSQL_ROOT_PASSWORD: secretMYSQL_DATABASE: todosvolumes:todo-mysql-data:
启动我们的完整应用
现在我们已经有了
docker-compose.yml文件,就可以启动它了!确保之前通过命令行启动的应用和 MySQL 容器已经停止并删除了。如何还运行着,可以通过 Docker Desktop 或者使用 docker ps 配合 docker rm -f 删除它们。
使用
docker-compose up命令启动应用程序栈(todo-app+mysql)。添加-d标志可以让它们保持在后台运行。docker-compose up -d
运行此命令之后,应看到如下输出:
Creating network "app_default" with the default driverCreating volume "app_todo-mysql-data" with default driverCreating app_todo-app_1 ... doneCreating app_mysql_1 ... done
你应该已经注意到了,
volume和network都已经已创建成功。默认情况下,Docker Compose 会自动为应用程序栈自动创建一个网络,这就是为什么我们没有在 compose 文件中显式定义网络的原因。- 让我们使用
docker-compose logs -f命令查看日志。每个服务的日志汇总统一输出在这里。-f标志用于实时输出日志。
如果要查看特定服务的日志,可以将服务名称添加到 logs 命令的末尾(例如docker-compose logs -f mysql)。 - 至此,只用了一个命令就可以启动我们应用程序需要的所有服务了。
在 Docker Dashboard 中查看我们的应用程序栈
如果现在查看 Docker Dashboard,将会看到有一个名为app的组,将所有使用到的容器组在一起了。默认情况下,项目名称是docker-compose.yml文件所在目录的名称。
如果点击app这个分组,将会看到我们在docker-compose.yml文件中定义的两个容器。名称也更具描述性,因为它们遵循< 项目名称 >_< 服务名称 >_< 副本编号 >的格式。因此,可以很方便的查看哪个容器是我们的todo服务以及哪个容器是 MySQL 数据库服务。
删除所有容器
如果要将它们全部删除,只需运行docker-compose down或在 Docker Dashboard 上点击垃圾桶图标即可。同时也会删除自动创建的网络。
删除 Volumes
默认情况下,运行docker-compose down命令,不会自动删除docker-compose.yml文件中定义的named volumes。如果要删除 volumes,只需添加--volumes标志即可。回顾
在本节中,我们学习了如何利用 Docker Compose 帮助我们极大简化多服务应用程序的定义和分享。我们把之前使用的命令转换为对应的 compose 格式,写入新创建的docker-compose.yml文件中。然后,就可以只使用一条命令启动或者删除所有服务了。
下一节让我们更进一步,介绍一些构建镜像的最佳实践。原始资料:Using Docker Compose
