Docker PHP 入门实践(四)

第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 有两行:

查看 官方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 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 MYSQL_PASSWORD=wt2022@1019 -e MYSQL_RANDOM_ROOT_PASSWORD=true mysql:5.7

解疑小课堂

当我们运行上述 docker run 命令时,Docker 将拉取最新版本的 MySQL 5.7镜像 并启动名为weather-db的容器。跟我们运行 PHP 容器一样,MySQL 在 Docker Hub上有很多版本的 Docker 镜像 ,您可以以几乎相同的方式使用它们。上面的命令包含了一些新的参数,让我来给你们介绍一下:

就像php:apache镜像,默认的镜像就可以了,所以我们不需要在镜像中添加任何内容。

登录到正在运行的容器

此时,我们想检查新容器中的数据库是否正常工作,但是如何访问正在运行的 Docker 容器呢?下面我们将使用docker exec命令进入新容器的终端,然后我们将使用 MySQL命令行界面 创建我们所需要的数据库或者数据表。

我们可以使用以下命令进入正在运行的数据库容器的 bash 终端:

$ docker exec -it weather-db bash

你应该看到一条像root@3cad1127aa0d:/#(容器的ID) 在终端上,表示您现在已登录到正在运行的容器。从容器内 (不是本地主机上) 运行:

$ mysql --user=admin --password
Enter password:

输入您为上面创建的MySQL容器选择的密码 (在本例中为p23l % v11p),然后点击 “返回” 键。您将看到一些关于MySQL的信息,如下所示:

PS E:workplacedocker-appweather-app> docker exec -it weather-db bash
root@4c9a8b9ebce0:/# 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

MySQL CLI

MySQL CLI 还提供了许多选项,以下是我们使用的三个选项:

退出MySQL和容器

我们现在已经完成了MySQL容器,所以让我们退出并停止该容器:

完成后,整个命令行输出应如下所示:

mysql> q
Bye
root@4c9a8b9ebce0:/# exit
exit
PS E:workplacedocker-appweather-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 MYSQL_PASSWORD=wt2022@1019 -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:workplacedocker-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 MYSQL_PASSWORD=wt2022@1019 -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='wt2022@1019' 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 = 'wt2022@1019'
HOSTPORT = 3306
CHARSET = utf8
DEBUG = true
[LANG]
default_lang = zh-cn

然后,我们开始修改我们的业务逻辑,打开项目根目录下的 app/controller/Weather.php 文件,更新如下:

<?php
namespace appcontroller;
use appBaseController;
use ClydecnAmapWeather as AmapWeather;
use thinkfacadeDb;
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');
}
}

解疑小课堂

在这里我们做了两步操作:

  1. 添加数据库配置

ThinkPHP 数据库配置,可以在 .env 里面配置,若果有不明白的可以查看 ThinkPHP6.0完全开发手册

  1. 添加业务逻辑
  2. 查询数据是否存在,存在就响应已经存在的数据
  1. 如果数据不存在,就直接请求接口并存储在数据库中,以待下次查询

虽然代码中的注释可能会有帮助,但如果你不熟悉 ThinkPHP6,还是有一些细节值得关注的:

连接 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命令有两个新部分:

现在,PHP容器已启动并正在运行,您应该能够导航到位置ID,如下所示:

GET 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);
}
}

现在您可以使用ApiPostpostman发送一个delete请求。例如:

DELETE http://localhost:38000/public/index.php/locations/310000

你应该看到一条信息Location 310000 已删除。现在当你做一个GET 再次请求该URL,您将等待更长的时间,因为结果来自 高德天气 API。

如果一切工作正常,你现在应该能够像以前一样访问该应用程序

展开阅读全文

页面更新:2024-04-16

标签:终端   容器   应用程序   入门   课堂   命令   天气   数据库   目录   数据   用户

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top