第 4 章. 连贯到数据库
在连贯数据库之前,咱们须要确保咱们的 PHP 容器已装置所有必要的扩大。默认状况下,Docker Hub 上的 PHP 镜像都是十分轻量级的,因而它不蕴含您可能须要的许多 PHP 扩大或 Linux 包。您必须依据我的项目优先级在较小或者更灵便的镜像之间进行衡量,然而咱们晓得该我的项目须要用到 MySQL,因而让咱们在 PHP 镜像中装置所需的拓展吧
应用根底的 PHP 镜像通常是一个很好的终点,然而我也能够在 Github 中查找应用启用常见扩大的 PHP 镜像。查看此存储库理解更多信息。
创立自定义 Dockerfile
进入到咱们的 天气利用
我的项目的根目录,创立一个的新文件命名为Dockerfile
。Dockerfile 没有扩展名,用于配置和设置 Docker 镜像。Docker Hub 上的所有镜像都有有相应的 Dockerfile 文件,通常您能够在 GitHub 上找到它们。PHP 的 dockerfile 在这里,但它们可能会有点凌乱,因为它们是互相关联的的。咱们的 Dockerfile 会简略得多:
Dockerfile
FROM php:apache
RUN docker-php-source extract && docker-php-ext-install mysqli pdo pdo_mysql && docker-php-source delete
解疑小课堂
此 Dockerfile 有两行:
FROM php:apache
– 这通知 Docker 在开始构建时抉择哪个镜像。你能够从一个 Linux 发行版开始 (比方 Ubuntu 或者超轻 alpine),或者您也能够本人构建一个雷同的镜像。在这里,咱们抉择php:apache
镜像作为咱们的运行容器。RUN docker-php-source extract...
– 这是增加咱们须要的 PHP 扩大。在咱们的例子中,咱们只想应用 mysqli 函数 用于操作 Mysql 数据库。因为这是一个十分常见的扩大,当咱们选用 PHP 根底镜像时,PHP 镜像中有主动增加它的办法。
查看 官网 Docker 文档 无关扩大现有镜像的更多配置命令。
构建镜像
咱们须要通过刚刚创立的 Dockerfile 去构建咱们所需的镜像:
cd E:/workplace/docker-app/weather-app
docker build . -t sunmking/weather-app
当咱们运行此命令构建 Docker 镜像时,将看到以下输入,具体如下:
[+] Building 0.3s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 31B 0.0s
=> [internal] load .dockerignore 0.1s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/php:apache 0.0s
=> [1/2] FROM docker.io/library/php:apache 0.0s
=> CACHED [2/2] RUN docker-php-source extract && docker-php-ext-install mysqli && docker-php-source delete 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.0s
=> => writing image sha256:d92e846df4b0210c29f84c8f5ec8affdb8a823b6de34a24ac460564f160e6207 0.0s
=> => naming to docker.io/sunmking/weather-app
解疑小课堂
Docker build 通过刚刚创立的 Dockerfile 构建一个可用于运行容器的镜像。在该命令中,咱们使了两个参数:
.
– 点让 Docker 晓得咱们构建的“content”— 在这种状况下,它是当前目录。您也能够应用绝对路径,如/ 用户 / 用户名 / 天气 - 利用
如果您晓得 Dockerfile 的确切门路。Docker 会在蕴含 Dockerfile 的目录的上下文中主动构建此镜像,因而请确保 Dockerfile 位于我的项目的根目录。-t sunmking/weather-app
– 的-t
为您的镜像设置一个“标签”。此标签可让您更轻松地从镜像中创立容器,或将镜像推送到镜像注册核心以与其他人共享。
咱们能够在本地计算机上运行 docker images 来查看所有的 Docker 镜像。当咱们运行此命令时,能够在终端中看到如下内容:
REPOSITORY TAG IMAGE ID CREATED SIZE
sunmking/weather-app latest d92e846df4b0 2 hours ago 477MB
docker101tutorial latest 870f3cf07e24 4 days ago 28.9MB
alpine/git latest b80d2cac43e4 12 days ago 43.6MB
snyk/snyk-docker-desktop-extension 0.6.2 d070900ca2ee 6 weeks ago 71.5kB
composer latest c8d389ce4877 9 months ago 193MB
php apache b4e8e213b0ec 10 months ago 477MB
php latest 13b9b1961ba3 10 months ago 484MB
mysql 5.7 c20987f18b13 10 months ago 448MB
运行 MySQL 容器
在介绍中,我提到 Docker 容器能够通过 Docker 的网络性能 形式 “ 链接 “ 起来。为了让咱们的 PHP 应用程序从数据库中获取数据,咱们须要将其链接到可用的数据库容器。OK,让咱们 l 来启动一个新的 MySQL 容器,以便咱们能够将 web 应用程序链接到它:
docker run -d --rm --name weather-db -e MYSQL_USER=admin -e MYSQL_DATABASE=weather -e [email protected] -e MYSQL_RANDOM_ROOT_PASSWORD=true mysql:5.7
解疑小课堂
当咱们运行上述 docker run 命令时,Docker 将拉取最新版本的 MySQL 5.7 镜像 并启动名为 weather-db 的容器。跟咱们运行 PHP 容器一样,MySQL 在 Docker Hub 上有很多版本的 Docker 镜像 , 您能够以简直雷同的形式应用它们。下面的命令蕴含了一些新的参数,让我来给你们介绍一下:
-d
– 这将在“Detached”模式下运行容器,这意味着您不必放弃终端与容器连贯,你能够间接敞开你的终端窗口,你的容器仍旧在后盾安稳的运行着。--name weather-db
- 命名咱们的数据库容器很重要,因为你能够更加不便的通过名称去连贯你创立的容器。咱们也能够应用这个名称在咱们的 PHP 应用程序中连贯到 MySQL 数据库,咱们将会在前面遇到。-e MYSQL_USER=admin
– MySQL 镜像 包含几个 -e (环境变量) 选项。第一个设置了咱们将在 PHP 应用程序中应用的 MySQL 用户的用户名。无关环境抉择的更多信息,请拜访 Docker Hub 官网镜像。-e MYSQL_DATABASE=weather
- 默认状况下,容器不会创立数据库。尽管您能够通过登录容器来手动创立一个 (这将在下一节中介绍),然而像这样事后创立数据库会更加简便。-e [email protected]
- 这将设置数据库的初始密码。不论咱们是不是在本地开发,都应该设置为强明码。-e MYSQL_RANDOM_ROOT_PASSWORD=true
– 为 root 用户设置一个随机的明码,不论在什么状况下都不要登录 root 账户。mysql:5.7
– 与 PHP 镜像一样,您能够抉择要应用的 MySQL 版本。在这里,我抉择应用版本 5.7。
就像 php:apache
镜像,默认的镜像就能够了,所以咱们不须要在镜像中增加任何内容。
登录到正在运行的容器
此时,咱们想查看新容器中的数据库是否失常工作,然而如何拜访正在运行的 Docker 容器呢?上面咱们将应用 docker exec
命令进入新容器的终端,而后咱们将应用 MySQL 命令行界面 创立咱们所须要的数据库或者数据表。
咱们能够应用以下命令进入正在运行的数据库容器的 bash 终端:
docker exec -it weather-db bash
你应该看到一条像[email protected]:/#
(容器的 ID) 在终端上,示意您当初已登录到正在运行的容器。从容器内 (不是本地主机上) 运行:
$ mysql --user=admin --password
Enter password:
输入您为下面创立的 MySQL 容器抉择的明码 (在本例中为 p23l % v11p),而后点击“返回”键。您将看到一些对于 MySQL 的信息,如下所示:
PS E:\workplace\docker-app\weather-app> docker exec -it weather-db bash
[email protected]:/# mysql -u admin -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, 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;
命令:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| weather |
+--------------------+
2 rows in set (0.01 sec)
解疑小课堂
在本章的的后面局部中,咱们登录到正在运行的数据库容器上,而后通过命令行登录到 MySQL,并且查看了有哪些数据库。因为大家可能不相熟这些命令,我将逐个介绍它们。
Docker Exec
docker exec
– 这是用于执行 Docker 命令是咱们能够进入在正在运行的容器上。docker exec 还有有许多选项,这里咱们就不一一介绍了,大家能够去官网文档中理解。-it
–-it
这两个标记通常是在一起应用的。i 示意交互式的,示意 [cmd] 是一个有用户输出的程序,比方 /bin/bash 和 python 等等。-t 产生一个终端。所以说有 - i 就必须有 -t,不然怎么输出呢。这 [cmd] 有的镜像是有默认值的,比方 centos 的镜像的默认值 /bin/bash,而 python 镜像的默认值是 python。所以说[cmd] 是能够不写的。weather-db
- 这个是咱们要在其上运行命令的正在运行的容器的名称 (您也能够应用容器 ID)。bash
– 最初,这是咱们要在容器中运行的命令。bash) 是大多数 Linux 发行版中装置的 shell,容许咱们在容器上运行其余程序。如果您的容器没有装置 bash,您也能够尝试 sh。
MySQL CLI
MySQL CLI 还提供了许多选项,以下是咱们应用的三个选项:
mysql
– 这是用于从终端拜访 MySQL 的命令。如果您始终在 VM 或本地计算机上应用 MySQL,则没有什么不同。--user=admin
– 咱们在此处指定用户名,以便 MySQL 晓得咱们心愿以特定用户身份拜访,而不是root
.--password
- 明码标记批示 MySQL 给咱们明码提醒。您也能够间接在命令中输出明码,但它通常不太平安。
退出 MySQL 和容器
咱们当初曾经实现了 MySQL 容器,所以让咱们退出并进行该容器:
- 要退出 MySQL CLI,请键入
\ q
而后按“Enter”。 - 通过键入退出容器
exit
而后按“Enter”。 - 通过键入
docker stop weather-db
来进行容器, 而后再次“Enter”。
实现后,整个命令行输入应如下所示:
mysql> \q
Bye
[email protected]:/# exit
exit
PS E:\workplace\docker-app\weather-app> docker stop weather-db
weather-db
咱们当初曾经解决了如何运行 MySQL 容器,并且咱们能够登录拜访数据库,然而咱们将如何保留在容器中的数据?当咱们进行这个容器时会产生什么?数据的持久性在事实世界的利用中是很重要的,所以在下一节中,咱们将深入研究如何在咱们的容器长久化保留咱们的数据。
保留们数据库容器中的数据
到目前为止,咱们曾经启动了数据库容器并主动创立了一个数据库和用户。这是很不错的开始,然而当咱们把这个数据库连贯到咱们的 PHP 应用程序时,咱们要确保数据库的表和值即便在咱们的容器进行后也会被保留。否则,每次咱们的数据库容器重新启动时,咱们将不得不重建数据库和增加数据。
从容器中保留数据用于本地开发的最好办法是挂载一个数据卷。这对咱们的 PHP 代码的本地开发是十分无效的,而咱们挂载数据库数据卷的过程也十分类似。在咱们启动 PHP 容器是也挂载了一个(在咱们的例子中,咱们之前创立的 weather-app 目录),但你能够从本机系统的任何中央挂载卷,我这里把数据挂载在我的项目的同级目录 .data 中。
当初咱们开始学 如何保留 mysql 容器里的数据, 当初进入到 weather-app
我的项目下执行以下命令:
docker run -d --rm --name weather-db -e MYSQL_USER=admin -e MYSQL_DATABASE=weather -e [email protected] -e MYSQL_RANDOM_ROOT_PASSWORD=true -v E:/workplace/docker-app/.data:/var/lib/mysql mysql:5.7
解疑小课堂
咱们在这个 docker 运行命令中增加的惟一内容是 -v E:/workplace/docker-app/.data:/var/lib/mysql。该命令是把一个卷从咱们的本地目录挂载到 MySQL 容器中。当咱们运行下面的命令时在(.data/)目录中会呈现很多文件和目录。这些是 MySQL 用来存储数据的文件,你能够从你的终端查看这些文件。
$ ls -a .data/ # Linux OR MAc
or
$ cd E:/workplace/docker-app/.data/ # win
$ dir # win
显示输入如下:
目录: E:\workplace\docker-app\.data
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2022/10/19 11:09 mysql
d----- 2022/10/19 11:09 performance_schema
d----- 2022/10/19 11:09 sys
d----- 2022/10/19 11:10 weather
-a---- 2022/10/19 11:09 56 auto.cnf
-a---- 2022/10/19 11:09 1676 ca-key.pem
-a---- 2022/10/19 11:09 1112 ca.pem
-a---- 2022/10/19 11:09 1112 client-cert.pem
-a---- 2022/10/19 11:09 1680 client-key.pem
-a---- 2022/10/19 14:36 79691776 ibdata1
-a---- 2022/10/19 14:36 12582912 ibtmp1
-a---- 2022/10/19 11:14 694 ib_buffer_pool
-a---- 2022/10/19 14:36 50331648 ib_logfile0
-a---- 2022/10/19 11:09 50331648 ib_logfile1
-a---- 2022/10/19 11:09 1680 private_key.pem
-a---- 2022/10/19 11:09 452 public_key.pem
-a---- 2022/10/19 11:09 1112 server-cert.pem
-a---- 2022/10/19 11:09 1676 server-key.pem
不要放心这些都是什么意思(只管如果你有趣味,你能够浏览一下 MySQL 的文档)。在这,咱们只关怀在 MySQL 容器中应用来自咱们主机的数据,容许咱们在容器敞开后仍能放弃数据库数据。
创立数据表
因为这个应用程序须要缓存来自 高德天气 API 的后果,所以咱们要创立一个 location 表,并增加列 id、weather 和 last_updated。
如果 MySQL 容器没有运行,那么应用下面的办法启动它,挂载数据卷:
docker run -d --rm --name weather-db -e MYSQL_USER=admin -e MYSQL_DATABASE=weather -e [email protected] -e MYSQL_RANDOM_ROOT_PASSWORD=true -v E:/workplace/docker-app/.data:/var/lib/mysql mysql:5.7
登录到 Mysql 容器并进入到 MySQL CLI 中。这一次,咱们将一步到位创立数据表:
docker exec -it weather-db mysql --user=admin --password='[email protected]' weather
接下来,运行 Mysql SQL 命令来创立咱们上述的数据库表:
mysql> CREATE TABLE locations (id VARCHAR(64) NOT NULL, weather JSON NULL, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
应该会失去反馈 Query OK
, 你也能够通过运行 SHOW TABLES;
命令来查看创立的表. 而后输出 \q
退出 mysql 终端.
解疑小课堂
与上次登录 MySQL 命令行不同的是,这次咱们把这个过程缩减到只有一个步骤。记住,当运行 docker run 或 docker exec 时,前面的参数局部是咱们想在容器中运行的命令。这意味着咱们不须要先登录到 bash 会话,再登录到 MySQL,咱们能够间接登录到 MySQL CLI。
将 PHP 应用程序中的数据保留到数据库
当初,咱们的数据库曾经筹备好了,即便在容器被移除后,它也会保留这些数据,咱们须要更新咱们的 PHP 应用程序,以连贯到数据库并存储天气后果。
最后,咱们是间接从 高德天气 API 获取数据,但当初咱们曾经有了一个存储机制(即:咱们的数据库),让咱们让应用程序将数据保留到数据库,以便缩小 API 申请。
首先进入到我的项目的根目录 运行 cp .example.env .env 并编辑 .env 文件,内容如下:
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
[DATABASE]
TYPE = mysql
HOSTNAME = weather-db
DATABASE = weather
USERNAME = admin
PASSWORD = '[email protected]'
HOSTPORT = 3306
CHARSET = utf8
DEBUG = true
[LANG]
default_lang = zh-cn
而后,咱们开始批改咱们的业务逻辑,关上我的项目根目录下的 app/controller/Weather.php 文件,更新如下:
<?php
namespace app\controller;
use app\BaseController;
use Clydecn\Amap\Weather as AmapWeather;
use think\facade\Db;
class Weather extends BaseController
{
public $key;
public $weather;
// 初始化
protected function initialize()
{
$this->key = "xxxxxxxxxxxxxxxx"; // 高德 KEY
$this->weather = new AmapWeather($this->key);
}
public function get()
{$rid = $this->request->param('location_id', '310000');
// 通过 Mysql 查问天气信息
$weather = Db::table('locations')->where(['id' => $rid])->find();
// 如果查问到了
if($weather){
// 间接返回
return json(json_decode($weather['weather'],true),200);
}
// 通过 API 查问当天天气
$res = $this->weather->getLiveWeather($rid);
// 将查问的后果插入数据库
Db::table('locations')->insert([
'id'=>$rid,
'weather'=>json_encode($res),
'last_updated'=>date('Y-m-d H:i:s'),
]);
return json($res, 200);
}
public function delete()
{
// todo
echo "location_id is" . $this->request->param('location_id');
}
}
解疑小课堂
在这里咱们做了两步操作:
- 增加数据库配置
ThinkPHP 数据库配置,能够在 .env 外面配置,若果有不明确的能够查看 ThinkPHP6.0 齐全开发手册
-
增加业务逻辑
- 查问数据是否存在,存在就响应曾经存在的数据
- 如果数据不存在,就间接申请接口并存储在数据库中,以待下次查问
尽管代码中的正文可能会有帮忙,但如果你不相熟 ThinkPHP6,还是有一些细节值得关注的:
$rid=$this->request->param('location_id', '310000');
– ThinkPHP6 中获取参数的办法.$weather=Db::table('locations')->where(['id' => $rid])->find();
– 数据库查问.returnjson(json_decode($weather['weather'],true),200);
– 将后果以 json 的格局展示给用户.
连贯 PHP 容器
有了代码,当初咱们须要运行 PHP 容器,链接到咱们刚刚启动的 MySQL 数据库容器:
docker run -d --privileged=true --rm --name=weather-app -p 38000:80 -v E:/workplace/docker-app/weather-app/:/var/www/html --link weather-db sunmking/weather-app
解疑课堂
此 docker run 命令有两个新局部:
--link weather-db
- 链接名为weather-db
的容器。你也能够给链接的容器一个别名在 PHP 容器中应用,然而咱们不须要在这里这样做。sunmking/weather-app
- 咱们应用的是本章结尾构建的新 Docker 镜像,而不是应用php:apache
。这样做的起因是咱们须要在自定义 Docker 镜像中增加的 PHP MySQLi PDO PDO_MYSQL 扩大。
当初,PHP 容器已启动并正在运行,您应该可能导航到地位 ID,如下所示:
GET [http://localhost:38000/public/index.php/weather/310000](http://localhost:38000/public/index.php/weather/310000)
第一次加载此 URL 时,加载可能须要一两秒钟,然而如果刷新页面,可能会更快的看到后果。我的加载工夫不到 150 毫秒! 这要归功于咱们通过将后果保留在数据库中。
删除数据
为了从数据库中删除数据,咱们将增加第二个路由。增加当前容许用户从数据库中删除增加的数据:
/**
* delete
*/
public function delete()
{$rid = $this->request->param('location_id', '310000');
// 通过 Mysql 查问天气信息
$weather = Db::table('locations')->where(['id' => $rid])->find();
// 如果查问到了
if($weather){Db::table('locations')->where(['id' => $rid])->delete();
// 间接返回
return json("Location {$rid} deleted.",200);
}else{return json("Location {$rid} Not Found.", 404);
}
}
当初您能够应用 ApiPost 或 postman 发送一个 delete
申请。例如:
DELETE http://localhost:38000/public/index.php/locations/310000
你应该看到一条信息Location 310000
已删除。当初当你做一个GET
再次申请该 URL,您将期待更长的工夫,因为后果来自 高德天气 API。
如果所有工作失常,你当初应该可能像以前一样拜访该应用程序