Docker从零到一部署DNMPR
前几天把本机的mac格式化了,原因是环境太乱了,什么东西都往里装,格式化后就想着重新安装开发工具和部署环境,不想再去下载那些集成环境了(XAMPP+MAMP),就想着自己用Docker重新部署一套适合自己的环境。 (ps.真的很搞,我手里php项目有两个不同环境的,还有一个要准备升级)
混乱翻查资料的时候看到了一个博客,《十分钟部署PHP+NGINX+MYSQL+REDIS》,尝试跟着部署了一遍,没想到真的成了,转载大佬的笔记,并在这里重新梳理和总结记录一下,造福后人hh
首先安装Docker
            
            
              json
              
              
            
          
          这个不用多说吧,自己去 https://www.docker.com/ 下载一个docker 版本自己选
安装完成后部署环境变量 输入命令 docker -v 查看版本
我的版本是Docker version 28.5.1, build e180ab8
在配置里直接新增以下国内加速地址
"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容器中和宿主机的文件映射
创建服务配置文件夹
            
            
              js
              
              
            
          
          mkdir -p ~/Code/docker/php
mkdir -p ~/Code/docker/nginx/{conf.d,cert,logs}
        这里是建立环境服务的配置文件地址,用于创建容器时设置文件映射和配置调整
拉取PHP镜像
            
            
              bash
              
              
            
          
          docker pull haveyb/php《大佬》
该镜像是这个大佬以php官方php-fpm:8.4.12为基础,添加了一些常用扩展
yar、redis、swoole、pdo_mysql、gd、pcntl、sockets、igbinary、msgpack、zstd、pdo_pgsql、xsl、zip、
bcmath、sysvmsg、sysvsem、sysvshm
为debian apt设置了默认阿里国内镜像源
添加了composer为当前最新稳定版本2.8.11,并为composer也配置了阿里国内镜像源。
        
            
            
              js
              
              
            
          
          docker run -itd --name temp-php haveyb/php bash
docker cp temp-php:/usr/local/etc/php/php.ini ~/Code/docker/php
        创建临时容器 并将临时容器中的php.ini拷贝至映射目录下
            
            
              bash
              
              
            
          
          docker rm -f temp-php
        完成后清除目录
创建PHP正式容器
            
            
              js
              
              
            
          
          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最新稳定版保持一致,已经是非常成熟的项目了】
            
            
              bash
              
              
            
          
          docker pull openresty/openresty
        创建测试站点配置文件
            
            
              bash
              
              
            
          
          cd ~/Code/docker/nginx/conf.d
        创建gg.conf,内容如下:
展开
            
            
              bash
              
              
            
          
          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;
    }
    # PHP脚本处理
    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容器:
            
            
              arduino
              
              
            
          
          docker run -itd --name temp-nginx openresty/openresty bash
        拷贝临时nginx容器内的nginx.conf到宿主机:
            
            
              javascript
              
              
            
          
          docker cp temp-nginx:/usr/local/openresty/nginx/conf/nginx.conf ~/Code/docker/nginx
        删除临时nginx容器:
            
            
              bash
              
              
            
          
          docker rm -f temp-nginx
        创建正式nginx容器:
            
            
              ruby
              
              
            
          
          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指定映射了的文件或目录,如果要执行删除操作,一定要宿主机执行,因为宿主机是可视化界面,误删的概率要小很多。
配置MySQL环境
1、进入宿主机待映射文件夹
            
            
              bash
              
              
            
          
          cd ~/Code/docker
        2、创建具体的映射文件夹
            
            
              arduino
              
              
            
          
          mkdir -p mysqldata/{data,logs,conf,pems,conf.d}
        3、自定义 my.cnf 文件
            
            
              bash
              
              
            
          
          cd ~/Code/docker/mysqldata/conf
        vi my.cnf
        
            
            
              ini
              
              
            
          
          [mysqld]
server-id = 1
log-bin = mysql-bin
        4、拉取官方 MySQL9.4镜像
docker pull mysql:9.4
        5、创建容器
展开
            
            
              ruby
              
              
            
          
          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、创建本地映射文件夹
            
            
              bash
              
              
            
          
          mkdir -p ~/Code/docker/redis/data/logs
touch ~/Code/docker/redis/data/logs/notice.log
        3、新建redis.conf文件
            
            
              bash
              
              
            
          
          cd ~/Code/docker/redis
vi redis.conf
        
            
            
              js
              
              
            
          
          # 设置允许所有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容器
            
            
              javascript
              
              
            
          
          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文件
            
            
              bash
              
              
            
          
          vi /etc/hosts
        添加下面代码
127.0.0.1           gg
        2、编辑php测试文件
            
            
              javascript
              
              
            
          
          vi ~/Code/php/test/index.php
        内容如下:
展开
            
            
              php
              
              
            
          
          <?php
echo "<h1>PHP 环境测试</h1>";
echo "PHP 版本: " . phpversion() . "<br><br>";
// 测试MySQL连接
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>";
// 测试Redis连接
echo "<h2>Redis 连接测试</h2>";
$redisHost = "redis";
$redisPort = 6379;
$redisPassword = "123456";
// 检查Redis扩展是否安装
if (!class_exists('Redis')) {
    echo "Redis 扩展未安装,请先安装 Redis 扩展";
} else {
    $redis = new Redis();
    try {
        // 连接Redis服务器
        $connectResult = $redis->connect($redisHost, $redisPort);
        if (!$connectResult) {
            throw new Exception("无法连接到Redis服务器");
        }
        // 使用ACL用户名和密码进行认证
        // 注意:Redis 6.0+ 支持用户名+密码认证,旧版本仅支持密码
        $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环境配置成功
预期输出结果:
            
            
              css
              
              
            
          
          PHP 环境测试
PHP 版本: 8.4.12
MySQL 连接测试
MySQL 连接成功: 9.4.0
Redis 连接测试
Redis 连接成功,且可以正常执行命令
Redis 服务器版本: 8.2.1
phpinfo()相关信息
        结语
终于也是写完了,在这里要感谢大佬写出的文档,此文主要是总结分享和个人复习使用
以上
谢谢