多容器应用程序

到目前为止,您一直在使用单容器应用程序。但是,现在您将把 MySQL 添加到应用程序堆栈中。经常出现以下问题:“MySQL 将在哪里运行?安装在同一个容器中还是单独运行?”一般来说,每个容器应该做一件事,并且做好。以下是单独运行容器的几个原因:

  • 您很有可能必须以不同于数据库的方式扩展 API 和前端。
  • 单独的容器允许您隔离版本和更新版本。
  • 虽然您可以在本地使用数据库容器,但您可能希望在生产中使用数据库托管服务。那么您不想将数据库引擎与您的应用程序一起提供。
  • 运行多个进程将需要一个进程管理器(容器只启动一个进程),这增加了容器启动/关闭的复杂性。

还有更多的原因。因此,如下图所示,最好在多个容器中运行您的应用程序。

Todo App 连接到 MySQL 容器

容器网络

请记住,默认情况下,容器是独立运行的,并且不了解同一台计算机上的其他进程或容器。那么,如何允许一个容器与另一个容器通信呢?答案是网络。如果将两个容器放在同一网络上,它们就可以相互通信。

启动MySQL

将容器放到网络上有两种方法:

  • 启动容器时分配网络。
  • 将已运行的容器连接到网络。

在以下步骤中,您将首先创建网络,然后在启动时附加 MySQL 容器。

  1. 创建网络。

    $ docker network create todo-app
    
  2. 启动 MySQL 容器并将其连接到网络。您还将定义数据库将用于初始化数据库的一些环境变量。要了解有关 MySQL 环境变量的更多信息,请参阅MySQL Docker Hub 列表中的“环境变量”部分 。


    $ 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:8.0
    
    $ 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:8.0
    $ 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:8.0
    

    在上一个命令中,您可以看到该--network-alias标志。在后面的部分中,您将了解有关此标志的更多信息。

    提示

    您会注意到上面命令中命名的卷todo-mysql-data安装在/var/lib/mysql,这是 MySQL 存储其数据的位置。但是,您从未运行过docker volume create命令。 Docker 识别出您想要使用命名卷并自动为您创建一个。

  3. 要确认数据库已启动并正在运行,请连接到数据库并验证其是否已连接。

    $ docker exec -it <mysql-container-id> mysql -u root -p
    

    当出现密码提示时,输入secret。在 MySQL shell 中,列出数据库并验证您是否看到该todos数据库。

    mysql> SHOW DATABASES;
    

    您应该看到如下所示的输出:

    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | todos              |
    +--------------------+
    5 rows in set (0.00 sec)
  4. 退出 MySQL shell 以返回到您计算机上的 shell。

    mysql> exit
    

    现在您已经有了一个todos数据库并且可以使用了。

连接到 MySQL

现在您知道 MySQL 已启动并正在运行,您可以使用它了。但是,你如何使用它呢?如果在同一网络上运行另一个容器,如何找到该容器?请记住,每个容器都有自己的 IP 地址。

为了回答上述问题并更好地理解容器网络,您将使用 nicolaka/netshoot容器,它附带了许多可用于排除或调试网络问题的工具。

  1. 使用 nicolaka/netshoot 镜像启动一个新容器。确保将其连接到同一网络。

    $ docker run -it --network todo-app nicolaka/netshoot
    
  2. 在容器内,您将使用该dig命令,这是一个有用的 DNS 工具。您将查找主机名的 IP 地址mysql

    $ dig mysql
    

    您应该得到如下所示的输出。

    ; <<>> DiG 9.18.8 <<>> mysql
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32162
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;mysql.				IN	A
    
    ;; ANSWER SECTION:
    mysql.			600	IN	A	172.23.0.2
    
    ;; Query time: 0 msec
    ;; SERVER: 127.0.0.11#53(127.0.0.11)
    ;; WHEN: Tue Oct 01 23:47:24 UTC 2019
    ;; MSG SIZE  rcvd: 44

    在“答案部分”中,您将看到解析A为的记录 (您的 IP 地址很可能具有不同的值)。虽然通常不是有效的主机名,但 Docker 能够将其解析为具有该网络别名的容器的 IP 地址。请记住,您使用的是 较早的。mysql172.23.0.2mysql--network-alias

    这意味着您的应用程序只需要连接到名为 的主机mysql,它就会与数据库通信。

使用 MySQL 运行您的应用程序

todo 应用程序支持设置一些环境变量来指定 MySQL 连接设置。他们是:

  • MYSQL_HOST- 正在运行的 MySQL 服务器的主机名
  • MYSQL_USER- 用于连接的用户名
  • MYSQL_PASSWORD- 用于连接的密码
  • MYSQL_DB- 连接后使用的数据库

笔记

虽然开发中普遍接受使用环境变量来设置连接设置,但在生产环境中运行应用程序时,强烈建议不要这样做。 Docker 前安全主管 Diogo Monica 写了一篇精彩的博客文章 解释了原因。

更安全的机制是使用容器编排框架提供的秘密支持。在大多数情况下,这些机密作为文件安装在正在运行的容器中。您会看到许多应用程序(包括 MySQL 映像和 todo 应用程序)也支持环境变量,其_FILE后缀指向包含该变量的文件。

例如,设置MYSQL_PASSWORD_FILEvar 将导致应用程序使用引用文件的内容作为连接密码。 Docker 不做任何事情来支持这些环境变量。您的应用程序需要知道如何查找变量并获取文件内容。

您现在可以启动您的开发就绪容器。

  1. 指定前面的每个环境变量,并将容器连接到您的应用程序网络。getting-started-app运行此命令时请确保您位于该目录中。


    $ docker run -dp 127.0.0.1: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:18-alpine \
      sh -c "yarn install && yarn run dev"
    

    在 Windows 中,在 PowerShell 中运行此命令。

    $ docker run -dp 127.0.0.1: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:18-alpine `
      sh -c "yarn install && yarn run dev"

    在 Windows 中,在命令提示符中运行此命令。

    $ docker run -dp 127.0.0.1:3000:3000 ^
      -w /app -v "%cd%:/app" ^
      --network todo-app ^
      -e MYSQL_HOST=mysql ^
      -e MYSQL_USER=root ^
      -e MYSQL_PASSWORD=secret ^
      -e MYSQL_DB=todos ^
      node:18-alpine ^
      sh -c "yarn install && yarn run dev"
    
    $ docker run -dp 127.0.0.1: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:18-alpine \
      sh -c "yarn install && yarn run dev"
    

  2. 如果您查看容器 ( ) 的日志docker logs -f <container-id>,您应该会看到类似于以下内容的消息,这表明它正在使用 mysql 数据库。

    $ nodemon src/index.js
    [nodemon] 2.0.20
    [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
    
  3. 在浏览器中打开应用程序,然后将一些项目添加到您的待办事项列表中。

  4. 连接到 mysql 数据库并证明项目正在写入数据库。请记住,密码是secret

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

    在 mysql shell 中,运行以下命令:

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

    您的桌子看起来会有所不同,因为它有您的物品。但是,您应该看到它们存储在那里。

概括

此时,您拥有一个应用程序,该应用程序将其数据存储在在单独容器中运行的外部数据库中。您了解了一些有关使用 DNS 的容器网络和服务发现的知识。

相关信息:

下一步

您很可能开始对启动此应用程序所需执行的所有操作感到有点不知所措。您必须创建网络、启动容器、指定所有环境变量、公开端口等等。需要记住的东西太多,而且肯定会让事情更难传递给其他人。

在下一节中,您将了解 Docker Compose。借助 Docker Compose,您可以以更轻松的方式共享应用程序堆栈,并让其他人通过一个简单的命令启动它们。