多容器应用

预计阅读时间:9分钟

到目前为止,我们一直在使用单个容器应用程序。但是,我们现在想将MySQL添加到应用程序堆栈中。通常会出现以下问题-“ MySQL将在哪里运行?将它安装在同一个容器中还是单独运行?” 通常,每个容器都应该做一件事情并且做好事。原因如下:

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

还有更多原因。因此,我们将更新我们的应用程序使其工作如下:

Todo App已连接到MySQL容器

容器网络

请记住,默认情况下,容器是独立运行的,并且对同一台计算机上的其他进程或容器一无所知。那么,我们如何允许一个容器与另一个容器对话?答案是 网络。现在,您不必成为网络工程师(万岁!)。只要记住这个规则...

笔记

如果两个容器在同一网络上,则它们可以相互通信。如果不是,他们就不会。

启动MySQL

有两种将容器放置在网络上的方法:1)在开始时分配它,或2)连接现有的容器。现在,我们将首先创建网络,并在启动时附加MySQL容器。

  1. 创建网络。

     docker network create todo-app
    
  2. 启动一个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: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
    

    您还将看到我们指定了--network-alias标志。我们将在稍后再讲到这一点。

    小费

    您会注意到我们使用的是todo-mysql-data这里命名的卷,并将其挂载到/var/lib/mysqlMySQL存储数据的位置。但是,我们从未运行过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)
    

    万岁!我们有我们的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.14.1 <<>> 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 -连接后要使用的数据库

通过Env Vars设置连接设置

虽然通常可以使用env vars设置连接设置来进行开发,但是 在生产环境中运行应用程序时,强烈建议不要使用它。Docker的前安全主管Diogo Monica 写了一篇很棒的博客文章, 解释了为什么。

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

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

在解释了所有这些内容之后,让我们开始开发就绪容器!

  1. 我们将指定上面的每个环境变量,并将容器连接到我们的应用程序网络。

     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"
    
  2. 如果我们查看容器(docker logs <container-id>)的日志,则应该看到一条消息,表明它正在使用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
    
  3. 在浏览器中打开应用程序,然后向待办事项列表中添加一些项目。

  4. 连接到mysql数据库并证明已将项目写入数据库。记住,密码是秘密的

     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 |
     +--------------------------------------+--------------------+-----------+
    

    显然,您的表看起来会有所不同,因为它包含您的项目。但是,您应该看到它们存储在这里!

如果快速浏览Docker Dashboard,您会看到我们有两个正在运行的应用程序容器。但是,没有真正的迹象表明它们在单个应用程序中组合在一起。我们很快就会看到如何使它变得更好!

Docker Dashboard显示了两个未分组的应用程序容器

回顾

至此,我们有了一个应用程序,该应用程序现在将其数据存储在运行在单独容器中的外部数据库中。我们了解了一些有关容器网络的知识,并了解了如何使用DNS执行服务发现。

但是,很有可能您会对启动该应用程序所需做的一切感到有点不知所措。我们必须创建一个网络,启动容器,指定所有环境变量,公开端口等等!这要记住很多,这肯定会使事情很难传递给其他人。

在下一节中,我们将讨论Docker Compose。借助Docker Compose,我们可以以更简单的方式共享我们的应用程序堆栈,并允许其他人使用一个(简单的)命令将它们旋转起来!

入门设置方向快速启动简介概念容器码头