Docker从零到一部署DNMP+Redis《全程干货》

  • 时间:2025-11-19 20:24 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:C Docker从零到一部署DNMPR前几天把本机的 mac 格式化了,缘由是环境太乱了,什么东西都往里装,格式化后就想着重新安装开发工具和部署环境,不想再去下载那些集成环境了(XAMPP+MAMP),就想着自己用 Docker 重新部署一套适合自己的环境。(ps.真的很搞,我手里 php 项目有两个不同环境的,还有一个要准备升级)混乱翻查资料的时候看到了一个博客,《十分钟部署 PHP+NGINX

C Docker从零到一部署DNMPR

前几天把本机的 mac 格式化了,缘由是环境太乱了,什么东西都往里装,格式化后就想着重新安装开发工具和部署环境,不想再去下载那些集成环境了(XAMPP+MAMP),就想着自己用 Docker 重新部署一套适合自己的环境。(ps.真的很搞,我手里 php 项目有两个不同环境的,还有一个要准备升级)

混乱翻查资料的时候看到了一个博客,《十分钟部署 PHP+NGINX+MYSQL+REDIS》,尝试跟着部署了一遍,没想到真的成了,转载大佬的笔记,并在这里重新梳理和总结记录一下,造福后人 hh

第一安装Docker

这个不用多说吧,自己去 https:
安装完成后部署环境变量 输入命令 docker -v 查看版本
我的版本是Docker version 28.5.1, build e1 #技术分享80ab8
在配置里直接新增以下国内加速地址
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://docker.1panel.live",
"https://docker.1ms.run",
"https://docker.1panel.live",
"https://docker.m.ixdev.cn",
"https://hub.rat.dev",
"https://docker.xuanyuan.me",
"https://dockerproxy.net",
"https://image.cloudlayer.icu",
"https://docker-registry.nmqu.com",
"https://hub.amingg.com",
"https://docker.hlmirror.com",
"https://docker.kejilion.pro",
"https://docker.367231.xyz",
"https://hub.1panel.dev",
"https://docker.etcd.fun",
"https://docker.apiba.cn",
"https://proxy.vvvv.ee"
 ]

创建容器网络

docker network create --driver bridge haveyb

建立容器网络组

创建代码文件夹

mkdir -p ~/Code/{php,go,python,java,c}

这里是预先建立你 Docker 容器中和宿主机的文件映射

创建服务配置文件夹

mkdir -p ~/Code/docker/php
mkdir -p ~/Code/docker/nginx/{conf.d,cert,logs}

这里是建立环境服务的配置文件地址,用于创建容器时设置文件映射和配置调整

拉取PHP镜像

docker pull haveyb/php《大佬》
该镜像是这个大佬以php官方php-fpm:8.4.12为基础,添加了一些常用扩展
yarredisswoolepdo_mysqlgdpcntlsocketsigbinarymsgpackzstdpdo_pgsqlxslzipbcmathsysvmsgsysvsemsysvshmdebian apt设置了默认阿里国内镜像源
添加了composer为当前最新稳定版本2.8.11,并为composer也配置了阿里国内镜像源。
docker run -itd --name temp-php haveyb/php bash
docker cp temp-php:/usr/local/etc/php/php.ini ~/Code/docker/php

创建临时容器 并将临时容器中的 php.ini 拷贝至映射目录下

docker rm -f temp-php

完成后清除目录

创建PHP正式容器

docker run -itd --name php84 --privileged 
-p 9000:9000 -p 9501:9501 
-v ~/Code/php/test:/data/php/test 
-v ~/Code/docker/php/php.ini:/usr/local/etc/php/php.ini 
--network=haveyb 
haveyb/php

这个命令解释一下

docker run

运行一个容器

-itd (三个选项的组合)

-i : 保持标准输入打开(interactive)

-t : 分配一个伪终端(tty)

-d : 在后台运行(detached mode)

组合效果 : 让容器在后台运行,但保持交互能力

--name php

设置容器名称 而不是随机生成的容器 ID

--privileged :

给容器赋予特权模式 容器内的进程几乎拥有宿主机的所有权限 可以访问所有设备、执行特权操作

-p 9000:9000 -p9501:9051 -p 宿主机端口:容器端口

一般 9000 用于 PHP-FPM,9501 可能用于 Swoole 或其他服务

-v
~/Code/php/test:/data/test 宿主机路径:容器内路径

将宿主机的 /Code/php/test 目录挂载到容器的 /data/test 目录

效果 : 容器内的 /data 目录实际就是宿主机的代码目录,实现文件同步

--network=haveyb

将容器连接到自定义网络

haveyb 是你创建的 Docker 网络 容器可以与该网络中的其他容器直接通信(通过容器名) 实现容器间的网络隔离和服务发现

拉取openresty镜像【lua加强版Nginx,几乎和Nginx最新稳定版保持一致,已经是超级成熟的项目了】

