Docker多容器应用程序
到目前为止,您已经在使用单个容器应用程序。但是,现在您将在应用程序堆栈中添加MySQL。经常会出现以下问题-“MySQL将在哪里运行?在同一个容器中安装还是分开运行?”一般来说,每个容器应该只做一件事并且做好。以下是运行容器分开的一些原因:
- 在扩展API和前端与数据库时,可能需要进行不同的扩展。
- 独立的容器允许您以隔离的方式进行版本管理和更新版本。
- 虽然您可能在本地使用容器进行数据库,但在生产中可能希望使用托管服务进行数据库。您不希望将数据库引擎与应用程序一起发布。
- 运行多个进程将需要一个进程管理器(容器只启动一个进程),这增加了容器启动/关闭的复杂性。
容器网络
请记住,默认情况下,容器独立运行,不知道同一台机器上的其他进程或容器。那么,如何让一个容器与另一个容器进行通信呢?答案是网络。如果您将两个容器放置在同一个网络上,它们可以相互通信。
启动MySQL
有两种方法可以将容器放入网络中:
在启动容器时分配网络。 将已经运行的容器连接到网络。 在接下来的步骤中,您将首先创建网络,然后在启动时将MySQL容器附加到该网络。
- 创建网络。
docker network create todo-app
- 启动一个MySQL容器并将其附加到网络上。您还将定义一些环境变量,数据库将使用这些变量来初始化数据库。
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工具。您将查找主机名mysql的IP地址。
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”中,您将看到一个名为mysql的A记录,其解析为172.23.0.2(您的IP地址可能具有不同的值)。虽然mysql通常不是有效的主机名,但Docker能够将其解析为具有该网络别名的容器的IP地址。记住,您之前使用了–network-alias标志。
这意味着您的应用程序只需要连接到名为mysql的主机,它就能与数据库通信。
使用MySQL运行您的应用程序
todo应用程序支持设置一些环境变量来指定MySQL连接设置。它们是:
- MYSQL_HOST - 运行MySQL服务器的主机名
- MYSQL_USER - 用于连接的用户名
- MYSQL_PASSWORD - 用于连接的密码
- MYSQL_DB - 连接后要使用的数据库
注意
尽管在开发中接受使用环境变量设置连接设置,但在生产中运行应用程序时,这是不推荐的。
一个更安全的机制是使用容器编排框架提供的密钥支持。在大多数情况下,这些密钥作为文件挂载到正在运行的容器中。您会发现许多应用程序(包括MySQL镜像和todo应用程序)还支持具有_FILE后缀的环境变量,用于指向包含变量的文件。
例如,设置MYSQL_PASSWORD_FILE变量将导致应用程序使用所引用文件的内容作为连接密码。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"
- 如果查看容器的日志(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 | +--------------------------------------+--------------------+-----------+
您的表格将会有所不同,因为它包含您的项目。但是,您应该能够在那里看到它们被存储。