基于wunderio/drupal-project的现代化Drupal开发与Kubernetes部署实践
1. 项目概述与核心价值
如果你正在寻找一个能让你快速启动一个现代化、可运维、且具备企业级部署能力的Drupal项目模板,那么
wunderio/drupal-project
绝对值得你花时间深入研究。这个项目远不止是一个简单的
composer create-project
命令的替代品,它是一个经过实战打磨的、为 Kubernetes 集群部署而生的完整解决方案。我接触过不少 Drupal 项目模板,但这个模板在开发体验、代码质量管控和持续集成/持续部署(CI/CD)流程的整合上,其完整性和成熟度都令人印象深刻。
简单来说,这个模板解决了 Drupal 开发者,特别是团队协作和需要频繁部署到复杂环境(如 Kubernetes)的开发者,面临的几个核心痛点:如何统一开发环境、如何自动化代码质量检查、如何安全地管理不同环境的配置和密钥、以及如何构建一个可靠且可重复的部署流水线。它基于业界广泛使用的
drupal-composer/drupal-project
,但在此基础上,深度集成了 Wunder 团队在大量 Drupal 项目中积累的最佳实践和工具链,包括 DDEV 本地开发环境、CircleCI 自动化流水线、以及专为 Kubernetes 设计的 Silta 部署配置。
对于个人开发者,它能帮你建立起一套非常专业的开发规范;对于团队,它几乎提供了一个“开箱即用”的标准化项目骨架,能极大减少项目初期的配置成本,并确保所有成员在统一的工具和流程下协作。接下来,我将为你深入拆解这个项目的设计思路、核心配置以及在实际使用中需要注意的细节和技巧。
2. 项目架构与核心组件解析
2.1 核心设计哲学:一切皆代码,环境即配置
wunderio/drupal-project
的核心设计思想是“基础设施即代码”和“配置即代码”的实践。这意味着,从本地开发环境(DDEV)到云端生产环境(Kubernetes via Silta)的所有配置,都通过版本控制的文件来定义和管理。这种做法的最大好处是
可重复性和一致性
。新成员加入项目,只需
git clone
和几条命令,就能获得一个与生产环境高度一致的本地开发环境,彻底告别“在我机器上是好的”这类问题。
项目结构清晰地体现了这一思想:
-
.ddev/: 定义了完整的本地容器化开发环境,包括 Web 服务器、数据库、缓存、搜索服务等。 -
silta/: 包含了部署到 Kubernetes 集群(Silta)所需的所有 Helm Chart 配置和加密的密钥文件。这是将 Drupal 应用“容器化”并部署到云上的蓝图。 -
.circleci/: 定义了从代码提交到自动构建、测试、部署的完整 CI/CD 流水线。 -
grumphp.yml: 代码提交时的质量门禁,确保不符合规范的代码无法进入仓库。 -
composer.json: 不仅管理 PHP 依赖,还通过drupal-scaffold等插件管理 Drupal 核心文件,并通过scripts字段定义项目级别的 Composer 钩子。
这种结构将开发、部署、运维的关切点分离,但又通过配置文件紧密连接。开发者主要关注
.ddev
和代码本身,运维或 DevOps 工程师则关注
silta
和
.circleci
的配置。所有改动都经过代码审查,确保了变更的可追溯性。
2.2 核心工具链选型与优势
模板集成的每一个工具都不是随意选择的,背后都有其解决特定问题的考量:
-
DDEV 作为本地开发环境 :相比 Lando 或单纯的 Docker Compose,DDEV 对 Drupal 的生态支持更为原生和友好。它提供了大量针对 Drupal 优化的命令(如
ddev drush、ddev syncdb),并且其插件系统(如ddev-wunderio-drupal)可以无缝扩展功能。选择 DDEV 意味着团队可以快速获得一个功能齐全、性能接近生产的本地环境,包括 Varnish、Elasticsearch、Mailpit 等常用服务。 -
CircleCI 作为 CI/CD 平台 :CircleCI 与 GitHub 集成度极高,配置采用 YAML 文件,清晰易懂。模板中预设的流水线已经处理了复杂的环境部署(包括多集群),并集成了密钥管理、手动审批等企业级功能。使用它,团队可以专注于定义“构建什么”和“部署到哪里”,而无需从头搭建 Jenkins 等更重型的系统。
-
Silta 作为 Kubernetes 部署方案 :Silta 是 Wunder 基于 Helm 为 Drupal 定制的 Kubernetes 部署方案。它封装了 Drupal 在 K8s 上运行的最佳实践,如 ConfigMap 管理、Secret 注入、水平自动伸缩、健康检查等。
silta/目录下的 YAML 文件就是 Helmvalues.yaml的定制化版本,让你能用声明式的方式定义生产环境的状态。这对于需要在多个客户或环境中维护数十个 Drupal 站点的团队来说,是维持部署一致性的关键。 -
GrumPHP 与 Conventional Commits :强制性的代码提交规范(必须包含 JIRA/GitHub 票据 ID)和自动化检查(代码风格、语法),是在团队规模扩大后维持代码库健康度的基石。它把质量控制左移,在代码提交时就发现问题,比在 CI 阶段甚至生产环境才发现问题的成本低得多。
实操心得 :这套工具链的组合,初看可能觉得复杂,但一旦跑通,其带来的效率提升和风险降低是巨大的。特别是
ddev start一键拉起所有服务和git push后自动部署到测试环境的能力,能让开发团队更专注于业务逻辑开发,而非环境调试。
3. 从零开始:项目初始化与配置详解
3.1 创建与克隆项目仓库
第一步是使用 GitHub 的“Use this template”功能。这里有一个
关键细节
:项目命名规范
client-COUNTRYCODE-CLIENT-PROJECT
。这不仅仅是命名约定,它通常与后续的 Kubernetes 命名空间、域名生成规则相关联。例如,一个名为
client-us-acme-website
的项目,其开发环境的域名可能就会是
main.client-us-acme-website.dev.wdr.io
。遵循这个规范能避免后续在 CI/CD 和 DNS 配置上出现意外问题。
克隆项目后,不要急于启动。首先进行一轮“项目身份”的配置更新:
-
README.md: 将模板的通用说明替换为当前项目的具体信息,如项目简介、本地开发指南、部署流程等。这是给未来团队成员(包括你自己)的第一份文档。 -
composer.json: 更新name、description字段。更重要的是,检查require和require-dev中的依赖版本,根据项目实际需要(如 Drupal 核心版本、关键模块版本)进行调整。 -
grumphp.yml: 找到git_commit_message任务下的正则表达式。你需要将其中匹配票据 ID 的模式(如[A-Z]+-\d+)更新为你们项目实际使用的票据系统格式。例如,如果你们用 JIRA 且项目键是WEB,那么正则表达式可能需要包含[WEB]-\d+。这一步至关重要,否则所有提交都会因票据格式不符而被 GrumPHP 拦截。
3.2 深度定制本地 DDEV 环境
.ddev/config.yaml
是 DDEV 环境的核心。模板提供了基础配置,但你需要根据项目需求进行调整:
-
name: 项目名称,会影响本地访问域名(<name>.ddev.site)。建议保持与仓库名一致以避免混淆。 -
php_version: 确保与生产环境计划使用的 PHP 版本一致。 -
webserver_type: 通常是nginx-fpm,这是 Drupal 的推荐搭配。 -
database: 默认是mysql:8.0,如果生产环境用 MariaDB,可以考虑切换。 -
xdebug_enabled: 默认为false。我建议在config.yaml中保持关闭,而在需要时通过ddev xdebug on临时开启。因为 Xdebug 会显著降低 PHP 执行速度,影响日常开发体验。 -
additional_hostnames和additional_fqdns: 如果你的站点需要响应多个本地域名(例如,用于多语言或多站点的测试),可以在这里添加。
更高级的定制在
.ddev/docker-compose.*.yaml
文件中。例如,模板中已经包含了
docker-compose.elasticsearch8.yaml
来提供 Elasticsearch 服务。如果你需要 Redis 作为缓存后端,就可以创建一个
docker-compose.redis.yaml
文件来定义 Redis 服务。这种覆盖式配置让服务管理非常灵活。
关于
ddev-wunderio-drupal
插件
:这个插件是模板的灵魂组件之一。它通过一个
pre-start
钩子自动安装。它提供了
ddev syncdb
(从远程环境同步数据库)、
ddev grumphp
、
ddev phpunit
等关键命令。查看其 GitHub 仓库的文档,可以了解所有可用命令和配置选项。例如,
syncdb
命令通常需要你先通过
ddev auth ssh
认证到远程主机,并且项目 VPN 配置正确才能工作。
3.3 配置管理与环境分离
Drupal 的配置管理(
config/sync
)是强大但容易踩坑的功能。模板通过
config_split
模块来实现不同环境的配置差异化。
-
理解默认结构
:在
web/sites/default/settings.php中,你会看到引用了config_split的设置。通常会有config_split.config_split.silta、.production、.main、.local等配置项。 -
环境逻辑
:
-
local: 本地开发环境独有配置(如禁用前端聚合、启用开发模块)。 -
main: 对应于main(开发/集成)环境。 -
production: 生产环境配置。 -
silta: 所有 Silta 部署的 K8s 环境共享的配置(如 Varnish 设置、文件系统路径)。
-
-
如何操作
:在本地开发时,你通过
drush cex导出的配置是“完整配置”。config_split会根据当前环境(由settings.php中的条件判断决定)自动激活对应的“分割配置”,并在导入时(drush cim)合并。这意味着,你可以在本地启用devel模块并导出配置,只要它被分配到config_split.config_split.local中,那么这部分配置就不会被同步到生产环境。 -
关键步骤
:初始化新站点后,你需要先在 UI 上(
/admin/config/development/configuration/config_split)或使用 Drush 命令启用这些config_split配置项,然后将它们的状态(status)导出到config/sync目录。这样,环境分离的“开关”本身也纳入了版本控制。
注意事项 :
config_split的配置优先级很高。务必在项目早期就规划好哪些配置属于哪个环境。一个常见的错误是将生产环境的第三方 API 密钥放到了全局配置中,导致被意外同步到开发环境。安全的做法是:将所有环境敏感的配置(如 API 端点、密钥)通过环境变量注入,并在settings.php中根据环境读取,而不是存储在config/sync里。
4. CI/CD 流水线:CircleCI 与密钥管理实战
4.1 CircleCI 配置解析
.circleci/config.yml
文件定义了一个多工作流(workflow)的管道。其典型流程如下:
-
build任务 :在任何分支推送时触发。运行composer install、npm install(如果存在)、执行代码质量检查(如 GrumPHP,实际上在提交时已检查,这里可能做二次验证)和 PHPUnit 测试。这是一个质量关卡,构建或测试失败会阻止后续部署。 -
deploy-to-silta任务 :此任务负责将应用部署到 Silta 集群。它依赖于build任务的成功。-
环境判断
:任务会通过分支名判断目标环境。通常,
main分支部署到main(开发)环境,production或prod分支部署到production(生产)环境。feature/*分支可能会部署到临时的预览环境。 -
手动批准
:对于
production环境的部署,模板通常配置了手动批准步骤(approve-deployment)。这需要在 CircleCI 的 UI 上点击“Approve”按钮后,部署才会继续。这是一个重要的安全阀。 -
密钥注入
:部署任务会使用对应环境的加密密钥,解密
silta/silta*.secrets文件,并将这些密钥作为环境变量注入到 Kubernetes 的 Secret 中,供 Drupal 容器使用。
-
环境判断
:任务会通过分支名判断目标环境。通常,
4.2 密钥管理:最需要谨慎对待的环节
这是整个模板中 安全风险最高 、也最需要理解透彻的部分。原理是“加密后再提交”,确保敏感信息(数据库密码、API 密钥等)不会以明文形式出现在 Git 历史中。
步骤详解:
-
生成加密密钥
:在 CircleCI 项目设置的
Contexts中,为silta_dev和silta_finland(或其他环境)分别创建加密密钥。这个密钥是一个长字符串。在 CircleCI UI 中,它被存储为一个环境变量,例如SEC_CLIENT_US_ACME_WEBSITE_SILTA_DEV。 务必立即将此密钥备份到团队的密码管理器(如 LastPass、1Password)中! 如果丢失,对应的加密文件将无法解密,导致部署失败。 -
配置 CircleCI
:在
.circleci/config.yml中,找到deploy-to-silta任务,你会看到类似secret_key_env: SEC_CLIENT_US_ACME_WEBSITE_SILTA_DEV的引用。这告诉 CircleCI 在运行时使用哪个环境变量作为解密密钥。 -
创建 secrets 文件
:在本地,你有一个
silta/silta.secrets.example文件作为模板。复制它并重命名为silta/silta.secrets(用于开发环境)和silta/silta-prod.secrets(用于生产环境)。在这些 YAML 文件中,以明文形式填写该环境所需的密钥。# silta/silta.secrets 示例 env: DRUPAL_HASH_SALT: 'your_very_long_random_string_here' DATABASE_PASSWORD: 'dev_db_password' SOME_API_KEY: 'dev_api_key_123' -
加密并提交
:使用 Silta CLI 工具进行加密。
加密后,原始的明文# 假设你已安装 silta-cli # 加密开发环境 secrets 文件 silta secrets encrypt --file silta/silta.secrets --secret-key=$SEC_CLIENT_US_ACME_WEBSITE_SILTA_DEV # 加密后,会生成 silta/silta.secrets.encrypted 文件 # 将 .encrypted 文件提交到 Git,并确保 .secrets(明文)文件在 .gitignore 中!.secrets文件必须被.gitignore忽略,只提交.encrypted文件。CircleCI 在部署时会用对应的密钥解密它。 -
解密(用于本地调试或更新)
:如果需要修改 secrets,你必须先解密。
silta secrets decrypt --file silta/silta.secrets.encrypted --secret-key=$SEC_CLIENT_US_ACME_WEBSITE_SILTA_DEV # 这会重新生成明文的 silta/silta.secrets 文件
踩坑实录 :我曾遇到过因为团队成员在本地加密时使用了错误的密钥上下文(比如用生产密钥加密了开发配置文件),导致部署到开发环境时解密失败。 最佳实践是:在团队文档中明确记录每个环境对应的加密密钥变量名,并在执行加密命令前,通过
echo $SEC_*确认当前 Shell 环境中的密钥变量是正确的。 另外,永远不要在 CI/CD 日志中打印密钥或解密后的内容,即使日志是私有的。
5. 高级开发技巧与故障排查
5.1 利用 Cursor AI 规则提升效率
模板内置了对 Cursor AI 编辑器的支持,规则文件位于
@.cursor/rules/
。这些规则文件(如
common.mdc
)本质上是在“教导” AI 助手关于你这个特定项目的上下文:文件结构、技术栈(Drupal、Silta、DDEV)、代码规范、提交信息格式等。
你可以这样利用它:
-
快速生成代码
:当你想创建一个新的自定义模块时,可以直接问 Cursor:“基于我们项目的 Drupal 标准,创建一个名为
my_custom_module的 .info.yml 文件和 .module 文件骨架。” Cursor 会根据规则中定义的模式来生成代码,可能自动包含正确的文件头注释和符合规范的代码结构。 -
理解复杂配置
:如果你对
silta/values.yaml中某个 Helm 参数的作用不清楚,可以选中它并询问 Cursor:“这个resources.requests.memory在 Silta 的上下文中是什么意思?生产环境通常设置多少?” AI 可以结合项目规则和其知识库给出更贴近你项目实践的答案。 -
遵守提交规范
:当你撰写提交信息时,Cursor 可以根据
grumphp.yml中定义的规则,提示你正确的票据 ID 格式和提交类型(feat, fix等)。
自定义规则
:随着项目发展,你可以将团队达成共识的编码习惯、常用的代码片段、甚至是常见的错误解决方案添加到
@.cursor/rules/
下的自定义规则文件中,让 AI 助手成为团队知识库的延伸。
5.2 Varnish 与 Purge 缓存配置实战
在本地使用 Varnish 进行缓存测试是确保生产环境缓存行为正确的关键。模板已经做了大量预配置,但理解其工作原理能帮你更好地调试。
-
配置核心
:核心是
varnish_purger模块和purge套件。确保它们已启用 (drush en varnish_purger purge)。关键的配置在admin/config/development/performance/purge。 -
Purger 设置要点
:
- 类型 :选择 “Tags”。这是 Drupal 8/9/10 推荐的缓存失效方式,基于缓存标签(cache tags)的粒度更细。
-
请求方法
:
必须选择
BAN。这是模板和 Silta 环境特意强调的一点。Silta 的 Varnish 配置通常只允许BAN请求来清除缓存,使用PURGE方法会返回405 Method Not Allowed。这是一个容易忽略但会导致缓存无法清除的坑。 -
请求头
:设置为
Cache-Tags: [invalidation:expression]。这告诉 Varnish,请求头中的Cache-Tags字段值就是需要失效的缓存标签表达式。
-
环境变量注入
:在
web/sites/default/settings.php中,有一段代码根据VARNISH_ADMIN_HOST环境变量来动态设置 Varnish 的主机和端口。在 DDEV 环境中,这些变量已被预设好,指向容器内的varnish服务。在生产环境的 Silta 部署中,这些值也会由 Kubernetes 自动注入。 这意味着同一套配置(config/sync中的)可以在不同环境下无缝工作 ,这是环境变量和配置分离带来的好处。 -
测试缓存清除
:
如果返回# 在 DDEV 环境中测试 BAN 请求 ddev exec curl -v -X BAN -H "Cache-Tags: config:system.performance" http://varnish200 Ban added,说明 Varnish 接收并处理了请求。你可以接着访问一个页面,触发 Drupal 的缓存重建,然后观察该页面的缓存是否被正确清除。 -
查看 Varnish 日志
:
这个命令可以实时过滤出与ddev exec -s varnish varnishlog -i BAN -i CacheBAN请求和缓存操作相关的日志,是调试缓存失效问题的利器。
5.3 数据库同步与工作流整合
ddev syncdb
命令是
ddev-wunderio-drupal
插件提供的“杀手级”功能。它通常通过 SSH 连接到远程环境(如
main
),导出数据库,并导入到本地。这保证了本地开发使用的是最新、最真实的数据。
实现前提 :
-
SSH 访问权限
:你需要有访问远程 Kubernetes Pod 或跳板机的 SSH 密钥,并且该密钥已添加到你的本地 SSH Agent。
ddev auth ssh命令就是用来处理容器内 SSH 认证的。 - 网络可达 :通常意味着你需要连接到公司的 VPN,才能访问开发或测试环境的内部网络。
-
正确的 Drush 别名
:远程环境的 Drush 站点别名(如
@main)必须配置正确,并且本地 DDEV 容器能够通过该别名连接到远程数据库。
常见问题排查 :
-
错误:
Failed to connect to remote host:首先确认 VPN 连接正常。然后在 DDEV 容器内尝试ssh www-admin@main-shell...看是否能连通。可能是 SSH 密钥未加载或远程主机密钥变更。 -
错误:
Drush command failed:检查远程环境的 Drush 别名文件(通常是~/.drush/sites/下的 YAML 文件)是否存在且配置正确。特别是数据库连接信息。 -
同步速度慢
:如果数据库很大,同步会耗时很长。可以考虑在远程环境使用
drush sql:dump --extra-dump=--skip-lock-tables --gzip生成压缩的导出文件,或者在本地同步时使用--skip-tables-key=common来跳过一些非核心的大表(如缓存表、日志表)。
工作流建议
:在开始一天的工作或切换任务分支前,先运行
ddev syncdb main
同步最新的开发环境数据库。在功能开发完成后,运行
ddev drush deploy
(它依次执行
config:import
,
updatedb
,
cache:rebuild
)来确保配置和数据库更新在本地无误,然后再提交代码。
5.4 测试策略与 PHPUnit 集成
模板预置了 PHPUnit 配置(
phpunit.xml
)和一个示例模块(
web/modules/custom/phpunit_example
)。这为实施测试驱动开发(TDD)或编写单元/功能测试打下了基础。
配置要点 :
-
phpunit.xml中已经设置了 Drupal 测试所需的 bootstrap 文件和测试套件。 -
它通常将
web/core和web/modules/custom等目录包含在测试扫描范围内。
运行测试 :
# 运行所有测试(可能很慢)
ddev phpunit
# 运行特定自定义模块下的测试
ddev phpunit web/modules/custom/my_module/tests
# 运行一个特定的测试类
ddev phpunit web/modules/custom/my_module/tests/src/Unit/MyServiceTest.php
# 运行标记为 “kernel” 的测试组(内核测试,比完整功能测试快)
ddev phpunit --group kernel
编写测试的建议 :
-
目录结构
:在自定义模块下建立
tests/src/Unit/(单元测试)和tests/src/Kernel/(内核测试)或tests/src/Functional/(功能测试)目录。 -
命名空间
:测试类的命名空间应与被测试类对应,并以
Test结尾。例如,\Drupal\my_module\MyService的测试类应为\Drupal\Tests\my_module\Unit\MyServiceTest。 -
利用 Drupal 测试基类
:单元测试继承
\Drupal\Tests\UnitTestCase,内核测试继承\Drupal\KernelTests\KernelTestBase,功能测试继承\Drupal\Tests\BrowserTestBase。这些基类提供了模拟容器、数据库事务、浏览器会话等基础设施。
集成到 CI
:
.circleci/config.yml
中的
build
任务应该包含运行测试的步骤。一个常见的模式是:先运行快速的单元测试和内核测试,如果通过,再运行更耗时的功能测试。确保测试失败会令 CI 任务失败,从而阻止有问题的代码被部署。
6. 常见问题与排查技巧实录
在实际使用这个模板的过程中,你几乎一定会遇到一些问题。下面是我和团队总结的一些常见问题及其解决方法。
6.1 环境启动与依赖问题
问题:
ddev start
失败,提示端口被占用或 Docker 错误。
-
排查
:首先运行
ddev poweroff关闭所有 DDEV 项目,然后ddev start重试。如果问题依旧,检查 Docker Desktop 是否正常运行(系统托盘图标)。在 macOS/Linux 上,可以尝试docker system prune -a --volumes( 警告:这会清除所有未使用的 Docker 数据,包括其他项目的数据库 )来清理可能冲突的容器或卷,然后重启 Docker。
问题:Composer 安装依赖时内存不足或超时。
-
排查
:DDEV 默认给 PHP 容器的内存可能有限。你可以通过增加 Docker Desktop 的资源分配(Settings -> Resources)来解决。对于超时,可以尝试在
ddev start前设置 Composer 镜像或使用ddev composer install --no-scripts --no-interaction先跳过脚本安装核心依赖,然后再手动处理。
6.2 部署与 CI/CD 问题
问题:CircleCI 部署任务失败,错误信息模糊,显示“Error deploying to Silta”。
-
排查步骤
:
-
查看完整日志
:在 CircleCI Job 页面,展开所有步骤,尤其是运行
silta deploy命令的那一步,查看其完整输出。 -
检查加密密钥
:这是最常见的原因。确认 CircleCI Context 中对应的
SEC_*环境变量值是否正确,且与加密silta*.secrets.encrypted文件时使用的密钥一致。可以尝试在本地用该密钥解密文件,看是否能成功。 -
检查 Helm/Kubernetes 配置
:错误可能源于
silta/values.yaml中的配置错误,比如镜像名称错误、资源请求(resources)设置过高导致集群资源不足、或缺少必要的配置项。对比一个成功部署的项目的values.yaml。 - 检查集群权限 :确认用于部署的 Service Account 或 Kubeconfig 在目标 Kubernetes 集群中有足够的权限创建/更新指定命名空间中的资源。
-
查看完整日志
:在 CircleCI Job 页面,展开所有步骤,尤其是运行
问题:代码提交被 GrumPHP 拒绝,提示提交信息格式错误。
-
排查
:仔细阅读错误信息。GrumPHP 会指出具体哪里不符合正则表达式。确保你的提交信息严格遵循
[TICKET-123]: (type) Description的格式。票据 ID 必须在方括号内,类型必须在圆括号内,后面跟一个空格和描述。描述首字母大写,结尾不要有句点。例如:[WEB-456]: (fix) Resolve login issue for users with special characters。
6.3 本地开发与功能问题
问题:
ddev syncdb
失败,提示 SSH 或数据库连接错误。
-
排查
:
-
SSH 连接
:在 DDEV 容器内手动执行 SSH 命令:
ddev ssh进入容器,然后尝试ssh www-admin@main-shell....。如果失败,检查ddev auth ssh是否执行过,以及本地~/.ssh的密钥是否已加载到 agent (ssh-add -l)。 -
Drush 别名
:确认远程环境的 Drush 别名文件存在且路径正确。有时别名文件可能位于
/var/www/.drush/sites/而非用户目录。 -
网络/VPN
:确保你连接到了可以访问目标内部网络(如
dev.wdr.io)的 VPN。
-
SSH 连接
:在 DDEV 容器内手动执行 SSH 命令:
问题:本地站点访问缓慢,或 Xdebug 导致页面超时。
-
排查
:
-
性能
:检查是否无意中开启了 Xdebug (
ddev xdebug status)。如果是,用ddev xdebug off关闭它。Xdebug 对性能影响极大,仅调试时开启。 -
资源
:使用
ddev describe查看服务状态,或用docker stats查看容器资源使用情况。如果 MySQL 或 Elasticsearch 容器占用 CPU 过高,可能是查询问题或索引重建。 -
OPCache
:确保
opcache.enable=1在 PHP 配置中已启用,这是生产模式下的重要性能优化。
-
性能
:检查是否无意中开启了 Xdebug (
问题:配置导入(
drush cim
)时发生冲突或错误。
-
排查
:
-
先导出再导入
:在另一环境做了配置更改后,确保已通过
drush cex导出并提交。在本地,先git pull获取最新配置,再运行drush cim。 -
使用
--partial和--source:如果只是部分配置冲突,可以尝试drush cim --partial --source=../config/sync。--partial允许导入部分配置,但需谨慎使用。 -
检查 UUID
:确保
web/sites/default/config目录下的system.site配置的 UUID 与数据库中的 UUID 一致。如果不一致,可以用drush config:set system.site uuid [new-uuid]来同步。 -
查看详细错误
:使用
drush cim -y --verbose获取更详细的错误信息,通常会精确到是哪个配置项的哪一行出了问题。
-
先导出再导入
:在另一环境做了配置更改后,确保已通过
6.4 缓存与 Varnish 问题
问题:内容更新后,前端页面看不到变化,怀疑缓存未清除。
-
排查流程
:
-
确认 Varnish 是否运行
:
ddev describe查看varnish服务状态。 -
手动触发清除
:在 Drupal 后台 (
admin/config/development/performance) 点击“清除所有缓存”,或运行ddev drush cache:rebuild。 -
检查 Purger 队列
:访问
admin/config/development/performance/purge,查看“队列”选项卡,看是否有积压的失效项。可以尝试手动处理队列。 -
测试 BAN 请求
:如前面所述,用
curl命令直接测试 Varnish 的 BAN 接口,看是否返回成功。 -
查看 Varnish 日志
:使用
ddev exec -s varnish varnishlog -g request -q "ReqURL ~ '^/node/'"(替换为你更新的页面路径)来查看对该页面的请求是否命中了缓存,以及是否有 BAN 请求记录。 - 检查缓存标签 :确保你更新的实体(如节点)正确地设置了缓存标签,并且 Purge 配置正确订阅了这些标签的失效事件。
-
确认 Varnish 是否运行
:
通过系统性地使用这个模板并理解其各部分的工作原理,你不仅能快速搭建起一个健壮的 Drupal 项目,更能掌握一套现代化的、可扩展的 Drupal 开发和部署方法论。它强迫你遵循最佳实践,虽然初期学习曲线稍陡,但长期来看,它为项目的可维护性、团队协作效率和部署可靠性带来的收益是巨大的。
更多推荐


所有评论(0)