前言
对于个人站长和中小团队来说,LNMP(Linux + Nginx + MySQL + PHP)依然是最经典的 Web 服务组合。然而传统的手动编译安装或一键面板方式,往往会遇到环境不一致、迁移困难、版本管理混乱等问题。Docker 容器化技术的出现,彻底改变了这一局面。
本文将手把手教你如何使用 Docker Compose 从零搭建一套生产可用的 LNMP 环境,涵盖 Nginx、MySQL 8.0、PHP 8.2(含常见扩展)以及 Redis 的容器化部署。
Docker 与 Docker Compose 简介
Docker 是一个开源的容器化平台,它可以将应用及其依赖打包到一个轻量级、可移植的容器中。与传统的虚拟机不同,Docker 容器共享宿主机的操作系统内核,启动速度更快,资源占用更小。
Docker Compose 则是 Docker 官方推出的多容器编排工具,通过一个 YAML 文件定义和运行多个容器。对于 LNMP 这种多服务架构,Compose 可以让我们一键启动所有服务。
第一步:安装 Docker 和 Docker Compose
在开始之前,我们需要在服务器上安装 Docker 环境。以下是在 Ubuntu 22.04 上的安装步骤:
# 更新包索引
sudo apt update
# 安装依赖包
sudo apt install -y ca-certificates curl gnupg lsb-release
# 添加 Docker 官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# 设置 Docker 仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装 Docker 和 Docker Compose
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 将当前用户加入 docker 组(避免每次 sudo)
sudo usermod -aG docker $USER
# 重新登录后生效,或者使用 newgrp docker安装完成后,验证版本:
docker --version
docker compose version第二步:规划项目目录结构
一个良好的目录结构能让后续维护变得轻松。我们在 /opt/lnmp 下创建以下结构:
/opt/lnmp/
├── docker-compose.yml # 容器编排文件
├── nginx/
│ ├── Dockerfile # Nginx 自定义镜像
│ ├── conf.d/
│ │ └── default.conf # Nginx 站点配置
│ └── logs/ # 日志目录
├── php/
│ ├── Dockerfile # PHP 自定义镜像
│ └── php.ini # PHP 配置文件
├── mysql/
│ ├── conf.d/
│ │ └── my.cnf # MySQL 配置文件
│ └── data/ # 数据持久化目录
├── redis/
│ ├── redis.conf # Redis 配置文件
│ └── data/ # Redis 持久化目录
└── www/
└── your-site/ # 网站代码目录创建目录:
mkdir -p /opt/lnmp/{nginx/{conf.d,logs},php,mysql/{conf.d,data},redis/{data},www/your-site}第三步:编写 Docker Compose 配置文件
docker-compose.yml 是整个 LNMP 环境的核心编排文件,它定义了四个服务:Nginx、PHP-FPM、MySQL 和 Redis。
version: '3.8'
services:
nginx:
image: nginx:1.25-alpine
container_name: lnmp-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/logs:/var/log/nginx
- ./www:/var/www
depends_on:
- php
networks:
- lnmp-network
restart: always
php:
build: ./php
container_name: lnmp-php
volumes:
- ./www:/var/www
- ./php/php.ini:/usr/local/etc/php/php.ini
networks:
- lnmp-network
restart: always
mysql:
image: mysql:8.0
container_name: lnmp-mysql
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf.d:/etc/mysql/conf.d
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
MYSQL_DATABASE: ${MYSQL_DATABASE:-wordpress}
MYSQL_USER: ${MYSQL_USER:-wpuser}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-wppass}
networks:
- lnmp-network
restart: always
redis:
image: redis:7-alpine
container_name: lnmp-redis
ports:
- "6379:6379"
volumes:
- ./redis/data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
networks:
- lnmp-network
restart: always
networks:
lnmp-network:
driver: bridge这里有几个设计要点值得注意。第一,所有服务都连接到同一个自定义网络 lnmp-network,这样容器之间可以通过服务名相互访问(例如 PHP 代码中连接数据库可以使用 lnmp-mysql 作为主机名)。第二,MySQL 和 Redis 的数据目录映射到宿主机,确保容器重启后数据不丢失。第三,使用 ${} 环境变量占位符配合 .env 文件,让敏感配置与编排文件分离。
第四步:配置 Nginx 和 PHP
Nginx 站点配置
创建 /opt/lnmp/nginx/conf.d/default.conf:
server {
listen 80;
server_name your-domain.com;
root /var/www/your-site/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 日志配置
access_log /var/log/nginx/your-site_access.log;
error_log /var/log/nginx/your-site_error.log;
}关键点是 fastcgi_pass php:9000,这里使用了服务名 php 而不是 IP 地址,Docker 内置 DNS 会自动解析到 PHP 容器的 IP。
PHP Dockerfile
创建 /opt/lnmp/php/Dockerfile:
FROM php:8.2-fpm-alpine
# 安装系统依赖
RUN apk add --no-cache libzip-dev oniguruma-dev libpng-dev libjpeg-turbo-dev freetype-dev libxml2-dev curl-dev
# 安装 PHP 扩展
RUN docker-php-ext-install pdo_mysql mysqli mbstring exif pcntl bcmath gd zip opcache intl
# 安装 Redis 扩展
RUN pecl install redis && docker-php-ext-enable redis
# 安装 Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# 配置 OPcache
RUN docker-php-ext-enable opcache
WORKDIR /var/wwwPHP 8.2 的 Alpine 镜像非常精简,通过 docker-php-ext-install 命令可以方便地安装所需的扩展。这里我们安装了生产环境中常用的扩展,包括 pdo_mysql、gd、zip 和 redis。
PHP 性能配置
创建 /opt/lnmp/php/php.ini:
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
memory_limit = 256M
date.timezone = Asia/Shanghai
[opcache]
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1第五步:配置 MySQL 和 Redis
MySQL 配置
创建 /opt/lnmp/mysql/conf.d/my.cnf:
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
max_connections = 500
innodb_buffer_pool_size = 512M
innodb_log_file_size = 256M
skip-name-resolve
default-time-zone = +08:00
[client]
default-character-set = utf8mb4skip-name-resolve 可以跳过 DNS 反向解析,加快连接速度,在容器环境中特别有用。
Redis 配置
创建 /opt/lnmp/redis/redis.conf:
requirepass YourRedisPass123
bind 0.0.0.0
port 6379
databases 16
save 900 1
save 300 10
save 60 10000
maxmemory 256mb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec第六步:启动 LNMP 环境
所有配置文件准备就绪后,只需一行命令即可启动:
cd /opt/lnmp
# 创建 .env 文件
cat > .env << EOF
MYSQL_ROOT_PASSWORD=YourRootPass123
MYSQL_DATABASE=myblog
MYSQL_USER=bloguser
MYSQL_PASSWORD=BlogPass456
EOF
# 启动所有服务
docker compose up -d
# 查看运行状态
docker compose ps
# 查看日志
docker compose logs -f首次启动时会构建 PHP 镜像,可能需要几分钟时间。之后再次启动只需几秒钟。
第七步:验证 LNMP 环境
在 /opt/lnmp/www/your-site/public/ 下创建一个 info.php 文件:
<?php
phpinfo();然后在浏览器中访问 http://your-server-ip/info.php,如果能看到 PHP 信息页面,说明 LNMP 环境搭建成功。
接着测试数据库连接:
<?php
try {
$pdo = new PDO('mysql:host=lnmp-mysql;dbname=myblog;charset=utf8mb4', 'bloguser', 'BlogPass456');
echo 'MySQL 连接成功!';
} catch (PDOException $e) {
echo '连接失败: ' . $e->getMessage();
}测试 Redis 连接:
<?php
$redis = new Redis();
$redis->connect('lnmp-redis', 6379);
$redis->auth('YourRedisPass123');
$redis->set('test', 'Hello Docker LNMP');
echo $redis->get('test');日常运维命令
# 停止所有服务
docker compose down
# 重启某个服务
docker compose restart nginx
# 查看实时日志
docker compose logs -f php
# 进入容器内部
docker compose exec php bash
# 重新构建镜像(配置文件改动后)
docker compose build php
docker compose up -d总结
通过 Docker 容器化部署 LNMP 环境,我们获得了以下几点优势:
- 环境一致性:开发、测试、生产环境完全一致,告别「在我机器上能跑」的尴尬
- 快速部署:新服务器上初始化 LNMP 只需几分钟
- 易于扩展:需要增加 PHP 版本?加一个容器即可,互不干扰
- 资源隔离:每个服务运行在独立容器中,一个服务挂了不影响其他
- 便于迁移:打包整个项目目录到新服务器,一行命令恢复所有服务
这套方案已经在多台生产服务器上稳定运行超过一年,经受住了日均数万 PV 的考验。如果你是个人站长或小团队运维,不妨从今天开始拥抱容器化吧。