Docker学习笔记九:多容器应用程序

235 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情

大家好,我是阿萨。之前学习的都是单容器的应用程序,今天学习多容器应用程序。在之前的待办事项容器基础上增加MySQL。

肯定有很多人问:MySQL运行在哪儿?是安装在相同容器还是单独安装呢?

一般情况下,每一个容器应该只完成一件事情。

原因:

  • 方便扩展前端和API
  • 单独容器,可以让当前版本和版本更新隔离开。
  • 可以让数据分离,本地调试数据库和生产环境的托管数据库分开管理。数据库不必跟随版本一起发布。
  • 一个容器只能启动一个进程。如果运行多进程。需要增加进程管理器。会增加容器启动和关闭的复杂性。

如下图是我们程序的示意图。待办事项和数据库分开。

一,容器网络

一般情况下,容器是隔离的。它不知道其他进程或者容器。怎么让容器时间通信呢?那就是网络。

如果2个容器在相同的网络里,那么他们可以相互通信。否则不能通讯。

二, 启动MySQL

有2中方式把容器放于网络中。1) 启动时设置网络。2)连接到一个已经存在的网络中。

现在我们先创建网络,然后和MySQL容器启动时连接上。

  1. 创建网络.

     $ docker network create todo-app
    
  2. 启动一个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:5.7
    

    如果是ARM 比如 Macbook M1 Chips / Apple Silicon,使用如下命令:

     $ docker run -d \
         --network todo-app --network-alias mysql \
         --platform "linux/amd64" \
         -v todo-mysql-data:/var/lib/mysql \
         -e MYSQL_ROOT_PASSWORD=secret \
         -e MYSQL_DATABASE=todos \
         mysql:5.7
    

    如果是Windows的PowerShell 请使用如下命令。

     PS> 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
    

    有一个参数 --network-alias 。请注意。

    Tip

    我们使用了这个卷 todo-mysql-data 挂载到/var/lib/mysql, 来存储数据。 请注意,我们没有使用 docker volume create命令Docker 知道我们想用一个命名卷。就自动创建了一个.

  3. 为了确认我们有数据库启动并运行,连接到数据库并校验连接。

     $ docker exec -it <mysql-container-id> mysql -u root -p
    

    需要输入密码时,请注意保密。在 MySQL的shell里,列出数据库并校验你看到了todos 数据库.

     mysql> SHOW DATABASES;
    

    输出像这样:

     +--------------------+
     | Database           |
     +--------------------+
     | information_schema |
     | mysql              |
     | performance_schema |
     | sys                |
     | todos              |
     +--------------------+
     5 rows in set (0.00 sec)
    

    退出mysql。

    mysql> exit
    

    todos 可以用啦!

三,连接到MySQL数据库。

数据库起来后。咋连接到容器上呢? 统一网络下,容器咋找到数据库 (每个容器都有自己的IP地址的)?

为了解决这个问题,我们将使用nicolaka/netshoot容器,它附带了许多用于排除故障或调试网络问题的工具。

  1. 启动一个新的 nicolaka/netshoot 镜像。确定连接到相同网络。

     $ docker run -it --network todo-app nicolaka/netshoot
    
  2. 容器内部使用 dig 命令, 这是一个非常有用的 DNS 工具。查找mysql的 IP 地址。

     $ dig mysql
    

    将会得到类似这样的输出:

     ; <<>> DiG 9.14.1 <<>> 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的一个解析为172.23.0.2的a记录(你的IP地址很可能有不同的值)。虽然mysql通常不是一个有效的主机名,但Docker能够将它解析为具有该网络别名的容器的IP地址(还记得我们前面使用的——network-alias标志吗?)这意味着…我们的应用程序只需要简单地连接到一个名为mysql的主机,它将与数据库对话!没有比这更简单的了!

四,运行你的程序在MySQL上

待办事项的应用程序指定了一些环境变量去连接MySQL。这些参数有:

  • MYSQL_HOST - 运行MYSQL的主机名。
  • MYSQL_USER - 连接MySQL的用户名。
  • MYSQL_PASSWORD - 连接MySQL的密码。
  • MYSQL_DB - 连接的数据库
  1. 请注意: 运行MySQL8.0之上的,请运行如下命令:

     mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'secret';
     mysql> flush privileges;
    
  2. 设置对应的环境变量。

     $ 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"
    

    使用ARM based chip, 比如 Macbook M1 Chips / Apple Silicon, 用如下命令

     $ 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 "apk add --no-cache python2 g++ make && yarn install && yarn run dev"
    

    Windows 请在 PowerShell中运行如下命令。

     PS> 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"
    
  3. 查看日志 (docker logs <container-id>), 能看到如下使用MySQL的信息。

     $ nodemon src/index.js
     [nodemon] 1.19.2
     [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
    
  4. 打开浏览器,查看待办事项。

  5. 连接上数据库,查看数据库数据。

     $ docker exec -it <mysql-container-id> mysql -p todos
    

    运行sql命令:

     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 |
     +--------------------------------------+--------------------+-----------+
    

如果你快速浏览一下Docker Dashboard,你会看到我们有两个应用程序容器在运行。但是,并没有真正的迹象表明它们被组合在一个单独的应用程序中。我们将很快学习到这一章节。

如果觉得阿萨的内容对你有帮助,欢迎围观点赞。