在 Docker 中设置基本的本地 PHP 开发环境
在本文中,我们将学习如何在 Docker 中搭建一个基本的本地 PHP 开发环境。我们将使用 docker-compose 和 Dockerfile 来实现。我们将使用 PHP、Apache 和 Mysql。后续教程将介绍如何搭建一个包含任务运行器、Composer 等组件的综合环境。
如果你只想快速查看源代码,请直接跳到底部。我们会一步一步地慢慢讲解。
先决条件:已安装 Docker 和 Docker-compose。
第一步:获取一个简单的 PHP 脚本并使用 Dockerfile 运行。
如果你查看PHP Docker 文档,你不会看到任何关于 docker-compose 文件的内容,但我们可以通过他们提供的内容来了解如何操作。一开始,他们提供了一个简单的 Dockerfile 设置。让我们在项目根目录下使用它作为我们的 Dockerfile:我将我的项目命名为“php-docker”。然后在里面 make a 命令,Dockerfile
代码如下:
FROM php:7.4-cli
COPY . /usr/src/myapp
WORKDIR /usr/src/myapp
CMD [ "php", "./index.php" ]
这段代码是创建我们将要使用的图像的设置。此设置通过一些命令行工具引入了 PHP 7.4。
这COPY . /usr/src/myapp
会将当前目录的内容复制到 Docker 容器内的 /usr/src/myapp 中。下一行:WORKDIR /usr/src/myapp
将 /usr/src/myapp 设置为“工作目录”,类似于 cd /to/your/project 的操作。
然后,在 /usr/src/myapp 文件夹中运行命令,$ php ./index.php
其中 index.php 是我们的脚本。这意味着我们需要一个 PHP 脚本。让我们index.php
在项目目录中创建如下文件:
<?php
echo "Hello from the docker container";
现在我们可以按照他们的指示,构建并运行 docker 镜像:
$ docker build -t my-php-app .
$ docker run -it --rm --name my-running-app my-php-app
第一个命令将使用当前目录的内容在您的计算机上构建名为“my-php-app”的镜像。第二个命令基于我们刚刚创建的镜像“my-php-app”准备一个名为“my-running-app”的容器。我们设置运行index.php脚本,因此该脚本将在命令行中运行。我们应该得到如下结果:
第一步完成了!但是简单的 PHP 脚本用处不大。让我们在 Apache Web 服务器上设置它。如果您进一步向下滚动文档,您会看到“镜像变体”部分,其中之一是 php-apache。此镜像将 Apache 与 PHP 捆绑在一起。这将使我们能够轻松地在 Web 服务器上运行脚本,并在浏览器中显示脚本结果。再次,让我们按照说明操作。要运行不带 dockerfile 的 Apache/php 镜像,请运行以下命令:(注意,第一行适用于 Linux/Mac 用户,第二行适用于仅支持 Windows 用户)
docker run -d -p 80:80 --name my-apache-php-app -v "$PWD":/var/www/html php:7.2-apache # This line for *nix users
docker run -d -p 80:80 --name my-apache-php-app -v C:\Users\fastp\Desktop\Code\tutorials\php-docker:/var/www/html php:7.2-apache # For Windows users
这一行基本上是在说运行容器并将名称设置为“my-apache-php-app”。-p 是设置从本地计算机到容器端口的 PORT 映射。左侧是我们的本地端口,右侧是容器上的端口。然后使用 -v 设置 VOLUME,或者...基本上将我们当前的工作目录绑定到 /var/www/html 文件夹。这实际上是将当前目录的内容放入容器上的 html 目录中,以便我们的代码可以在其中运行。最后,我们定义了构建的镜像,即php:7.2-apache
请注意,Windows 没有 $PWD 命令,因此我必须手动输入路径才能使其工作。
好的,我们设置我们的脚本在端口 80 上运行,所以继续访问http://localhost:80,您应该会看到您的脚本在浏览器中运行。
PHP 和 docker-compose
现在让我们开始将内容移动到 docker-compose 文件中,但首先让我们停止刚刚创建的容器。您可以运行 a 命令docker ps
获取容器 ID,然后运行,$ docker stop container_id
但我打算像这样停止所有容器:
docker stop $(docker ps -a -q)
现在docker-compose.yml
在项目根目录中创建一个文件并将以下内容放入其中:
version: '3.1'
services:
php:
image: php:7.4-apache
ports:
- 80:80
volumes:
- ./src:/var/www/html/
第一行设置了我们正在使用的 docker-compose 的版本号。然后是“services”,它是要设置的容器列表。我们将这个容器命名为“php”,以便其他容器可以通过该名称连接。“image”将是 php:7.4-apache(尽管我们之前的命令行实验使用的是 7.2)。
然后,就像在命令行中尝试一样,我们将设置从本地机器上的 80 端口映射到容器上的 80 端口。最后,我们将 ./src 文件夹的内容放入容器/var/www/html
文件夹中。现在,我们将脚本移动到本地机器上的 ./src 文件夹中。我的项目结构现在如下所示:
现在docker-compose up -d
从项目根目录运行并访问localhost:80,即可在浏览器中查看正在运行的脚本。因为我们使用卷将代码粘贴到容器中,所以我们应该能够更改脚本并使其自动更新。不妨试试。
现在让我们用关闭我们的容器docker-compose down
。
下一步是设置MySQL 和 Adminer(一个数据库访问工具)。幸好他们的文档提供了一个 docker-compose 的示例,所以我们不用想太多。不过,我们确实需要稍微修改一下设置,因为要将 PHP 连接到 MySQL,我们需要在 PHP 环境中安装一些缺失的部分。我们的docker-compose.yml
文件现在应该是这样的:
# Use root/example user/password credentials
version: '3.1'
services:
php:
build:
context: .
dockerfile: Dockerfile
ports:
- 80:80
volumes:
- ./src:/var/www/html/
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
adminer:
image: adminer
restart: always
ports:
- 8080:8080
我们的 PHP 服务看起来有所不同,因为要使用 mysqli 将 PHP 连接到数据库,我们需要安装一些 mysqli 相关的东西。这意味着我们需要使用 Dockerfile 来定制我们的 php7.4-apache 镜像。所以现在我们使用“build”命令来构建当前目录(点号)的内容,并使用 Dockerfile 来创建镜像。(Dockerfile 镜像代码如下)
现在我们添加了一个“db”服务,也就是 mysql 镜像。它使用了一些与密码相关的奇怪命令 :-),以及一个重启策略。它还设置了一个环境变量,将 root 密码设置为“example”,这样我们就可以通过它登录了。
然后,adminer 获取 adminer 镜像,并将端口映射设置为 8080:8080。就像在 XAMPP 中访问 localhost/phpmyadmin 获取数据库管理工具一样,嗯……这样,你就可以访问 localhost:8080 来访问 adminer 数据库工具。
我们来设置一下 Mysqli,让它在 PHP 容器中运行。我的Dockerfile 代码如下:
FROM php:7.4-apache
RUN docker-php-ext-install mysqli
我知道代码量很大……所以让我们逐行分析一下。第一行使用 php:7.4-apache 镜像来构建容器。第二行运行命令在容器内安装 mysqli 扩展。到这里,我们已经拥有了一个超级基础的 PHP 开发环境所需的一切。所以,让我们docker-compose up -d
再次运行。
现在我们应该可以访问 Adminer 并登录了。为了加快速度,我先用几张图片。需要注意的是,根据 dockerfile 的描述,我们这里“服务器”的名称是“db”。当然,我们也可以把它命名为“pie”或者其他任何我们喜欢的名字。
选择“创建数据库”
命名并点击保存。我将其命名为“company1”。
然后选择“新项目”将一些项目添加到您的表中。
现在我们只需要 PHP 连接到数据库。这不是 PHP 教程,所以我不会全部讲解,但它只是连接到数据库,运行一些查询并将它们打印在屏幕上。重点是第三行将 MySQL 连接到 PHP 的代码。
<?php
echo "Hello from the docker yooooo container";
$mysqli = new mysqli("db", "root", "example", "company1");
$sql = "INSERT INTO users (name, fav_color) VALUES('Lil Sneazy', 'Yellow')";
$result = $mysqli->query($sql);
$sql = "INSERT INTO users (name, fav_color) VALUES('Nick Jonas', 'Brown')";
$result = $mysqli->query($sql);
$sql = "INSERT INTO users (name, fav_color) VALUES('Maroon 5', 'Maroon')";
$result = $mysqli->query($sql);
$sql = "INSERT INTO users (name, fav_color) VALUES('Tommy Baker', '043A2B')";
$result = $mysqli->query($sql);
$sql = 'SELECT * FROM users';
if ($result = $mysqli->query($sql)) {
while ($data = $result->fetch_object()) {
$users[] = $data;
}
}
foreach ($users as $user) {
echo "<br>";
echo $user->name . " " . $user->fav_color;
echo "<br>";
}
现在,这是我们在浏览器中运行代码的结果。:
使用卷的持久性 Mysql:
您可能不会一次性构建整个应用程序,因此我们需要使用卷来存储持久数据,例如数据库中的数据。如果没有卷,每次停止容器时,您的数据都会被清除。为此,您只需在代码中添加几行代码即可。从 db: 开始的代码如下所示:(重要的几行位于“db”部分的末尾,即卷所在位置,以及最末尾的“volumes”位置)
db:
image: mysql
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- mysql-data:/var/lib/mysql
adminer:
image: adminer
restart: always
ports:
- 8080:8080
volumes:
mysql-data:
注意缩进。volumes将与 "services" 处于相同的缩进级别。
我现在不会深入讲卷(说实话我还不是专家,哈哈),但在这段代码中,我们在系统上(由 docker 管理)设置了一个名为 mysql-data 的卷。我们所有的数据库表和垃圾数据都存储在这个“mysql-data”卷中。然后我们将这些数据映射到容器的 /var/lib/mysql 目录下。
好了,差不多就是这样了。如果你想练习一下,可以尝试用 Postgres 替换 MySQL,或者用 Nginx 替换 Apache,或者尝试使用 Dockerfile 安装其他工具,比如 Composer。如果这篇文章对你有帮助,请告诉我。我希望得到一些反馈,这样我才能改进。