第16篇 实战:用 Docker Compose 编排 WordPress 与 MySQL

0 阅读4分钟

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。

到目前为止,我们的贯穿案例一直是 Flask + Redis 计数器。它足够经典,但有些读者可能会觉得“太轻量”了——毕竟只有两个服务,依赖关系也很简单。在实际工作中,你编排的应用栈往往更复杂:有前端有数据库,数据库还需要初始化 root 密码,Web 服务器必须等待数据库完全就绪才能连接。

今天我们就来编排一个更真实的应用栈——WordPress + MySQL。这个案例涉及到了完整的环境变量管理、启动顺序控制、数据持久化,以及一个你在生产环境中必然会遇到的问题:数据库密码等敏感信息该如何处理。通过这个实战,你将看到前几篇学到的概念是如何在一个更复杂的场景中串联起来的。

一、为什么选 WordPress + MySQL?

WordPress 是全球使用最广泛的内容管理系统,它由两个核心组件构成:

  • WordPress:PHP 编写的 Web 应用,处理前端请求

  • MySQL:关系型数据库,存储文章、用户、配置等数据

这个组合是 Compose 教学中的经典案例,因为它天然涵盖了我们在第 11-15 篇学到的所有关键概念:WordPress 依赖 MySQL(启动顺序控制),MySQL 数据必须持久化(Volume),数据库密码等配置通过环境变量注入(敏感信息管理),以及服务间通过 DNS 解析互相发现(自定义网络)。可以说,掌握了 WordPress + MySQL 的编排,你就掌握了一般 Web 应用的编排范式。

二、Compose 文件完整配置

2.1 目录结构

wordpress/
├── docker-compose.yml
├── .env              # 环境变量(不提交到 Git)
└── .gitignore

2.2 docker-compose.yml

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE:-wordpress}
      - MYSQL_USER=${MYSQL_USER:-wordpress}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - wp-net
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  wordpress:
    image: wordpress:6.7-php8.3-apache
    restart: unless-stopped
    ports:
      - "${WORDPRESS_PORT:-8080}:80"
    environment:
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=${MYSQL_USER:-wordpress}
      - WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD}
      - WORDPRESS_DB_NAME=${MYSQL_DATABASE:-wordpress}
    volumes:
      - wp-data:/var/www/html
    networks:
      - wp-net
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/wp-admin/install.php"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 15s

volumes:
  db-data:
  wp-data:

networks:
  wp-net:
    driver: bridge

2.3 .env 文件

MYSQL_ROOT_PASSWORD=ChangeMeRoot123!
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=ChangeMeUser456!
WORDPRESS_PORT=8080

安全警告:以上密码仅为示例。在生产环境中,请使用强随机密码,不要将 .env 提交到版本控制系统,可考虑使用 Docker Secrets(Swarm 模式)或 Kubernetes Secrets 来管理。这里 .env 文件必须加入 .gitignore,否则密码会被提交到 Git 历史。

三、关键配置解析

3.1 数据库服务(db)

MySQL 容器使用了几个关键环境变量:

  • MYSQL_ROOT_PASSWORD:MySQL root 用户密码,必须设置。MySQL 8.0 镜像在没有此变量时会报错退出。

  • MYSQL_DATABASE:容器启动时自动创建的数据库名。如果未指定,WordPress 将无法找到它的数据库。

  • MYSQL_USER / MYSQL_PASSWORD:创建一个普通用户并授予该数据库的全部权限(而不是直接用 root 连接,这是安全最佳实践)。

Volume 挂载 db-data:/var/lib/mysql 确保所有数据库文件持久化到命名卷中。即使容器被删除重建,数据也不会丢失。

健康检查使用 mysqladmin ping,这是 MySQL 自带的轻量级探测工具,比 mysql -e "SELECT 1" 更高效。由于 MySQL 首次启动需要初始化数据目录(包括创建数据库和用户),start_period: 30s 给了足够的时间窗口,避免在初始化期间被误判为 unhealthy。

3.2 WordPress 服务

WordPress 容器通过以下环境变量连接数据库:

  • WORDPRESS_DB_HOST:数据库主机名。这里写 db,即 MySQL 服务的名称,Docker 内嵌 DNS 自动解析为 MySQL 容器的 IP。

  • WORDPRESS_DB_USER / WORDPRESS_DB_PASSWORD:连接数据库的凭证,与 MySQL 容器中创建的 MYSQL_USERMYSQL_PASSWORD 对应。

  • WORDPRESS_DB_NAME:要使用的数据库名,与 MYSQL_DATABASE 对应。

WordPress 在启动时会自动检测 WORDPRESS_DB_HOST 指定的数据库是否可用。如果数据库不存在或凭证错误,WordPress 会进入安装引导页面而不是正常运行。因此 depends_on + service_healthy 确保了它启动时 MySQL 已经接受连接。

3.3 启动顺序:depends_on + service_healthy

第 15 篇讲过的知识点在此完美落地:

depends_on:
  db:
    condition: service_healthy

Compose 会先启动 db 容器,然后每 10 秒执行一次 mysqladmin ping,直到返回成功。只有 MySQL 健康检查通过后,wordpress 容器才会被创建和启动。这避免了 WordPress 启动时 MySQL 还没准备好的竞态条件。

3.4 敏感信息管理

