多容器应用
原文:https://docs.docker.com/get-started/07_multi_container/
到目前为止,您一直在处理单容器应用。但现在,您将添加 MySQL 到应用堆栈中。经常出现的问题是:“MySQL 将在哪里运行?将其安装在同一个容器中还是单独运行?”一般来说,每个容器应该做一件事并且做好。以下是几个单独运行容器的理由:
- 你很可能需要以不同于数据库的方式扩展 API 和前端。
- 分开的容器让你可以独立地版本控制和更新版本。
- 虽然您可能在本地使用数据库的容器,但在生产中您可能想使用托管服务。那时你就不想将数据库引擎与你的应用程序一起发布了。
- 运行多个进程将需要进程管理器(容器只启动一个进程),这增加了容器启动/关闭的复杂性。
还有更多原因。因此,如下图所示,最好在多个容器中运行您的应用。
容器网络
请记住,默认情况下容器在隔离状态下运行,不了解同一台机器上的其他进程或容器。那么,您如何允许一个容器与另一个容器通信呢?答案是网络。如果你将两个容器放在同一个网络上,它们就可以相互通信。
启动 MySQL
将容器放在网络上有两种方法:
- 在启动容器时指定网络。
- 将已经在运行的容器连接到网络。
在以下步骤中,您将首先创建网络,然后在启动时将 MySQL 容器附加到网络。
创建网络。
consoledocker network create todo-app
启动 MySQL 容器并将其连接到网络。您还将定义一些环境变量,数据库将使用这些环境变量初始化数据库。要了解有关 MySQL 环境变量的更多信息,请参阅 MySQL Docker Hub 页面中的“环境变量”部分。
consoledocker 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 识别到您想使用一个命名卷,并为您自动创建了一个。为了确认数据库已经启动并运行,请连接到数据库并验证它是否连接成功。
consoledocker exec -it <mysql-container-id> mysql -u root -p
当密码提示出现时,输入
secret
。在 MySQL shell 中,列出数据库并验证您看到todos
数据库。consolemysql> SHOW DATABASES;
您应该看到类似以下的输出:
plaintext+--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | todos | +--------------------+ 5 rows in set (0.00 sec)
退出 MySQL shell 返回到您的机器的 shell。
consolemysql> exit
现在您有了一个
todos
数据库,它已准备好供您使用。
连接到 MySQL
现在您知道 MySQL 已经启动并运行,您可以使用它。但是,您应该如何使用它?如果您在同一网络上运行另一个容器,如何找到该容器?请记住,每个容器都有自己的 IP 地址。
为了回答上述问题并更好地理解容器网络,您将使用 nicolaka/netshoot 容器,该容器附带了许多用于故障排除或调试网络问题的工具。
使用 nicolaka/netshoot 镜像启动一个新容器。确保将其连接到同一网络。
consoledocker run -it --network todo-app nicolaka/netshoot
在容器内部,您将使用
dig
命令,这是一个有用的 DNS 工具。您将查找主机名mysql
的 IP 地址。consoledig mysql
您应该得到类似以下的输出。
text; <<>> 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
在“ANSWER SECTION”中,您将看到
mysql
的A
记录解析为172.23.0.2
(您的 IP 地址可能有不同的值)。虽然mysql
通常不是一个有效的主机名, 但 Docker 能够将其解析为具有该网络别名的容器的 IP 地址。请记住,您之前使用了--network-alias
。这意味着您的应用只需要简单地连接到名为
mysql
的主机,它就会与 数据库通信。
使用 MySQL 运行您的应用
待办事项应用支持设置一些环境变量来指定 MySQL 连接设置。它们是:
MYSQL_HOST
- 运行 MySQL 服务器的主机名MYSQL_USER
- 用于连接的用户名MYSQL_PASSWORD
- 用于连接的密码MYSQL_DB
- 连接后使用的数据库
注意
虽然在开发中使用环境变量设置连接设置通常被接受,
但在生产中运行应用程序时,这种做法是极力不推荐的。Docker 的前安全主管 Diogo Monica 写了一篇精彩的博客文章,解释了为什么。
一个更安全的机制是使用您的容器编排框架提供的秘密支持。在大多数情况下, 这些秘密被挂载为运行容器中的文件。您会看到许多应用(包括 MySQL 镜像和待办事项应用) 也支持带有
_FILE
后缀的环境变量,以指向包含变量的文件。例如,设置
MYSQL_PASSWORD_FILE
变量将导致应用使用引用文件的内容 作为连接密码。Docker 不做任何事情来支持这些环境变量。您的应用需要知道查找 变量并获取文件内容。
现在您可以启动开发就绪的容器了。
指定前面的每个环境变量,并将容器连接到您的应用网络。确保在运行此命令时您位于
getting-started-app
目录中。consoledocker 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"
如果您查看容器的日志(
docker logs -f <container-id>
),您应该会看到一个类似于以下的消息,表明它正在使用 mysql 数据库。consolenodemon 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
在浏览器中打开应用并在您的待办列表中添加一些项目。
连接到 mysql 数据库并证明项目正在写入数据库。记住,密码是
secret
。consoledocker exec -it <mysql-container-id> mysql -p todos
并在 mysql shell 中运行以下命令:
consolemysql> 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,您可以以更简单的方式分享您的应用程序堆栈,并让其他人通过一个简单的命令快速启动它们。