翻译自docker官网
原文:Multi container apps | Docker Docs
注:命令为参照官网的本地运行结果
到目前为止,你一直在处理单容器应用。但是,现在你将添加 MySQL 到应用程序栈中。经常会出现以下问题 - “MySQL 将在哪里运行?将它安装在同一个容器中还是单独运行?”一般而言,每个容器应该做一件事,并做好一件事。以下是几个单独运行容器的理由:
并且还有更多理由。因此,如下图所示,最好是在多个容器中运行你的应用。
记住,默认情况下容器是独立运行的,不知道同一台机器上的其他进程或容器。那么,你如何允许一个容器与另一个容器通信呢?答案是网络。如果你将两个容器放在同一个网络上,它们就可以彼此通信。
将容器放在网络上有两种方法:
按照以下步骤,你将首先创建网络,然后在启动时附加 MySQL 容器。
% docker network create todo-app
9a887b3fc2e168b96f442fb8f8f14804fb2873a6637559019d2c5dc1cdf17220
检查网络详细信息:
% docker network inspect todo-app
[
{
"Name": "todo-app",
"Id": "9a887b3fc2e168b96f442fb8f8f14804fb2873a6637559019d2c5dc1cdf17220",
"Created": "2024-02-07T12:38:08.253104375Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.19.0.0/16",
"Gateway": "172.19.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
你还将定义一些数据库用来初始化数据库的环境变量。要了解更多关于 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
a73a993397e40d782c4a01bfa086e7d9f75a210574e00c193afb2538d53e91d3
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a73a993397e4 mysql:8.0 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp, 33060/tcp jolly_gauss
在上一个命令中,你可以看到 --network-alias 标志。在后面的部分,你将了解更多关于这个标志的信息。
提示:
你会注意到,在上面的命令中有一个名为 todo-mysql-data 的卷,它挂载在 /var/lib/mysql,这是 MySQL 存储其数据的地方。然而,你从未运行过 docker volume create 命令。Docker 识别出你想使用一个命名卷,并自动为你创建一个。
为了确认你的数据库已经启动并运行,请连接到数据库并验证是否已经连接。
当密码提示出现时,输入 secret。在 MySQL shell 中,列出数据库并验证你看到 todos 数据库。当你应该看到类似下面这样的输出后,退出 MySQL shell 以返回到你的机器上的 shell。
% docker exec -it a73a993397e4 mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.35 MySQL Community Server - GPL
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.03 sec)
mysql> exit
Bye
既然你知道 MySQL 已经在运行,你可以使用它了。但是,你如何使用它呢?如果你在同一个网络上运行另一个容器,你如何找到容器呢?记住,每个容器都有自己的 IP 地址。
为了回答上面的问题并更好地理解容器网络,你将使用 nicolaka/netshoot 容器,
这个容器附带了许多对于故障排除或调试网络问题非常有用的工具。
使用 nicolaka/netshoot 镜像启动一个新容器。确保将它连接到相同的网络。
在容器内部,你将使用 dig 命令,这是一个有用的 DNS 工具。你将查找主机名 mysql 的 IP 地址。
% docker run -it --network todo-app nicolaka/netshoot
Unable to find image 'nicolaka/netshoot:latest' locally
latest: Pulling from nicolaka/netshoot
08409d417260: Pull complete
......
404981eb2565: Pull complete
Digest: sha256:a7c92e1a2fb9287576a16e107166fee7f9925e15d2c1a683dbb1f4370ba9bfe8
Status: Downloaded newer image for nicolaka/netshoot:latest
dP dP dP
88 88 88
88d888b. .d8888b. d8888P .d8888b. 88d888b. .d8888b. .d8888b. d8888P
88' `88 88ooood8 88 Y8ooooo. 88' `88 88' `88 88' `88 88
88 88 88. ... 88 88 88 88 88. .88 88. .88 88
dP dP `88888P' dP `88888P' dP dP `88888P' `88888P' dP
Welcome to Netshoot! (github.com/nicolaka/netshoot)
Version: 0.11
e0ee51a5a0e2 ~ dig mysql
; <<>> DiG 9.18.13 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41032
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mysql. IN A
;; ANSWER SECTION:
mysql. 600 IN A 172.19.0.2
;; Query time: 3 msec
;; SERVER: 127.0.0.11#53(127.0.0.11) (UDP)
;; WHEN: Wed Feb 07 12:47:59 UTC 2024
;; MSG SIZE rcvd: 44
e0ee51a5a0e2 ~ exit
在“ANSWER SECTION”中,你将看到一个为 mysql 解析的 A 记录,解析为 172.23.0.2
(你的 IP 地址很可能有一个不同的值)。虽然 mysql 通常不是一个有效的主机名,Docker 能够将其解析为具有该网络别名的容器的 IP 地址。记住,你之前使用了--network-alias。
这意味着你的应用只需简单地连接到一个名为 mysql 的主机,它就会与数据库通信。
todo 应用支持设置一些环境变量来指定 MySQL 连接设置。它们是:
注意
虽然在开发中使用 env vars 来设置连接设置通常被接受,但在生产中运行应用程序时,强烈不建议这样做。Diogo Monica,Docker 的前安全负责人,撰写了一篇精彩的博客文章解释了原因。
更安全的机制是使用你的容器编排框架提供的秘密支持。在大多数情况下,这些秘密被挂载为在运行容器中的文件。你会看到许多应用程序(包括 MySQL 镜像和 todo 应用)也支持带有 _FILE 后缀的 env vars,以指向包含变量的文件。
例如,设置 MYSQL_PASSWORD_FILE 变量将导致应用使用引用文件的内容作为连接密码。Docker 对这些 env vars 不做任何支持。你的应用需要知道查找变量并获取文件内容。
你现在可以启动你的开发就绪容器了。
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"
7f47c7d41c10a2e83d841fb199ff6d54557b76635ffd2298b4033b9e512dd323
2. 如果你查看容器的日志(docker logs -f
% docker logs -f 7f47c7d41c10
yarn install v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 142.21s.
yarn run v1.22.19
$ nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Waiting for mysql:3306.
Connected!
Connected to mysql db at host mysql
Listening on port 3000
3. 打开你的浏览器中的应用,并添加一些事项到你的待办事项列表中。
4. 连接到 mysql 数据库并证明事项确实被写入到数据库中。记住,密码是 secret。
% docker exec -it a73a993397e4 mysql -p todos
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.35 MySQL Community Server - GPL
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> select * from todo_items;
+--------------------------------------+--------------------+-----------+
| id | name | completed |
+--------------------------------------+--------------------+-----------+
| 33424c3d-58cc-4ebb-b042-dd4f51bb8ac9 | Do amazing things! | 0 |
| 1d9d9979-7c30-444a-b6ab-d1b2adcfa7c1 | Be awesome! | 0 |
+--------------------------------------+--------------------+-----------+
2 rows in set (0.00 sec)
mysql> exit
Bye
你的表将因为包含你的项目而看起来不同。但是,你应该看到它们存储在那里。
至此,你拥有了一个现在将其数据存储在一个外部数据库中且运行在一个单独容器中的应用程序。你了解了一点关于容器网络和使用 DNS 进行服务发现的知识。