利用network命令搭建多容器应用

未匹配的标注

到目前为止,我们已经学会了如何基于单容器应用进行开发工作。但是,我们现在想要把 MySQL 添加到应用栈中。我们会问:MySQL在哪里运行?是把MySQL和应用安装在同一个容器中,还是分开运行2个容器?总的来说:每个容器应该只做一件事,而且要把这件事做好。有以下几个原因:

1、你很有可能不得不将API和前端不同于数据库地规模化

2、分离容器让你能够版本独立,且独立地更新版本

3、尽管你本地使用数据库的话,会使用容器,但是生产环境中,可能想要将托管服务用于数据库。这样你就不会想要把数据库引擎和你的应用一起发布上线了。

4、容器只能启动一个进程,运行多个进程就会需要一个进程管理器,这会增加容器启停的复杂性。

当然还有其它原因。综上所述,我们接下来就把应用做如下更新:

容器网络

记住一点:容器默认是独立运行的,对同一台机器上运行的其它进程和容器都一无所知。所以,我们怎么样让一个容器和另一个容器对话呢?答案是:网络。你不需要是一名网络工程师,只要记得这个规则就行:

如果2个容器在同一个网络,那么它们俩就能够互相对话;如果不在,那就不行。

启动MySQL

有2种方式把一个容器连上一个网络:1、启动时就把容器连上网络 2、网络连接一个现有的容器

我们会先创建一个网络,然后在启动时连上MySQL容器。

1、创建网络

docker network create todo-app

2、启动一个 MySQL 容器,并把容器连上网络。我们也会定义一些环境变量,数据库会用它们来初始化数据库,参见 MySQL Docker Hub清单的 Environment Variables 段落。

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:5.7

如果你使用的是 Power Shell 的话,把上述命令的 \ 替换成 ` 即可。

关于 –network-alias 旗标,我们一会儿再聊。

专家提示

你应该有注意到我们使用一个具名卷,名字是 todo-mysql-data ,并将其挂载到了 /var/lib/mysql ,这里是 MySQL 存储数据的地方。不过,我们并没有运行 docker volume create 命令。Docker 识别出,我们想要使用一个具名卷,接着就为我们自动创建了一个。

3、为了确认我们的数据库跑起来了,我们尝试连接数据库,并验证是否连接成功。

docker exec -it <mysql容器id> mysql -p

当密码提示符出现,输入 secret 。在 MySQL shell 中,列出数据库,并确认你看到了 todos 数据库。

mysql> SHOW DATABASES;

你应该会看到以下输出:

好了,我们已经有了我们的 todos 数据库,并且随时可以使用。

连接MySQL

既然我们已经知道 MySQL 已经正常运行了,让我们来使用 MySQL 吧。但是,问题……怎么用?如果我们在同一个网络运行另一个容器的话,我们如何找到容器?记住,每个容器都有自己的IP地址。

要弄清楚怎样才能使用MySQL,我们会用到 nicolaka/netshoot 容器,它自带了很多可以用于排错和调试网络问题的工具。

1、使用 nicolaka/netshoot 启动一个新容器。确保容器连接了同一个网络。

docker run -it –network todo-app nicolaka/netshoot

2、在容器中,使用 dig 命令,这个命令是一个好用的DNS工具。我们会用它来查找主机名为 mysql 的 IP 地址。

dig mysql

应该会看到如下输出:

在 ANSWER SECTION 中,你会看到 mysql 的 A 记录,解析为 172.18.0.2 ,你的IP地址很可能是另一个值。尽管 mysql 通常并不是一个有效的主机名,但是Docker能够将其解析为:网络别名为 mysql 的容器的 IP 地址。还接的之前用到的 –network-alias 旗标么?

这也就意味着,我们的应用只需要连接主机名为 mysql 的主机,然后就能和数据库连通了。没有比这更简单的了!

基于 MySQL 运行应用

待办任务应用支持通过设置一些环境变量,来指定 MySQL 的连接设置。它们是:

MYSQL_HOST

运行 MySQL 服务器的主机名

MYSQL_USER

连接数据库服务器使用的用户名

MYSQL_PASSWORD

连接数据库服务器使用的密码

MYSQL_DB

连上以后,使用的数据库

警告

尽管使用环境变量设置连接设置,用于开发的话通常是没问题的,但是生产环境运行应用的时候,这样做是极不推荐的。前Docker的安全一把手Diogo Monica专门写了一篇博客来解释原因。

一个更加安全的机制是使用容器编排框架所提供的密钥支持机制。在大多数情况下,这些密钥作为文件在容器中挂载。你会看到很多应用,包括MySQL镜像和待办应用,也会通过 _FILE 后缀,指向包含变量的文件的方式,来支持环境变量。

作为一个例子,设置 MYSQL_PASSWORD_FILE 变量会导致应用去使用变量所指向的文件的内容,作为连接密码。Docker不会做任何事来支持这些环境变量。你的应用需要知道如何查找变量,并获取文件内容。

由于我们的项目被投资者相中了,准备作为产品投产。所以我们需要考虑应用的规模化问题。SQLite显然是不适合规模化的。于是我们打算引入MySQL。不过这个时候我们就需要考虑:是单独为MySQL起一个容器,还是把它安装到现有容器当中。种种考量之下,我们知道给MySQL单独起一个容器的好处。那么接下来的问题就是,如何实现多个容器之间的通讯。我们利用 nicolaka/netshoot 容器,解决了找到容器的 ip 地址的问题。不过,我们的更大发现是:网络别名 –network-alias 的妙用。之后,我们知道原来在待办任务应用中,存在几个环境变量,使用这些环境变量,就能让我们指定指定应用向 MySQL 的连接,尽管这在生产环境中是绝对不推荐的。

那么,接下来就是今天的重头戏,实现应用容器对MySQL容器的请求。首先,让我们来启动准开发容器。

开工
1、指定上文一起学Docker8:如何搭建多容器应用(上)提到的所有环境变量,同时将容器接入我们的应用网络。

docker run -dp 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:12-alpine \

sh -c “yarn install && yarn run dev”

如果你用的是 Power Shell 的话,把命令中的 \ 替换成 ` 即可。

2、如果我们查看容器的日志的话,我们会看到消息,提示我们应用已经用上 mysql 数据库了。

3、在网页浏览器中打开应用,并给待办任务列表中,添加一些任务。

4、连接MySQL数据库,确认一下那些任务被写入了数据库。记住,密码是 secret 。

docker exec -it <mysql容器id> mysql -p todos

在 MySQL shell 中运行以下命令,你会看到刚才在网页端添加的任务,已经在这里显示了。

如果你打开Docker仪表盘查看的话,你会看到有2个应用容器在运行。但是没有什么标识可以让你一眼发现:这2个容器是同一个应用的。我们之后会看看怎么让它有更好的展示。

回顾
此时此刻,我们有一个应用,它把数据保存在另一个容器中的外部数据库中。我们学习了容器网络的一些内容,看到了如何通过使用DNS来实现服务发现。

不过,你可能开始觉得启动应用所需要的东西越来越多。我们必须创建网络,启动容器,指定所有环境变量,暴露端口等等。要记的东西有很多,如果要把工作交接给别人的话,也越发困难了。

在下一篇文章中,我们会讨论Docker Compose。有了 Docker Compose,我们能够以更加简单的方式分享我们的应用栈,其他人只要一个简单的命令就能启动容器。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
秦晓武
讨论数量: 0
发起讨论 只看当前版本


暂无话题~