第五部分-DockerCompose——26. 实战:LNMP 应用编排
26. 实战LNMP 应用编排1. 项目概述LNMPLinux Nginx MySQL PHP是经典的 Web 应用架构。本实战将使用 Docker Compose 完整编排 LNMP 环境包括 Nginx、PHP-FPM、MySQL 和 phpMyAdmin。┌─────────────────────────────────────────────────────────────┐ │ LNMP 架构图 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 用户请求 │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Nginx (80) │ │ │ │ - 静态文件处理 │ │ │ │ - 反向代理到 PHP │ │ │ └─────────────────────┬───────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ PHP-FPM (9000) │ │ │ │ - PHP 代码解析 │ │ │ │ - 业务逻辑处理 │ │ │ └─────────────────────┬───────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ MySQL (3306) │ │ │ │ - 数据存储 │ │ │ │ - 数据查询 │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘2. 项目结构lnmp/ ├── docker-compose.yml ├── .env ├── nginx/ │ ├── Dockerfile │ └── conf.d/ │ └── app.conf ├── php/ │ ├── Dockerfile │ └── php.ini ├── mysql/ │ └── my.cnf ├── www/ │ └── index.php └── logs/ ├── nginx/ └── php/3. Docker Compose 配置3.1 主配置文件# docker-compose.ymlversion:3.8services:# Nginx 服务nginx:build:context:./nginxdockerfile:Dockerfilecontainer_name:lnmp-nginxports:-${NGINX_PORT:-80}:80volumes:-./www:/var/www/html-./logs/nginx:/var/log/nginxdepends_on:-phpnetworks:-lnmp-netrestart:alwaysenvironment:-TZAsia/Shanghai# PHP-FPM 服务php:build:context:./phpdockerfile:Dockerfilecontainer_name:lnmp-phpvolumes:-./www:/var/www/html-./logs/php:/var/log/phpdepends_on:mysql:condition:service_healthynetworks:-lnmp-netrestart:alwaysenvironment:-TZAsia/Shanghai-PHP_FPM_PMdynamic-PHP_FPM_MAX_CHILDREN50# MySQL 服务mysql:image:mysql:8.0container_name:lnmp-mysqlports:-${MYSQL_PORT:-3306}:3306volumes:-mysql-data:/var/lib/mysql-./mysql/my.cnf:/etc/mysql/conf.d/my.cnf-./mysql/init:/docker-entrypoint-initdb.denvironment:-MYSQL_ROOT_PASSWORD${MYSQL_ROOT_PASSWORD}-MYSQL_DATABASE${MYSQL_DATABASE}-MYSQL_USER${MYSQL_USER}-MYSQL_PASSWORD${MYSQL_PASSWORD}-TZAsia/Shanghainetworks:-lnmp-netrestart:alwayshealthcheck:test:[CMD,mysqladmin,ping,-h,localhost]interval:10stimeout:5sretries:5start_period:30s# phpMyAdmin可选phpmyadmin:image:phpmyadmin/phpmyadmincontainer_name:lnmp-phpmyadminports:-${PHPMYADMIN_PORT:-8080}:80environment:-PMA_HOSTmysql-PMA_PORT3306-UPLOAD_LIMIT100Mdepends_on:mysql:condition:service_healthynetworks:-lnmp-netrestart:alwaysprofiles:-devnetworks:lnmp-net:driver:bridgevolumes:mysql-data:3.2 环境变量文件# .env# NginxNGINX_PORT80# MySQLMYSQL_PORT3306MYSQL_ROOT_PASSWORDroot123MYSQL_DATABASElnmp_dbMYSQL_USERlnmp_userMYSQL_PASSWORDlnmp_pass# phpMyAdminPHPMYADMIN_PORT8080# 其他TZAsia/Shanghai4. Nginx 配置4.1 Nginx Dockerfile# nginx/Dockerfile FROM nginx:alpine # 安装依赖 RUN apk add --no-cache curl # 复制配置文件 COPY conf.d/app.conf /etc/nginx/conf.d/default.conf # 创建日志目录 RUN mkdir -p /var/log/nginx \ touch /var/log/nginx/access.log \ touch /var/log/nginx/error.log # 暴露端口 EXPOSE 80 # 健康检查 HEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 \ CMD curl -f http://localhost/ || exit 14.2 Nginx 配置文件# nginx/conf.d/app.conf server { listen 80; server_name localhost; root /var/www/html; index index.php index.html; # 日志配置 access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # 静态文件缓存 location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ { expires 30d; add_header Cache-Control public, immutable; } # PHP 请求转发 location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; # 超时设置 fastcgi_connect_timeout 60s; fastcgi_send_timeout 60s; fastcgi_read_timeout 60s; } # 默认首页 location / { try_files $uri $uri/ /index.php?$args; } # 禁止访问隐藏文件 location ~ /\. { deny all; } }5. PHP 配置5.1 PHP Dockerfile# php/Dockerfile FROM php:8.0-fpm-alpine # 安装 PHP 扩展 RUN docker-php-ext-install pdo_mysql mysqli # 安装 Composer COPY --fromcomposer:latest /usr/bin/composer /usr/bin/composer # 复制 PHP 配置 COPY php.ini /usr/local/etc/php/conf.d/custom.ini # 创建日志目录 RUN mkdir -p /var/log/php \ chown -R www-data:www-data /var/log/php # 安装常用工具 RUN apk add --no-cache git unzip curl # 切换用户 USER www-data # 健康检查 HEALTHCHECK --interval30s --timeout3s --start-period10s --retries3 \ CMD php -v || exit 15.2 PHP 配置文件# php/php.ini [PHP] # 时区 date.timezone Asia/Shanghai # 错误报告 error_reporting E_ALL ~E_DEPRECATED ~E_STRICT display_errors Off display_startup_errors Off log_errors On error_log /var/log/php/error.log # 上传限制 upload_max_filesize 20M post_max_size 20M max_file_uploads 20 # 内存限制 memory_limit 128M # 执行时间 max_execution_time 30 max_input_time 60 # Session session.save_path /tmp # OpCache opcache.enable 1 opcache.memory_consumption 128 opcache.interned_strings_buffer 8 opcache.max_accelerated_files 4000 opcache.revalidate_freq 60 # FPM 配置 pm dynamic pm.max_children 50 pm.start_servers 5 pm.min_spare_servers 5 pm.max_spare_servers 356. MySQL 配置# mysql/my.cnf [mysqld] # 基础配置 server-id 1 port 3306 # 字符集 character-set-server utf8mb4 collation-server utf8mb4_unicode_ci # 日志 log_error /var/log/mysql/error.log slow_query_log 1 slow_query_log_file /var/log/mysql/slow.log long_query_time 2 # 性能优化 max_connections 200 innodb_buffer_pool_size 256M innodb_log_file_size 128M innodb_flush_log_at_trx_commit 2 # 临时表 tmp_table_size 32M max_heap_table_size 32M # 查询缓存MySQL 8.0 已移除但保留配置 # query_cache_type 0 [client] default-character-set utf8mb47. PHP 应用示例7.1 测试文件!--www/index.php--!DOCTYPEhtmlhtmlheadtitleLNMPDocker 环境/titlemeta charsetutf-8stylebody{font-family:Arial;margin:40px;}.info{background:#f0f0f0; padding: 20px; border-radius: 5px; }h1{color:#333; }pre{background:#fff; padding: 10px; overflow: auto; }/style/headbodyh1✅LNMPDocker 环境运行成功/h1divclassinfoh2系统信息/h2?phpechopstrongPHP 版本:/strong .phpversion()./p;echopstrong服务器软件:/strong .$_SERVER[SERVER_SOFTWARE]./p;echopstrong运行时间:/strong .date(Y-m-d H:i:s)./p;?h2MySQL 连接测试/h2?phptry{$pdonewPDO(mysql:hostmysql;dbnamelnmp_db;charsetutf8mb4,lnmp_user,lnmp_pass);// 创建测试表$pdo-exec(CREATE TABLE IF NOT EXISTS test ( id INT AUTO_INCREMENT PRIMARY KEY, message VARCHAR(255), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ));// 插入测试数据$stmt$pdo-prepare(INSERT INTO test (message) VALUES (?));$stmt-execute([Hello from Docker LNMP!]);// 查询数据$result$pdo-query(SELECT * FROM test ORDER BY id DESC LIMIT 5);echop stylecolor:green✅ MySQL 连接成功/p;echoh3最近记录/h3;echoul;while($row$result-fetch(PDO::FETCH_ASSOC)){echoliID:{$row[id]}-{$row[message]}-{$row[created_at]}/li;}echo/ul;}catch(PDOException$e){echop stylecolor:red❌ MySQL 连接失败: .$e-getMessage()./p;}?h2PHP扩展/h2pre?phpprint_r(get_loaded_extensions());?/pre/div/body/html8. 启动与管理8.1 启动服务# 创建目录结构mkdir-pwww logs/nginx logs/php mysql/init# 复制测试文件cpindex.php www/# 构建并启动docker-composeup-d# 查看状态docker-composeps# 查看日志docker-composelogs-f# 进入容器docker-composeexecphpbashdocker-composeexecmysqlbash# 查看 Nginx 访问日志docker-composeexecnginxcat/var/log/nginx/access.log8.2 常用命令# 重启服务docker-composerestart# 停止服务docker-composestop# 停止并删除docker-composedown# 停止并删除卷清理数据docker-composedown-v# 重新构建docker-composebuild --no-cachedocker-composeup-d--build# 查看资源使用docker-composetopdockerstats# 执行 PHP 脚本docker-composeexecphp php-vdocker-composeexecphpcomposerinstall9. 性能优化9.1 生产环境配置# docker-compose.prod.ymlversion:3.8services:nginx:restart:alwayslogging:driver:json-fileoptions:max-size:10mmax-file:3deploy:resources:limits:cpus:0.5memory:256Mphp:restart:alwayslogging:driver:json-fileoptions:max-size:10mmax-file:3deploy:resources:limits:cpus:1memory:512Menvironment:-PHP_FPM_MAX_CHILDREN20mysql:restart:alwayslogging:driver:json-fileoptions:max-size:10mmax-file:3deploy:resources:limits:cpus:1memory:1G9.2 压力测试# 使用 ab 进行压力测试ab-n1000-c10http://localhost/# 使用 wrkwrk-t4-c100-d30shttp://localhost/# 监控容器资源dockerstats lnmp-nginx lnmp-php lnmp-mysql10. 故障排查# 检查容器状态docker-composeps# 查看详细日志docker-composelogs nginxdocker-composelogs phpdocker-composelogs mysql# 检查 PHP-FPMdocker-composeexecphp php-fpm-t# 检查 Nginx 配置docker-composeexecnginx nginx-t# 测试 MySQL 连接docker-composeexecmysql mysql-uroot-p-eSHOW DATABASES# PHP 连接测试docker-composeexecphp php-rnew PDO(mysql:hostmysql;dbnamelnmp_db, lnmp_user, lnmp_pass);11. 扩展示例11.1 Redis 缓存services:redis:image:redis:alpinecontainer_name:lnmp-redisvolumes:-redis-data:/datanetworks:-lnmp-netvolumes:redis-data:11.2 Node.js 服务services:node:build:./nodecontainer_name:lnmp-nodeports:-3000:3000networks:-lnmp-net12. 小结完整 LNMP 环境Nginx PHP-FPM MySQL配置文件分离每个服务独立配置健康检查确保服务可用性数据持久化MySQL 数据使用卷日志管理统一日志收集性能优化资源限制和缓存配置易于扩展可添加 Redis、Node.js 等服务