多容器应用
到目前为止,您一直在使用单个容器应用程序。但是,现在您将 MySQL 添加到 应用程序堆栈。经常出现以下问题 - “MySQL 将在哪里运行?将其安装在相同的 容器还是单独运行它?一般来说,每个容器都应该做一件事并把它做好。以下是单独运行容器的几个原因:
- 您很有可能必须以不同于数据库的方式扩展 API 和前端。
- 通过单独的容器,您可以单独对版本进行版本控制和更新。
- 虽然您可以在本地使用数据库的容器,但您可能希望使用托管服务 对于生产中的数据库。那时,您不想将数据库引擎与应用程序一起提供。
- 运行多个进程将需要一个进程管理器(容器只启动一个进程),这增加了容器启动/关闭的复杂性。
还有更多原因。因此,如下图所示,最好在多个容器中运行您的应用程序。

容器联网
请记住,默认情况下,容器是隔离运行的,并且对其他进程一无所知 或同一台计算机上的容器。那么,如何允许一个容器与另一个容器通信呢?答案是 联网。如果您将两个容器放在同一个网络上,它们可以相互通信。
启动 MySQL
有两种方法可以将容器放在网络上:
- 在启动容器时分配网络。
- 将已在运行的容器连接到网络。
在以下步骤中,您将首先创建网络,然后在启动时附加 MySQL 容器。
创建网络。
$ docker network create todo-app
启动 MySQL 容器并将其连接到网络。您还将定义一些环境变量,这些变量的 database 将用于初始化数据库。要了解有关 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 识别出您想要使用命名卷,并自动为您创建一个。要确认数据库已启动并运行,请连接到数据库并验证它是否已连接。
$ 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)
退出 MySQL shell 以返回到计算机上的 shell。
mysql> exit
您现在有一个
todos
数据库,它已准备好供您使用。
连接到 MySQL
现在,您知道 MySQL 已启动并正在运行,您可以使用它。但是,你如何使用它呢?如果您运行 同一网络上的另一个容器,如何找到该容器?请记住,每个容器都有自己的 IP 地址。
为了回答上述问题并更好地了解容器网络,您将使用 nicolaka/netshoot 容器 它附带了许多工具,这些工具可用于排查或调试网络问题。
使用 nicolaka/netshoot 镜像启动新容器。确保将其连接到同一网络。
$ docker run -it --network todo-app nicolaka/netshoot
在容器内部,您将使用
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
在 “ANSWER SECTION” 中,您将看到一个
A
的记录mysql
解析为172.23.0.2
(您的 IP 地址很可能具有不同的值)。而mysql
通常不是有效的主机名,则 Docker 能够将其解析为具有该网络别名的容器的 IP 地址。请记住,您使用了--network-alias
早些时候。这意味着,您的应用只需连接到名为
mysql
它将与 数据库。
使用 MySQL 运行应用
todo 应用程序支持设置一些环境变量来指定 MySQL 连接设置。他们是:
MYSQL_HOST
- 正在运行的 MySQL 服务器的主机名MYSQL_USER
- 用于连接的用户名MYSQL_PASSWORD
- 用于连接的密码MYSQL_DB
- 连接后要使用的数据库
注意
虽然使用 env vars 设置连接设置在开发中通常被接受,但强烈建议不要这样做 在生产环境中运行应用程序时。Docker 的前安全主管 Diogo Monica 写了一篇精彩的博客文章来解释原因。
更安全的机制是使用容器编排框架提供的密钥支持。在大多数情况下, 这些密钥作为文件挂载到正在运行的容器中。您将看到许多应用程序(包括 MySQL 镜像和 todo 应用程序) 还支持带有
_FILE
suffix 指向包含该变量的文件。例如,将
MYSQL_PASSWORD_FILE
var 将导致应用程序使用引用文件的内容 作为连接密码。Docker 不执行任何作来支持这些环境变量。您的应用需要知道要查找 变量并获取文件内容。
您现在可以启动开发就绪型容器。
指定前面的每个环境变量,并将容器连接到您的应用程序网络。确保您位于
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"
如果查看容器 (
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
在浏览器中打开应用程序,并将一些项目添加到您的待办事项列表中。
连接到 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,您可以在 更简单的方法,让其他人使用一个简单的命令来启动它们。