docker pull openresty/openresty

创建测试站点配置文件

cd ~/Code/docker/nginx/conf.d

创建 gg.conf,内容如下:

展开

server {
    listen 80;
    server_name gg;
    root /data/php/test;
    index index.php index.html;

add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always;

client_max_body_size 10M;

location ~* .(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 30d; add_header Cache-Control "public, max-age=2592000"; try_files $uri =404; }

location ~ .php$ { try_files $uri =404; fastcgi_pass php:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param HTTP_HOST $host; fastcgi_param PHP_VALUE "date.timezone=Asia/Shanghai"; include fastcgi_params; }

location / { try_files $uri $uri/ /index.php?$args; }

access_log /var/log/nginx/gg_access.log; error_log /var/log/nginx/gg_error.log; }

3、创建Nginx容器

创建临时 nginx 容器:

docker run -itd --name temp-nginx openresty/openresty bash

拷贝临时 nginx 容器内的 nginx.conf 到宿主机:

docker cp temp-nginx:/usr/local/openresty/nginx/conf/nginx.conf ~/Code/docker/nginx

删除临时 nginx 容器:

docker rm -f temp-nginx

创建正式 nginx 容器:

docker run -itd --name nginx --privileged 
-p 80:80 -p 443:443 
-v ~/Code:/data 
-v ~/Code/docker/nginx/conf.d:/etc/nginx/conf.d 
-v ~/Code/docker/nginx/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf 
-v ~/Code/docker/nginx/cert:/usr/local/openresty/nginx/cert 
-v ~/Code/docker/nginx/logs:/var/log/nginx 
--network=haveyb 
openresty/openresty

4、注意事项

本地宿主机修改 nginx 或 php 配置文件后,如何加载?重新启动容器

宿主机执行:

docker restart nginx
docker restart php

或者进入相应容器内执行:

nginx -s reload
php-fpm -s reload

需要特别谨慎的点:

由于目录映射的特性,如果宿主机的某个文件或目录与容器内的某个文件或目录通过-v 进行了映射,那么在容器内对映射了的文件或目录进行删除,宿主机的文件或目录也会相应被删除。

因此为了安全起见,所有通过-v 指定映射了的文件或目录,如果要执行删除操作,必定要宿主机执行,由于宿主机是可视化界面,误删的概率要小许多。

SQL 配置MySQL环境

1、进入宿主机待映射文件夹

cd ~/Code/docker

2、创建具体的映射文件夹

mkdir -p mysqldata/{data,logs,conf,pems,conf.d}

3、自定义 my.cnf 文件

cd ~/Code/docker/mysqldata/conf
vi my.cnf
[mysqld]
server-id = 1
log-bin = mysql-bin

4、拉取官方 MySQL9.4镜像

docker pull mysql:9.4

5、创建容器

展开

docker run -itd --name mysql 
-e MYSQL_ROOT_PASSWORD=123456 
-p 3306:3306 
-v ~/Code/docker/mysqldata/data:/var/lib/mysql 
-v ~/Code/docker/mysqldata/logs:/var/log/mysql 
-v ~/Code/docker/mysqldata/conf:/etc/mysql 
-v ~/Code/docker/mysqldata/conf.d:/etc/mysql/conf.d 
-v ~/Code/docker/mysqldata/pems:/etc/mysql/pems 
--restart unless-stopped 
--network=haveyb 
mysql:9.4

--restart unless-stopped 除非手动停止,否则自动重启

当容器退出时,Docker 会自动重新启动它

6、测试MySQL连接

用 navicat 连接时,直接用127.0.0.1,端口号3306,用户名 root,密码123456连接即可

如果在 php 文件中连接 MySQL,host 写 MySQL 容器的容器名称,在这里就是 mysql

配置Redis环境

1、拉取redis镜像

docker pull redis:8.2

2、创建本地映射文件夹

mkdir -p ~/Code/docker/redis/data/logs
touch ~/Code/docker/redis/data/logs/notice.log

3、新建redis.conf文件

cd ~/Code/docker/redis
vi redis.conf
# 设置允许所有ip来连接

bind 0.0.0.0

# 设置端口号

port 6379

# 密码

requirepass 123456

# 保护模式开关,开启时仅允许本地连接或认证连接

protected-mode yes

# 设置日志级别

loglevel notice

# 日志地址

logfile /data/logs/notice.log

# 设置最大内存容量为256MB

maxmemory 256MB

# 内存淘汰策略:从所有键中淘汰最近最少使用的键,最适合缓存场景

maxmemory-policy allkeys-lru

# TCP保活探测间隔(秒),用于检测无效连接

tcp-keepalive 300

# 是否以守护进程方式启动,docker需要配置为no

daemonize no

# 持久化设置

dir /data

# RDB 持久化配置(文件会存放在 /data/dump.rdb)

