1. 为什么要在macOS上通过Docker部署Nginx+PHP?
作为macOS开发者,我这些年越来越依赖Docker来搭建本地开发环境。传统方式直接在macOS安装Nginx和PHP会遇到各种依赖冲突、版本管理难题。上周帮同事排查一个PHP版本不兼容问题,发现他本地同时安装了5.6和7.4版本,环境变量混乱不堪。而用Docker容器化部署,每个项目都能拥有独立的运行环境,就像给每个应用分配了专属的"房间"。
这种部署方式特别适合:
- 需要快速切换PHP版本的开发者(比如同时维护Laravel 5和Laravel 8项目)
- 团队协作时保证环境一致性(再也不会出现"在我机器上是好的"这种对话)
- 需要隔离生产环境配置的运维人员(用容器模拟生产环境)
2. 环境准备与Docker安装
2.1 选择适合的Docker版本
目前macOS上有两种主流Docker方案:
- Docker Desktop:官方图形化工具(推荐新手使用)
- Colima:命令行方案(适合追求轻量化的开发者)
我建议从Docker Desktop开始,虽然它会占用约1GB内存,但提供了直观的GUI管理界面。安装步骤:
bash复制# 使用Homebrew安装(需提前安装Homebrew)
brew install --cask docker
# 或者直接下载dmg安装包
# 官网下载地址:https://www.docker.com/products/docker-desktop/
安装完成后,在Launchpad中打开Docker应用,菜单栏会出现鲸鱼图标。首次启动需要输入系统密码来创建网络接口。
注意:如果公司网络有严格代理设置,需要在Preferences → Resources → Proxies中配置代理服务器,否则镜像拉取会失败。
2.2 验证Docker安装
打开终端运行:
bash复制docker --version
# 应输出类似:Docker version 20.10.17, build 100c701
docker-compose --version
# 输出:Docker Compose version v2.6.0
如果看到版本号说明安装成功。建议执行一个测试容器:
bash复制docker run hello-world
这个命令会:
- 自动从Docker Hub拉取hello-world镜像
- 创建临时容器并执行
- 输出欢迎信息后自动退出
3. 构建Nginx+PHP容器方案设计
3.1 单容器 vs 多容器架构
常见有两种部署方式:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 单容器(Nginx+PHP同容器) | 部署简单,调试方便 | 不符合单一职责原则,扩容困难 | 快速原型开发 |
| 多容器(Nginx和PHP分离) | 可独立扩展,符合生产实践 | 需要配置容器间通信 | 正式项目开发 |
我推荐使用多容器方案,虽然初次配置稍复杂,但更接近生产环境。下面是我们的架构设计:
code复制用户请求 → Nginx容器(80端口) → PHP-FPM容器(9000端口) → 返回响应
3.2 准备docker-compose.yml
创建项目目录并新建docker-compose.yml:
bash复制mkdir php-nginx-docker && cd php-nginx-docker
touch docker-compose.yml
文件内容框架:
yaml复制version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./code:/var/www/html
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
php:
build: ./php
volumes:
- ./code:/var/www/html
这个配置实现了:
- Nginx监听宿主机8080端口,映射到容器80端口
- PHP使用自定义Dockerfile构建
- 代码目录共享给两个容器
- Nginx配置通过volume挂载
4. PHP容器定制化配置
4.1 创建PHP Dockerfile
新建php目录并创建Dockerfile:
bash复制mkdir php && cd php
touch Dockerfile
推荐使用官方PHP镜像作为基础,这里以PHP 8.1-fpm为例:
dockerfile复制FROM php:8.1-fpm-alpine
# 安装常用扩展
RUN docker-php-ext-install pdo_mysql opcache
# 安装Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 调整PHP配置
COPY php.ini /usr/local/etc/php/conf.d/custom.ini
WORKDIR /var/www/html
这个Dockerfile做了:
- 基于轻量级Alpine系统的PHP 8.1镜像
- 安装MySQL和OPcache扩展
- 集成Composer依赖管理工具
- 加载自定义php.ini配置
4.2 自定义PHP配置
创建php.ini文件覆盖默认配置:
ini复制[Date]
date.timezone = Asia/Shanghai
[OPcache]
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
[Session]
session.gc_maxlifetime=1440
这些配置优化了:
- 时区设置(避免日志时间混乱)
- OPcache性能(适合开发环境)
- Session过期时间
5. Nginx配置调优
5.1 基础Nginx配置
创建nginx.conf文件:
nginx复制server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
关键配置解析:
fastcgi_pass php:9000:请求转发到php容器的9000端口SCRIPT_FILENAME:确保PHP能找到正确的脚本路径try_files:实现前端控制器模式(适合Laravel等框架)
5.2 性能优化配置
在server块中添加这些配置:
nginx复制# 启用gzip压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
}
6. 项目结构与启动
6.1 创建示例PHP应用
在code目录下创建测试文件:
bash复制mkdir code && cd code
echo "<?php phpinfo();" > index.php
目录结构最终应该是:
code复制php-nginx-docker/
├── docker-compose.yml
├── nginx.conf
├── php/
│ ├── Dockerfile
│ └── php.ini
└── code/
└── index.php
6.2 启动与验证
运行以下命令启动服务:
bash复制docker-compose up -d --build
这个过程会:
- 构建PHP镜像(根据Dockerfile)
- 拉取Nginx镜像
- 创建并启动两个容器
验证服务:
- 访问 http://localhost:8080 应该看到phpinfo页面
- 检查容器运行状态:
bash复制docker-compose ps
应该看到两个容器状态为"Up"。
7. 开发环境实用技巧
7.1 Xdebug配置(调试必备)
修改php/Dockerfile添加:
dockerfile复制RUN apk add --no-cache $PHPIZE_DEPS \
&& pecl install xdebug \
&& docker-php-ext-enable xdebug
新建xdebug.ini:
ini复制[xdebug]
xdebug.mode=develop,debug
xdebug.client_host=host.docker.internal
xdebug.start_with_request=yes
xdebug.discover_client_host=1
xdebug.log=/var/log/xdebug.log
在VSCode中配置launch.json:
json复制{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}/code"
}
}
]
}
7.2 常用运维命令
bash复制# 查看容器日志
docker-compose logs -f nginx
# 进入PHP容器
docker-compose exec php sh
# 重新构建PHP镜像
docker-compose build php
# 清理无用镜像
docker image prune -a
8. 常见问题排查
8.1 502 Bad Gateway错误
可能原因及解决方案:
-
PHP-FPM未运行:
bash复制docker-compose exec php ps aux应该能看到php-fpm进程
-
Nginx配置错误:
检查fastcgi_pass地址是否正确指向php容器 -
文件权限问题:
bash复制docker-compose exec php chown -R www-data:www-data /var/www/html
8.2 性能优化建议
-
OPcache配置:
在php.ini中调整:ini复制opcache.revalidate_freq=0 opcache.enable_cli=1 -
Nginx worker进程:
在nginx.conf顶部添加:nginx复制worker_processes auto; events { worker_connections 1024; } -
启用HTTP/2:
修改docker-compose.yml中nginx的ports:yaml复制ports: - "8080:80" - "8443:443"
9. 生产环境注意事项
如果需要部署到生产环境,还需要考虑:
-
安全加固:
- 禁用phpinfo等调试信息
- 限制Nginx直接访问敏感文件
- 定期更新基础镜像
-
数据持久化:
yaml复制volumes: php-session-data: mysql-data: -
监控方案:
- 添加Prometheus监控
- 配置日志收集
- 设置健康检查
这套方案我已经在团队内部使用了2年多,最大的感受是再也不用担心"在我机器上能跑"的问题。新成员入职只需要git clone项目代码,运行docker-compose up就能获得完全一致的开发环境。对于PHP版本切换,只需要修改Dockerfile中的基础镜像版本即可,真正实现了"一次配置,到处运行"。