使用Docker部署LNMP环境与WordPress

前言

官方也提供了WordPress镜像,官方镜像中通常已经集成了PHP和Apache,若仅部署WordPress可以考虑使用官方镜像。

使用Docker部署LNMP环境与WordPress有许多好处:

  • 环境一致性与隔离性​:无论宿主机环境均可保证一致性,容器间影响小
  • 快速部署与跑路:使用Docker Compose一键部署应用,同时数据文件集中,方便一键打包跑路
  • 快速更新与回滚:重新下载镜像即可实现升级/降级
  • 安全性与资源控制​:隔离环境
  • ​测试与开发效率​:随时重建容器
  • 轻微的性能损失

基础准备

安装Docker与Docker Compose

注意:由于网络限制官方安装教程可能无法成功安装,建议使用云服务商都提供的镜像安装Docker的方法。

参考教程安装Docker与Docker Compose:

检查docker是否安装:

docker info
docker compose version

设置Docker镜像源

注意:绝大部分云服务商的Docker镜像加速源只支持内网访问。

更多Docker镜像源可以参考Docker Hub 镜像加速器

检查Docker镜像源:

docker info

Registry Mirrors中应为设置的镜像。

启用Docker的用户命名空间重映射(userns-remap)(可选)

启用用户命名空间重映射可以有效提升容器安全性。它通过 Linux 的用户命名空间(User Namespace)​​ 技术,实现了容器内用户与宿主机用户的隔离和映射,将容器中的UID/GID重新映射到宿主机不同的UID/GID

编辑/etc/docker/daemon.json,添加以下内容:

{
    "userns-remap": "default",
}

重启Docker:

systemctl restart docker

检查是否启用:

cat /etc/subuid

输出结果应该类似于:

dockremap:100000:65536

其中dockremap​​为宿主机上的系统用户名,100000为起始子UID/GID​​,表示映射范围的起始值,65536为ID数量​​,表示从起始值开始连续分配多少个 UID/GID 给该用户。因此相当于容器中UID/GID的0~65536被映射为了宿主机中的100000~165536,容器内的 rootUID 0)会被映射到宿主机的100000,容器内的UID 1映射到 100001,依此类推。

提前拉取镜像(可选)

提前拉取镜像以避免后续创建容器时拉取镜像:

docker pull nginx:1.28.0-alpine3.21
docker pull php:8.3.25-fpm-alpine3.21
docker pull mariadb:11.8.3

构建镜像

此处以nginx:1.28.0php:8.3.25-fpmmariadb:11.8.3为例构建所需镜像。

Nginx

版本选择

同一个Nginx版本存在多个版本的镜像可选,以Nginx版本1.28.0为例,标签中的含义为:

perl镜像中启用了 ​​Perl 模块
otel镜像集成了 ​​OpenTelemetry(OTel)​​ 支持
bookworm基于 Debian 12(代号 bookworm)的镜像
slim基于 ​​Debian 的精简版
alpine/alpine3.21/alpine3.22基于 Alpine Linux 的镜像

此处选择nginx:1.28.0-alpine3.21

构建Nginx镜像

Web服务器通常使用www-data用户,但nginx镜像中默认没有www-data用户,但有www-data用户组,因此需要创建www-data用户并加入www-data用户组,编写Dockerfile

FROM nginx:1.28.0-alpine3.21

RUN adduser -u 82 -S -G www-data www-data

并在Dockerfile同级目录下构建镜像:

docker build -t nginxm:1.28 .

PHP

版本选择

和Nginx类似,同一个PHP版本也存在多个版本的镜像可选,以PHP版本8.3.25为例,标签中的含义为:

fpm使用 ​​PHP-FPM​​作为运行模式,适合与 Nginx/Apache 配合
cli仅包含 PHP 的命令行接口,适合脚本或命令行工具,​​不包含 Web 服务器集成​​
apache镜像内预装了 ​​Apache HTTP Server​​,PHP 作为 Apache 模块运行
zts启用 ​​Zend Thread Safety​​(线程安全)的 PHP 版本
bookworm基于 Debian 12(代号 bookworm)的镜像
trixie基于 Debian 13(代号 trixie )的镜像
alpine/alpine3.21/alpine3.22基于 Alpine Linux 的镜像

