教程:使用 MySQL 和 Docker Compose 创建多容器应用

本文介绍如何使用 MySQLDocker Compose创建多容器应用。 使用具有多个容器的应用可以将容器专用于专用任务,因此每个容器都可以专注于单个任务。 使用多容器应用有许多优点:

  • 使用单独的容器可以不同于数据库来管理 API 和前端资源。
  • 使用多个容器可以在隔离环境中管理和更新不同版本。
  • 本地数据库可以在用于生产中的数据库的容器和托管服务中维护。
  • 与使用进程管理器运行多个进程相比,多容器应用更高效,这增加了容器启动/关闭的复杂性。

在本教程中,你将:

  • 启动 MySQL
  • 使用 MySQL 运行多容器应用
  • 为应用创建 Docker Compose 文件
  • 使用 Docker Compose 运行应用程序堆栈

先决条件

  • 本文是教程系列的一部分。 这些过程建立在一个已建立的示例之上,该示例需要适用于 Linux 的 Docker Desktop 容器。

    建议的方法是完成第一个教程: 创建容器应用,包括满足先决条件,以及教程: 在应用中保存数据。 完成这些教程后,请继续阅读本文中所述的过程。

  • 本文中的示例使用 Docker Compose

    适用于 Windows 的 Docker Desktop 包括 Docker Compose。

    运行以下命令来验证 Docker 安装:

    docker-compose version
    

Visual Studio Code