你可能会问:MySQL 密码直接写在 .env 文件里安全吗?

在单机 Compose 场景中,这是常用的折中方案——比硬编码在 YAML 中好,但仍然需要把 .env 加入 .gitignore。生产环境中的更安全做法包括:使用 Docker Swarm 的 Secrets 功能,通过 /run/secrets/ 挂载;在 Kubernetes 中使用 Secret 对象,并通过 Sealed Secrets 或 External Secrets Operator 加密后存入 Git。

.gitignore 文件内容:

四、启动与验证

4.1 一键启动

# 在 wordpress 目录下执行
docker compose up -d

输出:

[+] Running 4/4
 ✔ Network wordpress_wp-net     Created    0.1s
 ✔ Volume "wordpress_db-data"   Created    0.0s
 ✔ Volume "wordpress_wp-data"   Created    0.0s
 ✔ Container db                 Started    0.5s

注意,此时 wordpress 容器还没有启动。因为 db 容器虽然在运行,但健康检查还没有通过。等待约 30-40 秒,MySQL 完成首次初始化(创建数据库、用户、设置 root 密码),mysqladmin ping 返回成功,Compose 才会启动 WordPress 容器。

docker compose logs -f db

观察 MySQL 初始化日志,当看到 ready for connections 时,表示 MySQL 已经就绪。

4.2 验证服务状态

输出:

NAME                IMAGE                          STATUS
wordpress-db-1      mysql:8.0                      Up 2 minutes (healthy)
wordpress-wordpress-1 wordpress:6.7-php8.3-apache  Up 1 minute (healthy)

两个服务都标记为 (healthy)

4.3 访问 WordPress

打开浏览器,访问 http://localhost:8080。你会看到 WordPress 的安装向导页面,选择语言,设置站点标题、管理员用户名和密码,然后登录即可。

4.4 验证数据持久化

我们来模拟一次灾难恢复演练:

# 1. 先确认可以正常访问 WordPress 并完成初始化安装
# 在浏览器中完成安装向导,设置管理员账号密码,登录后写一篇测试文章

# 2. 模拟灾难:删除所有容器
docker compose down

# 3. 检查数据卷仍然存在
docker volume ls | grep wordpress
# wordpress_db-data
# wordpress_wp-data

# 4. 重新启动(必须使用同一个 docker-compose.yml 和 .env)
docker compose up -d

# 5. 检查日志
docker compose logs wordpress | grep "complete"
# 不会出现安装向导,直接可以访问

访问 http://localhost:8080,你之前写的测试文章仍然存在。数据卷确保了数据在容器销毁后不会丢失。

五、常见踩坑与解决

坑 1:MySQL 启动后 WordPress 连接报错

现象:WordPress 显示“建立数据库连接时出错”。

排查

# 查看 WordPress 日志
docker compose logs wordpress

# 检查环境变量是否正确注入
docker compose exec wordpress env | grep WORDPRESS_DB

# 确认 MySQL 确实在运行且健康
docker compose exec db mysqladmin ping -h localhost -u root -p${MYSQL_ROOT_PASSWORD}

常见原因:.env 文件未放置在正确位置(必须与 docker-compose.yml 同级),或 MYSQL_PASSWORDWORDPRESS_DB_PASSWORD 不一致。

坑 2:WordPress 首次启动卡在安装向导

这是正常行为!WordPress 镜像并不会自动完成安装向导(设置站点标题、管理员账号等)。你需要通过浏览器访问 http://localhost:8080 手动完成。完成安装后,WordPress 会在数据库中写入站点配置,之后重启容器不会再出现安装向导。

坑 3:端口冲突

现象:启动时提示 Bind for 0.0.0.0:8080 failed: port is already allocated

解决:修改 .env 中的 WORDPRESS_PORT=8081,或在启动时覆盖:

WORDPRESS_PORT=8081 docker compose up -d

六、从 WordPress 到 K8s

你可能已经注意到,WordPress + MySQL 这个案例中涉及的每个概念,在 Kubernetes 中都有对应的实现:

这就是第 18 篇将要详细展开的内容——从 Compose 到 Kubernetes 的概念映射。你此刻用 Compose 编排的每个步骤,在 K8s 中几乎都有 1:1 的替代方案,只是表达方式从 YAML 变成了更强大的声明式 API。

七、命令速查表

八、本篇总结

通过 WordPress + MySQL 这个实战案例,你将前面学到的 Compose 知识融会贯通:

  • 服务定义:两个服务通过 services 声明,Compose 自动创建容器。

  • 自定义网络wp-net 让 WordPress 和 MySQL 通过服务名 db 互相通信。

  • 数据持久化:命名卷确保数据库文件和 WordPress 上传内容不随容器删除而丢失。

  • 启动顺序控制depends_on + service_healthy 彻底解决了“数据库未就绪导致应用崩溃”的问题。

  • 配置管理:通过 .env 文件统一管理环境变量和敏感信息,避免硬编码。

  • 健康检查:MySQL 用 mysqladmin ping,WordPress 用 HTTP 端点验证,确保服务真正可用。

下一篇——第 17 篇:Compose 进阶:多 Compose 文件与环境覆盖,我们将学习如何通过多文件组合和环境特定覆盖文件,让同一套 Compose 配置适配开发、测试、生产等多套环境,真正实现“一次编写,到处部署”。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !