从手动设置到一键部署:我的 Docker 化 WordPress 之旅
Source: Dev.to
从手动搭建到一键部署:我的 WordPress Docker 化之旅
在这篇文章中,我想分享一下我把 WordPress 从传统的手动安装过程迁移到使用 Docker 的完整流程。通过一步步的实验,我最终实现了只需要一条命令就能启动完整的 WordPress 环境的目标。
目录
手动搭建的痛点
在本地或服务器上手动安装 WordPress 时,我经常会遇到以下几个问题:
- 环境不一致:不同机器的 PHP、MySQL 版本不统一,导致代码在本地跑得好,在生产环境报错。
- 依赖管理繁琐:每次升级插件或主题,都需要手动检查兼容性。
- 迁移成本高:从开发环境迁移到生产环境,需要导出数据库、拷贝文件、重新配置
wp-config.php,过程容易出错。
这些痛点促使我去寻找一种更 可重复、可移植 的解决方案。
Docker 基础概念回顾
- 镜像(Image):只读的模板,用来创建容器。
- 容器(Container):镜像的运行实例,拥有自己的文件系统、网络和进程空间。
- Dockerfile:定义如何构建镜像的脚本。
- docker-compose:用 YAML 文件描述多容器应用的部署方式,能够一次性启动所有相关服务(如 WordPress、MySQL、phpMyAdmin 等)。
构建 Docker 镜像
下面的 Dockerfile 基于官方的 wordpress:php8.2-apache 镜像,加入了一些自定义插件和主题。
FROM wordpress:php8.2-apache
# 安装必要的系统依赖
RUN apt-get update && apt-get install -y \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install gd
# 拷贝自定义插件和主题
COPY ./plugins /var/www/html/wp-content/plugins
COPY ./themes /var/www/html/wp-content/themes
# 设置文件权限
RUN chown -R www-data:www-data /var/www/html/wp-content
EXPOSE 80
提示:如果你只想使用官方镜像的默认插件和主题,可以省略
COPY步骤。
构建镜像的命令:
docker build -t my-wordpress:latest .
使用 docker-compose 编排服务
下面的 docker-compose.yml 定义了 WordPress、MySQL 与 phpMyAdmin 三个服务。所有服务都在同一个自定义网络 wpnet 中,便于相互通信。
version: "3.9"
services:
wordpress:
image: my-wordpress:latest
container_name: wp_app
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp_user
WORDPRESS_DB_PASSWORD: secretpassword
WORDPRESS_DB_NAME: wp_database
volumes:
- ./wp-data:/var/www/html
depends_on:
- db
networks:
- wpnet
db:
image: mysql:8.0
container_name: wp_db
environment:
MYSQL_DATABASE: wp_database
MYSQL_USER: wp_user
MYSQL_PASSWORD: secretpassword
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- db_data:/var/lib/mysql
networks:
- wpnet
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: wp_phpmyadmin
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: rootsecret
ports:
- "8081:80"
depends_on:
- db
networks:
- wpnet
networks:
wpnet:
volumes:
db_data:
注意:
volumes用于持久化数据,确保容器重启后数据库和 WordPress 文件仍然保留。
启动所有服务:
docker-compose up -d
此时,访问 http://localhost:8080 即可看到 WordPress 安装向导,http://localhost:8081 则是 phpMyAdmin 的登录页面。
一键部署脚本
为了进一步简化部署,我把构建镜像、拉取依赖、启动容器的步骤封装进了一个 Bash 脚本 deploy.sh。
#!/usr/bin/env bash
set -e
# 1. 构建自定义 WordPress 镜像
echo "🔧 正在构建 WordPress 镜像..."
docker build -t my-wordpress:latest .
# 2. 拉取所需的官方镜像(如果本地不存在)
echo "📦 拉取 MySQL 与 phpMyAdmin 官方镜像..."
docker pull mysql:8.0
docker pull phpmyadmin/phpmyadmin
# 3. 启动 compose
echo "🚀 启动 Docker Compose..."
docker-compose up -d
# 4. 打印访问地址
echo "✅ 部署完成!"
echo "WordPress: http://localhost:8080"
echo "phpMyAdmin: http://localhost:8081"
使用方法:
chmod +x deploy.sh
./deploy.sh
只要运行一次脚本,整个 WordPress 环境就会在几秒钟内准备好。
常见问题与调试技巧
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 容器启动后 502 错误 | WordPress 容器未能连接到 MySQL | 检查 WORDPRESS_DB_HOST 是否正确(应为 db),并确保 db 服务已健康启动(docker logs wp_db) |
| 数据库初始化失败 | MySQL 环境变量拼写错误或密码不匹配 | 重新检查 MYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORD 与 WORDPRESS_DB_* 系列变量 |
| 插件/主题未生效 | 挂载卷覆盖了容器内的插件目录 | 确认 ./plugins 与 ./themes 路径下的文件结构正确,且卷映射没有冲突 |
| 容器频繁重启 | 端口冲突或资源不足 | 使用 docker ps -a 查看容器状态,检查宿主机的端口占用情况,或在 docker-compose.yml 中添加 restart: unless-stopped |
调试技巧:
docker-compose logs -f实时查看所有服务日志。docker exec -it wp_app bash进入 WordPress 容器内部,手动检查文件权限或运行wp-cli。- 使用
docker-compose down -v完全清除卷后重新部署,确保没有残留的旧数据。
结语
通过 Docker,我成功把原本需要 手动配置、繁琐迁移 的 WordPress 开发流程,转变为 一键部署、环境一致 的现代化工作流。下面是我在实际项目中得到的几条体会:
- 镜像层次化:把公共依赖(如 PHP、Apache)放在基础镜像,业务代码放在上层,能够显著加快后续构建速度。
- 持久化卷:一定要为数据库和 WordPress 内容使用卷,否则容器重启会导致数据丢失。
- 版本锁定:在
docker-compose.yml中明确指定镜像标签(如mysql:8.0),防止意外升级导致兼容性问题。 - CI/CD 集成:将
docker build与docker-compose up脚本写进 CI 流水线,能够实现自动化部署,进一步提升交付效率。
如果你也在考虑把传统的 WordPress 项目迁移到容器化环境,希望这篇文章能为你提供一个清晰的参考路径。祝你玩得开心,部署顺利!
本文版权归原作者所有,转载请注明出处。
项目背后的“原因”
作为一名正在转向 DevOps 的人,我很快意识到,真正的学习是通过动手构建实现的,而不是仅仅观看教程。虽然我之前已经使用手动 SSH 命令和 Ansible Playbook 搭建过 WordPress,但我一直听说容器化是 DevOps 的基础技能。于是,我决定通过完成 Project 1(在我的 30 项 DevOps 路线图中)来弥补这一差距:将完整的 WordPress LEMP 堆栈容器化。
本文记录了我的实战过程、遇到的挑战以及在此过程中学到的关键概念。
我构建的内容
我创建了一个类似生产环境的 WordPress 环境,只需一条命令即可启动:
docker-compose up -d
该命令会启动两个容器:
- MySQL 8.4 – 数据库
- WordPress(PHP 8.3)– 应用程序
整个基础设施都定义在 docker-compose.yml 文件中——实践中的基础设施即代码。
架构:简单但强大
用户浏览器 → localhost:8080 → WordPress 容器 → MySQL 容器 (db:3306)
docker-compose.yml
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DB_NAME: wordpress
depends_on:
- db
volumes:
- wp_data:/var/www/html
volumes:
db_data:
wp_data:
关键挑战与解决方案
挑战 1 – 数据库连接问题
- 问题: WordPress 安装失败,出现 “database connection error”。
- 解决方案: 容器之间通过 service names(服务名称)通信,而不是
localhost。使用db(服务名称)作为数据库主机即可解决此问题。
挑战 2 – macOS 上的端口冲突
- 问题: 端口 80 已被占用。
- 解决方案: 在 compose 文件中将端口映射改为
"8080:80"。
挑战 3 – GitHub 认证错误
- 问题: 因密码认证已被弃用,无法推送代码。
- 解决方案: 生成 GitHub 个人访问令牌(Personal Access Token),并在 CLI Git 操作中使用该令牌。
这个项目教会我的东西
-
基础设施即代码 (IaC) 不只是流行词
在 YAML 文件中定义整个堆栈的感觉颇为革命性。这个单一文件可以:- 进行版本控制
- 与团队成员共享
- 在任何地方部署相同的环境
- 充当文档
-
容器网络在你理解后就像魔法一样
wordpress容器可以通过使用服务名称(db:3306)直接连接到db容器。Docker 会创建一个虚拟网络,使容器能够通过名称相互发现。 -
开发‑生产环境的一致性是可以实现的
相同的环境可以运行在:- 我的本地 MacBook
- AWS EC2 实例
- CI/CD 流水线
- 任意开发者的机器
再也没有 “在我机器上可以工作” 的问题!
-
公开学习有其好处
在 GitHub 上记录这段旅程并撰写本文巩固了我的理解。完整代码可在此获取,供任何人参考或基于此构建。
对比:Docker 前后
| 方面 | 手动/Ansible 设置 | Docker 化设置 |
|---|---|---|
| 设置时间 | 15–20 分钟 | 30 秒 |
| 可复现性 | 环境依赖 | 保证一致性 |
| 学习曲线 | 初期较低 | 较陡但更有价值 |
| 可移植性 | 服务器特定 | 在任何支持 Docker 的地方运行 |
| 扩展性 | 手动干预 | 添加更多容器 |
我遵循的核心命令
| 操作 | 命令 |
|---|---|
| 启动所有服务 | docker-compose up -d |
| 检查状态 | docker-compose ps |
| 查看日志 | docker-compose logs -f |
| 停止所有服务 | docker-compose down |
| 停止并删除卷(全新环境) | docker-compose down -v |
| 访问 MySQL shell | docker-compose exec db mysql -u root -p |
初学者指南:我推荐的学习路径
- 从官方 Docker Getting Started 教程开始 – 增强信心。
- 先将简单的东西容器化(例如,一个静态网站),再去处理数据库。
- 尽早使用 Docker Compose – 它简化了多容器应用。
- 不要害怕
docker-compose down -v– 重新开始常能解决问题。 - 仔细阅读错误信息 – 它们通常很有帮助。
我的旅程下一步
- 添加 Nginx 作为反向代理,以提升性能并实现 SSL 终止。
- 正确实现 持久化存储,用于上传和主题。
- 使用 Prometheus/Grafana 容器添加 监控。
- 创建 CI/CD 流水线,自动构建和部署镜像。
- 将其转换为 Kubernetes 清单,学习编排。
最后感想
将 WordPress Docker 化从一项令人生畏的任务,变成了一项赋能的技能。最初对网络和配置的挫败感,随着我领悟到容器的强大而转为兴奋。
最有价值的经验并非关于 Docker 本身,而是关于 DevOps 思维方式:自动化一切,彻底记录,构建可复现的系统。
给所有正在学习的朋友们:开始动手吧。你的第一个项目不必完美,只要完成即可。随后写下来,分享出去,然后继续下一个项目。
对我帮助最大的资源
-
…以及无数博客文章、Stack Overflow 回答和 Docker 社区 Slack。
-
Docker Hub: WordPress Docker Image
-
Docker Compose 文档: Docker Compose Docs
与我联系
- GitHub: @alanvarghese-dev