feat(docker): 移除 bind mount,程式碼與 vendor 烘進 image
Run Tests / test (pull_request) Successful in 32s

Dockerfile 改 multi-stage(app + web),app/scheduler/queue-worker/
reverb/nginx 五個服務都不再依賴 ./:/var/www bind mount 取得程式碼;
nginx 改本地 build 從 app 階段 COPY --from 取得 public/,public/storage
symlink 在兩階段各自於 build 時建立。docker-compose.yml 新增具名 volume
storage-app-public 讓上傳檔案跨 image 重建保留;env_file: 取代原本
bind mount 帶入 .env 的方式,只給四個 Laravel runtime 服務。
compose.override.yml 補上開發用 bind mount 維持改 code 立即生效;
docker-entrypoint.sh 收斂到只剩目錄權限設定,migration/cache/swagger
移到 deploy.yml 統一負責,避免職責重疊。

實作驗證時發現並修復三個規劃階段沒預見的問題:app 服務的 build: 缺
target: app 導致預設建到最後一個 stage(image 實際變成 nginx);
.dockerignore 需排除本機既有的 public/storage 符號連結(Windows 上
會讓 build context 打包失敗);env_file: 讓 .env 全部變數變成真實
環境變數、蓋掉 phpunit.xml 的測試隔離設定,已擴大 tests/bootstrap.php
的強制覆蓋清單修復(239 tests 全綠)。

本機 dev 模式與 production 模式(無 override)皆完整驗證:healthcheck、
migration/cache/swagger、上傳檔案持久性、nginx 獨立於 app 服務靜態檔
與 storage 檔案、.env 熱更新、nginx 無 .env 存取權。

openspec change: bake-image-remove-bind-mount

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142LC1kQb8EyV59TjHDkhWS
This commit is contained in:
2026-08-04 16:59:18 +08:00
parent 3b0cdf96d8
commit 6a7d98b0fe
12 changed files with 226 additions and 168 deletions
+22 -5
View File
@@ -1,10 +1,27 @@
<?php
// docker compose 將 DB_CONNECTION=mysql 注入為真實環境變數(存在於 $_SERVER),
// PHPUnit 的 <env force="true"> 只覆蓋 $_ENV / putenv,而 Laravel env() 透過
// phpdotenv 優先讀 $_SERVER——導致容器內跑測試時 RefreshDatabase 直接清空
// 開發用 MySQL2026-06-12 實際發生三次)。必須在 bootstrap 階段三者同步強制。
foreach (['DB_CONNECTION' => 'sqlite', 'DB_DATABASE' => ':memory:'] as $key => $value) {
// docker-compose.yml 改用 env_file: 注入 .env 後,.env 內所有變數(不只 DB_*)
// 都變成真實環境變數(存在於 $_SERVER),PHPUnit 的 <env force="true"> 只覆蓋
// $_ENV / putenv,而 Laravel env() 透過 phpdotenv 優先讀 $_SERVER——導致容器內
// 跑測試時實際使用 .env 的 production-like 值(如 CACHE_STORE=redis、
// SESSION_DRIVER=database、QUEUE_CONNECTION=database、MAIL_MAILER=smtp),
// 而非 phpunit.xml 宣告的 testing 值,曾造成 RefreshDatabase 清空開發用 MySQL
// 2026-06-12)、以及後續拿掉 bind mount 改用 env_file 後測試互相污染快取/
// 對外寄信等問題(2026-08-04)。必須在 bootstrap 階段將 phpunit.xml 宣告的
// 每一個 testing 值同步強制寫入 $_SERVER / $_ENV / putenv 三處。
foreach ([
'APP_ENV' => 'testing',
'APP_MAINTENANCE_DRIVER' => 'file',
'BCRYPT_ROUNDS' => '4',
'CACHE_STORE' => 'array',
'DB_CONNECTION' => 'sqlite',
'DB_DATABASE' => ':memory:',
'MAIL_MAILER' => 'array',
'PULSE_ENABLED' => 'false',
'QUEUE_CONNECTION' => 'sync',
'SESSION_DRIVER' => 'array',
'TELESCOPE_ENABLED' => 'false',
] as $key => $value) {
$_SERVER[$key] = $value;
$_ENV[$key] = $value;
putenv("{$key}={$value}");