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-fpm
docker 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 mysqli
docker-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.conf
docker 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
经验文章,请点击:


