docker安装nginx和php,如何修改ng配置、安装php扩展?
发布于 作者:苏南大叔 来源:程序如此灵动~
如果出于测试目的的话,苏南大叔测试机上面的phpstudy还是很好用的。那么,本文中的搭建方式,更接近于实际的运维场景。使用docker拉取并运行对应的容器,配置一个自己的LNMP组合。通过Docker安装最新版的Nginx/PHP/MySQL,并将它们配置到同一个网络中。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10,docker@28.0.4,mysql@5.7,nginx@1.27.4,php@8.4.6-fpm。对于文中出现的换行连接符,苏南大叔这边因为测试环境是win10,所以使用的是 ^,读者可以根据实际情况使用 \。
前文回顾
本文的内容,基于如下几篇文字:
- https://newsn.net/say/docker-win.html
- https://newsn.net/say/docker-win-2.html
- https://newsn.net/say/docker-mysql.html
如果拉取过程中出错,请记得配置daemon.json中的registry-mirrors字段,例如:
{
"registry-mirrors" :
[
"https://docker.m.daocloud.io",
"https://docker.xuanyuan.me",
"https://docker.1ms.run"
]
}准备工作
宿主机上的持久化目录,参考分布如下:
D:\data
├─mysql
│ ├─conf
│ ├─data
│ └─log
├─nginx
│ ├─conf
│ └─log
├─php
│ ├─etc
│ └─extensions
└─www这里的d:/data/www这个目录,在php和nginx中,都进行了映射/var/www,是个双重目录映射。参考nginx配置这一段内容。

Nginx、PHP 和 MySQL 容器,在不暴漏端口的前提下,为了能够相互通信,苏南大叔需要将它们放在同一个Docker network中,这里暂定网络名称为sunan_network。参考文字:
docker pull nginx
docker pull php:8.4.6-fpm
docker pull mysql:5.7
docker network create sunan_network端口映射,并不是说绝对不能使用,这个是看实际情况来定的。就本文来说,
mysql做了3306端口映射,这主要是因为要使用第三方客户端对它进行管理。nginx做了888:80的端口影射,这主要是因为本来nginx也必须曝露端口,但是宿主机上存在着另外的80应用。php没有做端口映射,9000端口通过统一的network进行内部使用。

安装 mysql
运行MySQL容器,并设置必要的目录映射和端口映射:
if not exist d:/data/mysql/my.cnf echo. > d:/data/mysql/my.cnf
docker run -d ^
--name mysql-container ^
--restart always ^
--network sunan_network ^
-e MYSQL_ROOT_PASSWORD=root ^
-e MYSQL_DATABASE=sunan_db ^
-v d:/data/mysql/my.cnf:/etc/mysql/my.cnf ^
-v d:/data/mysql/conf:/etc/mysql/conf.d ^
-v d:/data/mysql/data:/var/lib/mysql ^
-v d:/data/mysql/log:/var/log/mysql ^
-p 3306:3306 ^
mysql:5.7 --character-set-server=utf8 --collation-server=utf8_general_ci参数说明
--network sunan_network: 将容器加入到sunan_network网络中。-e MYSQL_ROOT_PASSWORD=root: 设置 MySQL 的 root 用户密码。-e MYSQL_DATABASE=sunan_database: 创建一个名为sunan_database的数据库。-v d:/data/mysql/data:/var/lib/mysql: 持久化 MySQL 数据。-v d:/data/mysql/conf:/etc/mysql/conf.d: 映射 MySQL 配置文件目录。-p 3306:3306: 将 MySQL 的 3306 端口映射到宿主机。--character-set-server=utf8,位置很重要,放在前面就执行出错。并且不设置utf8的话,就会出现中文乱码等问题。
是的,苏南大叔准备使用第三方客户端连接这个mysql容器,所以做了3306端口映射。
安装 PHP
先准备持久化数据:
docker run -d --name php-container php:8.4.6-fpmdocker cp php-container:/usr/local/etc d:/data/php/
docker cp php-container:/usr/local/lib/php/extensions d:/data/php/extensions/docker stop php-container
docker rm php-container正式运行PHP容器,并设置目录映射:
docker run -d ^
--name php-container ^
--restart always ^
--network sunan_network ^
-v d:/data/www:/var/www ^
-v d:/data/php/etc:/usr/local/etc ^
-v d:/data/php/extensions:/usr/local/lib/php/extensions ^
php:8.4.6-fpm参数说明
--network sunan_network: 将容器加入到sunan_network网络中。-v d:/data/www:/var/www: 映射 PHP 项目代码目录。-v d:/data/php/etc:/usr/local/etc: 映射自定义的 PHP 配置文件。
这里的/var/www是个特殊的路径,在nginx配置中会做出映射。
进入 PHP 容器并安装扩展:
docker exec -it php-container bash在容器内运行以下命令安装扩展:
docker-php-ext-install mysqlidocker-php-ext-install命令,这不就是pecl install命令么?退出当前状态的命令是手敲的exit。
exit安装完成后,重启 PHP 容器:
docker restart php-container安装 Nginx
依旧是做些目录映射方面的准备:
docker run -d --name nginx-container nginx:latest
docker cp nginx-container:/etc/nginx/conf.d d:/data/nginx/conf
docker cp nginx-container:/etc/nginx/nginx.conf d:/data/nginx/nginx.confdocker stop nginx-container
docker rm nginx-container运行 Nginx 容器,并设置目录映射和端口映射:
docker run -d ^
--name nginx-container ^
--restart always ^
--network sunan_network ^
-v d:/data/nginx/nginx.conf:/etc/nginx/nginx.conf ^
-v d:/data/nginx/conf:/etc/nginx/conf.d ^
-v d:/data/nginx/log:/var/log/nginx ^
-v d:/data/www:/var/www:rw ^
-p 888:80 ^
nginx:latest参数说明
--network sunan_network: 将容器加入到sunan_network网络中。-v d:/data/nginx/conf:/etc/nginx/conf.d: 映射 Nginx 配置文件目录。-v d:/data/www:/var/www: 映射网站项目代码目录。-p 888:80: 将 Nginx 的 80 端口映射到宿主机的 888 端口。
没映射到主机的80端口,原因是宿主机上还有个dify重要应用占用着80端口。
Nginx 配置
修改在 d:/data/nginx/conf 目录下的配置文件:default.conf:
server {
listen 80;
server_name localhost;
root /var/www;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
# root /var/www;
include fastcgi_params;
fastcgi_pass php-container:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
配置好之后,重启nginx。命令如下:
docker restart nginx-container或者进入到容器内部执行reload:
docker exec -it nginx-container nginx -s reload这个nginx配置是成败的关键。和通常意义上的nginx配置是有所不同的。因为这个例子中,nginx和php实际上并不在一起,相互隔离的,但是又在同一个network下面,所以在fastcgi_pass的配置是:php-container:9000。
在这个例子中,实际上还有一点可能会容易忽略,那就是:php-container和nginx-container使用了同一个目录映射/var/www。那么,在配置nginx的时候,在location ~ \.php$中就少设置了一个root。实际上这个省略的root是php那边的路径。但是,两者路径相同,所以即使忽略了也不会报错。
测试环境
在 d:/data/www 目录下创建一个 index.php 文件:
$servername = "mysql-container"; // MySQL 容器的名称
$username = "root"; // MySQL 用户名
$password = "root"; // MySQL 密码
$database = "sunan_db"; // 数据库名称
$conn = new mysqli($servername, $username, $password, $database);
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
echo "成功连接到 MySQL 数据库!";
$result = $conn->query("SELECT VERSION() AS version");
if ($result) {
$row = $result->fetch_assoc();
echo "<br>MySQL 版本: " . $row['version'];
} else {
echo "<br>无法获取 MySQL 版本信息";
}
$conn->close();
访问下面的地址查看效果:
关于持久化
在这篇文字里面,
【1】mysql的相关目录,并没有事先建立临时容器。而nginx和php则选择了相反的方案,选择建立临时容器,docker cp之后再进行删除。选择这样的处理方式的主要原因是(这和容器自身的情况有很大关系,不能苛责,只能适应):mysql的数据,是容器进入后,再生成的数据。所以,仅提供目录即可。而nginx和php,开局就要读取到正确的配置文件,否则容器不能启动。所以,要先准备好正确的配置文件。
【2】关于在docker cp和目录映射的过程中,路径结尾的/是否使用,是有很大的区别的。查看运行结果,仔细体会。
总结
这种docker部署的方式,非常适合开发和测试环境,能够快速搭建一个完整的Web开发环境。更多苏南大叔的docker经验文章,请点击: