docker基础:多容器应用通信

翻译自docker官网
原文:Multi container apps | Docker Docs
注:命令为参照官网的本地运行结果

多容器应用

到目前为止,你一直在处理单容器应用。但是,现在你将添加 MySQL 到应用程序栈中。经常会出现以下问题 - “MySQL 将在哪里运行?将它安装在同一个容器中还是单独运行?”一般而言,每个容器应该做一件事,并做好一件事。以下是几个单独运行容器的理由:

  • 你很有可能需要不同于数据库的方式来扩展 API 和前端。
  • 单独的容器让你可以独立地版本控制和更新版本。
  • 虽然你可能在本地使用容器作为数据库,但你可能希望在生产中使用托管服务。那样你就不想将数据库引擎与你的应用一起发布了。
  • 运行多个进程将需要进程管理器(容器只启动一个进程),这增加了容器启动/关闭的复杂性。

并且还有更多理由。因此,如下图所示,最好是在多个容器中运行你的应用。

docker基础:多容器应用通信_第1张图片

容器网络

记住,默认情况下容器是独立运行的,不知道同一台机器上的其他进程或容器。那么,你如何允许一个容器与另一个容器通信呢?答案是网络。如果你将两个容器放在同一个网络上,它们就可以彼此通信。

启动 MySQL

将容器放在网络上有两种方法:

  • 在启动容器时指定网络。
  • 将已经运行的容器连接到一个网络。

按照以下步骤,你将首先创建网络,然后在启动时附加 MySQL 容器。

1. 创建网络

% 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": {}

    }

]

2. 启动一个 MySQL 容器并将其附加到网络。

你还将定义一些数据库用来初始化数据库的环境变量。要了解更多关于 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 识别出你想使用一个命名卷,并自动为你创建一个。

3.连接数据库

为了确认你的数据库已经启动并运行,请连接到数据库并验证是否已经连接。

当密码提示出现时,输入 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

既然你知道 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 的主机,它就会与数据库通信。

使用 MySQL 运行你的应用

todo 应用支持设置一些环境变量来指定 MySQL 连接设置。它们是:

  • MYSQL_HOST - 运行 MySQL 服务器的主机名
  • MYSQL_USER - 用于连接的用户名
  • MYSQL_PASSWORD - 用于连接的密码
  • MYSQL_DB - 连接后使用的数据库

注意
虽然在开发中使用 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 ),你应该会看到一个类似于以下的消息,表明它正在使用 mysql 数据库。

% 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. 打开你的浏览器中的应用,并添加一些事项到你的待办事项列表中。

docker基础:多容器应用通信_第2张图片 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 进行服务发现的知识。
 

你可能感兴趣的:(容器技术,docker)