dbfilename dump.rdb save 900 1

# AOF 持久化配置(文件会存放在 /data/appendonly.aof)

appendonly yes

# AOF文件存储路径

appendfilename appendonly.aof

# AOF 刷盘策略(每秒刷盘,推荐)

appendfsync everysec #加载由于某些缘由导致的末尾异常的 AOF 文件(主进程被 kill/断电等) aof-load-truncated yes

# 开启RDB-AOF混合持久化格式

aof-use-rdb-preamble yes

# 当Aof log增长超过指定百分比例时,重写AOF文件

auto-aof-rewrite-percentage 100

# AOF 重写的最小文件大小(避免小文件频繁重写)

auto-aof-rewrite-min-size 64mb

# 客户端空闲超时时间(秒),0表明永不超时

timeout 0

# PID文件路径,记录Redis进程ID(仅守护进程模式有效)

pidfile /var/run/redis_6379.pid

# 可用数据库的数量,默认16个(编号0-15)

databases 16

# 超过此值的命令会被记录到慢查询日志(微妙,10000微妙=10毫秒=0.01秒,正常命令执行时间一般在1毫秒以内,简单的 GET/SET 甚至只需微秒级)

slowlog-log-slower-than 10000

# 慢查询日志的最大存储条数,超过此条数,新日志会覆盖最旧的日志(FIFO队列 First-In-First-Out Queue,先进先出队列)

slowlog-max-len 128

注:获取 redis8.2默认配置,可通过访问
raw.githubusercontent.com/redis/redis… 获取

4、创建redis容器

docker run -itd --name redis -p 6379:6379 
  -v ~/Code/docker/redis/redis.conf:/etc/redis/redis.conf 
  -v ~/Code/docker/redis/data:/data 
  --network=haveyb 
  redis:8.2 
  redis-server /etc/redis/redis.conf

redis-server /etc/redis/redis.conf 使用自定义配置文件启动 Redis 服务(而不是默认配置)

测试

1、增加宿主机对gg域名的本地解析

编辑本地hosts文件

vi /etc/hosts

添加下面代码

127.0.0.1 gg

2、编辑php测试文件

vi ~/Code/php/test/index.php

内容如下:

展开

<?php
echo "<h1>PHP 环境测试</h1>";
echo "PHP 版本: " . phpversion() . "<br><br>";

echo "<h2>MySQL 连接测试</h2>"; $serverName = "mysql"; $userName = "root"; $password = "123456";

try { $conn = new PDO("mysql:host=$serverName;charset=utf8mb4", $userName, $password); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); echo "MySQL 连接成功: " . $conn->getAttribute(constant("PDO::ATTR_SERVER_VERSION")); } catch(PDOException $e) { echo "MySQL 连接失败: " . $e->getMessage(); }

echo "<br><br>";

echo "<h2>Redis 连接测试</h2>"; $redisHost = "redis"; $redisPort = 6379; $redisPassword = "123456";

if (!class_exists('Redis')) { echo "Redis 扩展未安装,请先安装 Redis 扩展"; } else { $redis = new Redis(); try { $connectResult = $redis->connect($redisHost, $redisPort); if (!$connectResult) { throw new Exception("无法连接到 Redis 服务器"); }

$authResult = $redis->auth($redisPassword); if (!$authResult) { throw new Exception("Redis 认证失败,用户名或密码错误"); }

$redis->set("test_key", "php_redis_test"); $testValue = $redis->get("test_key"); if ($testValue === "php_redis_test") { echo "Redis 连接成功,且可以正常执行命令<br>"; echo "Redis 服务器版本: " . $redis->info()['redis_version']; } else { throw new Exception("Redis 命令执行失败"); } } catch (Exception $e) { echo "Redis 连接失败: " . $e->getMessage(); } finally { if (isset($redis) && $redis->isConnected()) { $redis->close(); } } }

echo "<br><br>"; phpinfo();

访问 http://gg/ 如果有 phpinfo 输出,说明 LNMP 环境配置成功

预期输出结果:

PHP 环境测试
PHP 版本: 8.4.12

MySQL 连接测试 MySQL 连接成功: 9.4.0

Redis 连接测试 Redis 连接成功,且可以正常执行命令 Redis 服务器版本: 8.2.1

phpinfo()相关信息

结语

终于也是写完了,在这里要感谢大佬写出的文档 ,此文主要是总结分享和个人复习使用

以上

谢谢

补充

有一个坑说明一下
背景是我搭建部署了两套PHPMYSQL环境
其中Mysql8的端口映射是3307:3306
我使用navicat走3307连接正常
php走3307连接失败 为什么呢?
是由于容器内网络通信是走容器端口,而非宿主机映射端口
我navicat连宿主机走3307 实际上映射到了3306端口
但PHP项目运行实际上是在容器内,也就是走容器内网络 所以实际上应该是走容器端口3306
  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部