此处选择php:8.3.25-fpm-alpine3.21

添加扩展

已经编译的扩展

官方镜像中默认编译了一部分扩展,可以通过以下指令查看容器中已经编译的扩展:

docker run --rm <PHP镜像名称> php -m

例如,查看php:8.3.25-fpm-alpine3.21已经编译的扩展docker run --rm php:8.3.25-fpm-alpine3.21 php -m

core ctype curl date dom fileinfo filter hash iconv json libxml mbstring mysqlnd openssl pcre pdo pdo_sqlite phar posix random readline reflection session simplexml sodium spl sqlite3 standard tokenizer xml xmlreader xmlwriter opcache zlib
核心扩展

在官方镜像中还提供了安装核心扩展的脚本docker-php-ext-configuredocker-php-ext-installdocker-php-ext-enable

查看docker-php-ext-install的用法、支持的扩展:

docker run --rm <PHP镜像名称> docker-php-ext-install -h

例如查看php:8.3.25-fpm-alpine3.21支持的扩展docker run --rm php:8.3.25-fpm-alpine3.21 docker-php-ext-install -h

usage: /usr/local/bin/docker-php-ext-install [-jN] [--ini-name file.ini] ext-name [ext-name ...]
   ie: /usr/local/bin/docker-php-ext-install gd mysqli
       /usr/local/bin/docker-php-ext-install pdo pdo_mysql
       /usr/local/bin/docker-php-ext-install -j5 gd mbstring mysqli pdo pdo_mysql shmop

if custom ./configure arguments are necessary, see docker-php-ext-configure

Possible values for ext-name:
bcmath bz2 calendar ctype curl dba dl_test dom enchant exif ffi fileinfo filter ftp gd gettext gmp hash iconv imap intl json ldap mbstring mysqli oci8 odbc opcache pcntl pdo pdo_dblib pdo_firebird pdo_mysql pdo_oci pdo_odbc pdo_pgsql pdo_sqlite pgsql phar posix pspell random readline reflection session shmop simplexml snmp soap sockets sodium spl standard sysvmsg sysvsem sysvshm tidy tokenizer xml xmlreader xmlwriter xsl zend_test zip

Some of the above modules are already compiled into PHP; please check
the output of "php -i" to see which modules are already loaded.

需要注意,安装某些扩展可能需要提前手动安装一些库:

扩展可能需要额外安装的库Alpine命令
intlicu-devicu-data-fullicu-libsapk add --no-cache icu-dev icu-data-full icu-libs
ziplibzip-devlibzipapk add --no-cache libzip-dev libzip
gd(含jepg、png、webp、avif)libjpeg-turbo-devlibpng-devlibwebp-devlibheif-devlibavif-devfreetype-devzlib-devapk add --no-cache libjpeg-turbo libpng libwebp libheif-dev libavif-dev freetype-dev zlib-dev
gmpgmp-devgmpapk add --no-cache gmp-dev gmp

安装扩展时可以先使用docker run --rm -it php:8.3.25-fpm-alpine3.21 sh创建一个临时容器进行测试,根据提示安装所需要的包。某些扩展在安装时还需要运行docker-php-ext-configure,安装完成后还需要使用docker-php-ext-enable使能扩展。以安装gd为例

apk add --no-cache libjpeg-turbo-dev libpng-dev libwebp-dev libheif-dev libavif-dev freetype-dev zlib-dev
docker-php-ext-configure gd --with-jpeg --with-webp --with-avif --with-freetype
docker-php-ext-install -j$(nproc) gd
docker-php-ext-enable gd
其他扩展

官方镜像可以使用pecl install命令安装其他扩展。安装其他扩展时也可能需要提前安装一些库:

扩展可能需要额外安装的库Alpine命令
几乎所有PECL扩展autoconfg++makeapk add --no-cache autoconf g++ make
imagick(含jepg、png、webp、avif)imagemagick-devlibjpeg-turbolibpnglibwebplibheif-devlibavif-devapk add --no-cache imagemagick-dev libjpeg-turbo libpng libwebp libavif-dev libheif-dev
memcachedlibmemcached-devzlib-devlibevent-devapk add --no-cache libmemcached-dev zlib-dev libevent-dev

通常由于网络限制无法直接安装,可以先在https://pecl.php.net/package/<扩展名称>下载,例如下载imagickhttps://pecl.php.net/package/imagick,然后将安装包复制到容器中安装,同时也需要使用docker-php-ext-enable使能扩展。例如安装

apk add --no-cache autoconf g++ make
apk add --no-cache imagemagick-dev libjpeg-turbo libpng libwebp libavif-dev libheif-dev
pecl install /tmp/pecl/imagick-3.8.0.tgz && docker-php-ext-enable imagick

构建适用于WordPress的PHP镜像

参考Server Environment,官方推荐安装的扩展有:

级别扩展镜像中不包含的核心扩展镜像中不包含的其他扩展
必须(required)json mysqli/mysqlndmysqli
强烈推荐(highly recommended)curl dom exif fileinfo hash igbinary imagick/gd intl mbstring openssl pcre xml zipexif intl zip gdigbinary imagick
用于缓存(cache)apcu/memcached/redis opcacheapcu/memcached/redis
可选(optional)timezonedbtimezonedb
备用(may)bcmath filter iconv shmop simplexml sodium xmlreader zlibbcmath shmop
文件变更ssh2 ftp socketsftp socketsssh2

用于缓存的扩展选择memcached,不安装用于文件变更的扩展,因此额外安装以下扩展:

mysqli exif intl zip gd bcmath shmop igbinary imagick memcached timezonedb

igbinaryimagickmemcachedtimezonedb的安装包手动从官网下载并复制到Dockerfile同级目录下的pecl目录,编写Dockerfile

FROM php:8.3.25-fpm-alpine3.21

RUN apk update && apk upgrade --no-cache && \
    apk add --no-cache autoconf g++ make && \
    apk add --no-cache icu-dev icu-data-full icu-libs libzip-dev libzip zlib-dev \
                       libjpeg-turbo-dev libpng-dev libwebp-dev libheif-dev libavif-dev freetype-dev \
                       imagemagick-dev imagemagick  libmemcached-dev libevent-dev

RUN docker-php-ext-configure gd --with-jpeg --with-webp --with-avif --with-freetype && \
    docker-php-ext-install -j$(nproc) mysqli exif intl zip gd bcmath shmop && \
    docker-php-ext-enable mysqli exif intl zip gd bcmath shmop

COPY ./pecl/ /tmp/pecl
RUN pecl install /tmp/pecl/igbinary-3.2.16.tgz /tmp/pecl/imagick-3.8.0.tgz \
                 /tmp/pecl/memcached-3.3.0.tgz /tmp/pecl/timezonedb-2025.2.tgz && \
    docker-php-ext-enable igbinary imagick memcached timezonedb && \
    rm -rf /tmp/pecl

apk速度较慢建议更换镜像源。并在Dockerfile同级目录下构建镜像:

docker build -t phpm:8.3 .

MariaDB

数据库选择MariaDB,镜像的标签主要用于区分操作系统的版本:

无标签基于 Debian 的镜像
ubi基于 ​​Red Hat Universal Base Image​​ 的镜像
ubi9基于 ​​UBI 9​​(对应 RHEL 9 系列)的镜像
noble基于 ​​Ubuntu 24.04 LTS​​(代号 noble)的镜像

此处选择mariadb:11.8.3。MariaDB镜像无需特别的修改。

创建编排文件docker-compose.yaml

由于MariaDB默认不支持通过主机名进行认证,因此手动为容器分配IP地址。本应用的目录结构为:

.
├── wwwroot/                  # 用于存放网站数据,此文件夹下的用户和用户组应为100082
│   ├── site1.example.com     # 单个网站的数据
│   └── site2.example.com     # 单个网站的数据
├── server/                   # Docker容器数据,此文件夹下的用户和用户组应为100000
│   ├── mysql/                # 数据库数据
│   │    ├── data/            # 数据库原始数据
│   │    ├── config/          # 数据库配置
│   │    └── logs/            # 数据库日志,此文件夹下的用户和用户组应为100999
│   ├── php/                  # PHP容器数据
│   │    ├── config/          # PHP配置
│   │    └── logs/            # PHP日志
│   └── nginx/                # Nginx数据
│         ├── ssl/            # 证书文件
│         ├── config/         # Nginx配置
│         └── logs/           # Nginx日志
└── docker/                   # 应用及容器构建文件
     ├── docker-compose.yaml  # 应用编排
     ├── php/                 # PHP镜像构建
     │    ├── Dockerfile      # PHP镜像构建文件
     │    └── pecl            # PECL安装包
     └── nginx/               # Nginx镜像构建文件
           └── Dockerfile     # Nginx镜像构建