本教程系列介绍了 Visual Studio Code(VS Code)的过程。 查看以下注意事项,了解如何在此环境中工作:

  • 使用左侧菜单在 容器资源管理器EXPLORER (文件和文件夹)视图之间切换:

    显示 Visual Studio Code 中的容器资源管理器和文件/文件夹资源管理器视图的屏幕截图。

  • 通过选择 终端>新终端,在 VS Code 中打开命令行窗口。 也可以使用 Ctrl+Shift+`(反引号)键盘快捷方式。

  • 除非另有指定,否则请在 Bash 窗口中运行命令。 标记为 Bash 的大多数命令在 Bash 窗口或 VS Code 命令行窗口中运行。

启动 MySQL 数据库管理系统

默认情况下,容器以隔离方式运行。 容器不知道同一台计算机上的其他进程或其他容器。

若要在容器之间启用通信,需要连接到同一网络。 同一网络上的多个容器可以相互共享数据和处理信息。

可通过两种方法将容器附加到网络。 可以在创建期间将容器附加到网络,或稍后将现有容器附加到网络。

在此示例中,你将创建网络并在启动时附加 MySQL 容器。

  1. 创建名为 todo-app的网络:

    docker network create todo-app
    
  2. 启动名为 todo-mysql-data 的 MySQL 容器,并将其附加到 todo-app 网络。 该命令为 MySQL 数据库 mysql创建网络别名 todos

    运行此命令时,输入 <your-password> 占位符的 MySQL 根密码。

    docker run -d --network todo-app --network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=<your-password> -e MYSQL_DATABASE=todos mysql:lts
    

    此命令还定义 MYSQL_ROOT_PASSWORDMYSQL_DATABASE 环境变量。 有关详细信息,请参阅 MySQL Docker 中心列表

    警告

    本教程演示了使用 MySQL 数据库进行身份验证的密码凭据,该数据库不是最安全的方法。 请参阅 MySQL 文档,了解更安全的身份验证方法。

  3. 获取容器 ID,以便在下一步中使用。

    docker ps
    
  4. 确认可以连接到 mysql 网络上的容器。

    运行命令时,输入 <mysql-container-id> 占位符的容器 ID。

    docker exec -it <mysql-container-id> mysql -p
    

    在提示符下,输入创建 todo-mysql-data 容器时提供的密码。

  5. 在 MySQL shell 中,列出数据库并验证是否看到 todos 数据库。

    SHOW DATABASES;
    

    应会看到以下输出:

    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | todos              |
    +--------------------+
    5 rows in set (0.00 sec)
    
  6. 若要结束连接并返回到命令行提示符,请输入 退出

使用 MySQL 运行应用

todo 应用支持设置某些环境变量来指定 MySQL 连接设置。 下表列出了支持的变量,以及本部分介绍的示例中使用的值。

变量名称 示例值 描述
MYSQL_HOST mysql MySQL 服务器的主机名。
MYSQL_USER root 用于连接的用户名。
MYSQL_PASSWORD <your-password> 用于连接的密码。 在此示例中,请将根密码替换为 <your-password> 占位符。
MYSQL_DATABASE todos 建立连接后要使用的数据库的名称。

警告

使用环境变量设置连接设置对于开发是可以接受的,但不建议在生产环境中运行应用程序。 有关详细信息,请参阅 为何不应将环境变量用于机密数据

更安全的机制是使用容器业务流程框架提供的机密支持。 在大多数情况下,这些机密作为文件装载在正在运行的容器中。

在以下示例中,启动应用并将应用容器连接到 MySQL 容器。

  1. 运行以下 docker 命令。 请注意该命令如何指定前面所述的环境变量。

    运行命令时,请记得输入 <your-password> 占位符的 MySQL 根密码。

    docker run -dp 3000:3000 -w /app -v ${PWD}:/app --network todo-app -e MYSQL_HOST=mysql -e MYSQL_USER=root -e MYSQL_PASSWORD=<your-password> -e MYSQL_DB=todos node:lts-alpine sh -c "yarn install && yarn run dev"
    
  2. 在 VS Code 编辑器中,打开容器资源管理器,右键单击应用容器,然后选择“ 查看日志”。

    还可以使用 docker logs 命令从命令行查看日志。

  3. 查看日志输出。 请注意指示应用已连接到 MySQL 数据库的行:Connected to mysql db at host mysql

    # Previous log messages omitted
    $ nodemon src/index.js
    [nodemon] 1.19.2
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching dir(s): *.*
    [nodemon] starting `node src/index.js`
    Connected to mysql db at host mysql
    Listening on port 3000
    
  4. 在 Internet 浏览器中,转到正在运行的应用程序:http://localhost:3000

  5. 在正在运行的应用程序中,将一些项添加到待办事项列表中。

  6. 连接到 mysql 网络上的 MySQL 容器数据库,以便检查数据库。

    运行命令时,输入 <mysql-container-id> 占位符的容器 ID。

    docker exec -ti <mysql-container-id> mysql -p todos
    

    在提示符下,输入创建 todo-mysql-data 容器时提供的密码。

  7. 在 MySQL shell 中,验证你添加的 todo_items 是否已写入 todos 数据库。

    use todos;
    select * from todo_items;
    

    应会看到类似于以下示例的输出:

    +--------------------------------------+--------------------+-----------+
    | id                                   | name               | completed |
    +--------------------------------------+--------------------+-----------+
    | c906ff08-60e6-44e6-8f49-ed56a0853e85 | Do amazing things! |         0 |
    | 2912a79e-8486-4bc3-a4c5-460793a575ab | Be awesome!        |         0 |
    +--------------------------------------+--------------------+-----------+
    

现在,你有一个应用程序,用于在单独的容器中运行的外部数据库中存储数据。 此过程演示如何使用网络在容器之间启用通信。

创建 Docker Compose 文件

Docker Compose 可帮助定义和共享多容器应用程序。 Docker Compose 文件可以指定所有必需的服务,以便可以使用单个命令启动或结束所有相关进程。 可以在项目存储库根目录的 Docker Compose 文件中定义应用程序堆栈,并在版本控制下维护配置。 此方法允许其他人在克隆存储库时为项目做出贡献。

在以下示例中,为多容器应用程序配置 Docker Compose 文件 todo

  1. todo 应用项目的根目录中,创建名为 docker-compose.yml的 Docker Compose 文件。

    注意

    默认情况下,YAML 架构版本设置为最新版本。 运行应用时,如果架构版本已过时,将收到警告消息。 若要查看当前架构版本和兼容性矩阵,请参阅 概述(撰写文件)

  2. docker-compose.yml 文件中,添加以下元素。 指定应用 name 并启动要作为应用程序的一部分运行的 services(或容器)列表。

    name: todo
    
    services:
    

    服务列表对于你的应用是唯一的。 示例包括 appwebdbproxy等。 在后面的步骤中扩展 services 元素的定义。

    提示

    缩进在 .yml 文件中非常重要。 如果在 VS Code 中编辑,Intellisense 会指示格式或语法中的任何错误。

  3. 返回到 services 文件中的 定义。 通过添加一个条目来扩展定义 app 服务元素,其中包括容器的映像。

    services:
      app:
        image: node:lts-alpine
    

    可以为服务选取任何名称。 该名称会自动成为网络别名,在定义 MySQL 服务时非常有用。

  4. 扩展 app 元素定义以指定要执行的 command

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
    
  5. 定义要用于 ports 服务的 app。 请注意,这些端口对应于用于使用 MySQL 运行应用的命令的 -p 3000:3000 参数。

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
    
  6. 标识 working_dir 服务的工作目录 app 以及映射的 volumes

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
    

    定义 Docker Compose 卷时可以使用基于当前目录的相对路径。

  7. 指定在为 environment 服务执行命令时要使用的 app 变量定义。

      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
        environment:
          MYSQL_HOST: mysql
          MYSQL_USER: root
          MYSQL_PASSWORD: <your-password>
          MYSQL_DB: todos
    

    务必输入 <your-password> 占位符中的 MySQL 根密码(root password)。

  8. mysql 服务定义后添加 MySQL 服务 app 的定义。 按所示指定元素名称和值并使用相同的缩进。

    services:
      app:
        ...
      mysql:
        image: mysql:lts
    

    mysql 服务定义对应于你之前用于启动 MySQL 的命令。 定义服务时,它会自动接收网络别名。

  9. 标识 volumes 服务的映射的 mysql

    services:
      app:
        ...
      mysql:
        image: mysql:lts
        volumes:
          - todo-mysql-data:/var/lib/mysql
    
  10. 指定在为 environment 服务执行命令时要使用的 mysql 变量定义。

    services:
      app:
        ...
      mysql:
        image: mysql:lts
        volumes:
          - todo-mysql-data:/var/lib/mysql
        environment: 
          MYSQL_ROOT_PASSWORD: <your-password>
          MYSQL_DATABASE: todos
    

    务必输入 <your-password> 占位符中的 MySQL 根密码(root password)。

  11. 定义整个应用的卷映射。 在 volumes: 部分后添加 services: 部分,并使用相同的缩进。

    services:
       ...
    
    volumes:
      todo-mysql-data:
    
  12. 确认已完成的 docker-compose.yml 文件如以下示例所示。 您应该能查看到 <your-password> 占位符的 MySQL 根密码。

    name: todo
    
    services:
      app:
        image: node:lts-alpine
        command: sh -c "yarn install && yarn run dev"
        ports:
          - 3000:3000
        working_dir: /app
        volumes:
          - ./:/app
        environment:
          MYSQL_HOST: mysql
          MYSQL_USER: root
          MYSQL_PASSWORD: <your-password>
          MYSQL_DB: todos
    
      mysql:
        image: mysql:lts
        volumes:
          - todo-mysql-data:/var/lib/mysql
        environment: 
          MYSQL_ROOT_PASSWORD: <your-password>
          MYSQL_DATABASE: todos
    
    volumes:
      todo-mysql-data:
    

使用 Docker Compose 运行应用程序堆栈

现在可以尝试运行 docker-compose.yml 文件。

  1. 停止应用程序和数据库的任何正在运行的实例。

    按照 VS Code 中的以下步骤操作:

    1. 打开 容器资源管理器 (容器工具扩展)。

    2. 对于每个正在运行的容器,右键单击该容器并选择 “删除”。

  2. 启动多容器应用和所有服务。

    按照 VS Code 中的以下步骤操作:

    1. 打开 EXPLORER(文件和文件夹)视图。

    2. 右键单击 docker-compose.yml 文件,然后选择“撰写启动”。

    应会看到类似于以下示例的输出:

    [+] Building 0.0s (0/0)
    [+] Running 2/2
    ✔ Container app-app-1    Started  0.9s 
    ✔ Container app-mysql-1  Running
    

    此操作为应用和网络创建映射卷。 默认情况下,Docker Compose 会专门为应用程序堆栈创建网络。

  3. 查看正在运行的容器的日志。

    按照 VS Code 中的以下步骤操作:

    1. 打开 容器资源管理器 (容器工具扩展)。

    2. 右键单击应用容器,然后选择“查看日志”

    应会看到类似于以下示例的输出:

    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
    

    日志显示服务名称和实例编号,例如每行开头 app_1。 此格式可帮助你按服务和实例区分消息。 每个服务的日志被整合到一个流中。 此方法使你能够监视与计时相关的问题。

  4. 现在可以在 Internet 浏览器中打开正在运行的应用程序:http://localhost:3000

停止 Docker Compose 并运行容器

完成应用和容器后,可以将其删除。

按照 VS Code 中的以下步骤操作:

  1. 打开 EXPLORER(文件和文件夹)视图。

  2. 右键单击 docker-compose.yml 文件,然后选择“撰写停止”。

此操作会停止所有正在运行的容器并删除网络。

默认情况下,不会移除 compose 文件中已命名的卷。 如果要删除这些卷,可以使用 docker-compose down --volumes 命令。

清理资源

如果将本教程系列中的 先决条件 组件应用到安装,则可以重复使用配置以供将来的 Docker 开发使用。 删除或卸载任何组件并不重要。