因此docker-compose.yaml为:

services:
  db:
    image: mariadb:11.8.3
    container_name: mariadb
    networks:
      server-network:
        ipv4_address: 172.20.0.100
    volumes:
      - /www/server/mysql/data:/var/lib/mysql
      - /www/server/mysql/config:/etc/mysql/
      - /www/server/mysql/logs:/var/log/mysql
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: your-password

  php:
    image: phpm:8.3
    container_name: php
    networks:
      server-network:
        ipv4_address: 172.20.0.102
    volumes:
      - /www/wwwroot:/var/www/html
      - /www/server/php/config:/usr/local/etc
      - /www/server/php/logs:/var/log
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
    depends_on:
      - db

  nginx:
    image: nginxm:1.28
    container_name: nginx
    networks:
      server-network:
        ipv4_address: 172.20.0.101
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /www/wwwroot:/var/www/html
      - /www/server/nginx/ssl:/etc/ssl
      - /www/server/nginx/config:/etc/nginx
      - /www/server/nginx/logs:/var/log/nginx
    restart: unless-stopped
    depends_on:
      - php

networks:
  server-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/24

注意修改数据库ROOT的密码MYSQL_ROOT_PASSWORD

构建文件系统

由于绑定挂载时容器中的文件/文件夹会被宿主机中的对应文件/文件夹完全替代,因此容器在运行时可能缺少必要的配置文件,因此在部署应用之前,还需要将容器中的配置文件先复制出来。以下以Nginx为例提取默认的配置文件,首先创建一个临时容器,并将目标文件/文件夹复制出来,最后再销毁容器:

docker run -d --name=temp_container nginx:1.28.0-alpine3.21
docker cp temp_container:/etc/nginx /www/server/nginx/config
docker stop temp_container
docker rm -v temp_container

其余容器的提取方法类似。需要注意修改文件夹的用户和用户组:

chown 100000 ./server/ -R
chgrp 100000 ./server/ -R
chown 100082 ./wwwroot/ -R
chgrp 100082 ./wwwroot/ -R
chown 100999 ./server/mysql/logs/ -R
chgrp 100999 ./server/mysql/logs/ -R

使用Docker Compose部署应用

启动应用

docker-compose.yaml同级目录下执行即可启动应用:

docker compose up -d

其他常用的指令有:

指令描述
docker compose ps查看应用运行状态,正常运行时状态应为Up
docker compose logs查看应用日志
docker compose stop停止应用
docker compose restart重新启动应用
docker compose down删除应用

管理单个容器的常用指令:

指令描述
docker ps查看所有容器的运行状态,正常运行时状态应为Up
docker logs <容器ID/容器名>查看单个容器日志
docker stop <容器ID/容器名>停止单个容器
docker restart <容器ID/容器名>重新单个容器
docker rm <容器ID/容器名>删除单个容器
docker exec -it <容器ID/容器名> sh进入正在运行的容器内部​​,并启动一个交互式 shell(sh

例如,在部署acme.sh时就可以使用docker restart nginx来重启nginx镜像。

容器配置

如何配置Nginx、PHP、MariaDB并不是本文的重点,因此不在此赘述。需要注意,PHP和Nginx的用户和用户组都是www-data(容器内:82,容器外:100082)。

启动Wordpress

创建数据库

进入MariaDB交互式创建数据库:

docker exec -it mariadb mariadb -u root -p

然后输入编排文件中MYSQL_ROOT_PASSWORD数据库ROOT密码即可进入SQL命令行:

CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wordpress'@'172.20.0.102' IDENTIFIED BY 'your-password';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'172.20.0.102';
FLUSH PRIVILEGES;
EXIT;

注意修改数据库的密码。

安装Wordpress

最后一步便是安装WordPress了,在WordPress官网下载安装包并解压,同样需要设置用户和用户组为100082。怎样安装Wordpress请参考官方的安装教程,数据库的地址可以填容器编排时的名字db

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