Files
CFDivePlatform/openspec/changes/bake-image-remove-bind-mount/proposal.md
T
a620906209 3b0cdf96d8 chore(openspec): 新增 bake-image-remove-bind-mount change 規劃
P0「移除 Docker bind mount、程式碼烘進 image」的完整規劃:Dockerfile
改 multi-stage(app + web)、docker-compose.yml 拿掉五個服務的 bind
mount、nginx 改本地 build 取得 public/、deploy.yml 改 build-then-up、
entrypoint 職責收斂、.dockerignore 補齊。尚未實作,僅規劃文件。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142LC1kQb8EyV59TjHDkhWS
2026-08-04 16:22:50 +08:00

5.4 KiB
Raw Blame History

Why

目前 cfdive-platform image 是空殼——Dockerfile 沒有 COPY . /var/www,程式碼完全靠 docker-compose.yml 對 app、nginx、scheduler、queue-worker、reverb 五個服務的 ./:/var/www bind mount 從主機借過去。這代表 image 本身不含可執行的程式碼,無法搬到另一台機器獨立運作,也不是可版本化、可回溯的部署單位。P1(log 改 stderr、session 改 Redis)與 file-storage-s3(上傳檔案可切到 S3)已經拆掉了「container 必須綁死同一台主機磁碟」的兩個主要理由,現在是把程式碼真正烘進 image、讓 container 變成自足部署單位的時機,也是未來水平擴容的前提。

What Changes

  • Dockerfile 改為 multi-stageapp 階段(php:8.2-fpm)統一策略為「先 COPY composer manifests → composer install --no-scripts → COPY 全專案 → 補跑 composer dump-autoload --optimize(不重複加 --no-dev,該旗標已在 install 階段決定 vendor 內容)與 php artisan package:discover --ansi--no-scripts 跳過的 composer hook 手動補上)→ 執行 ln -sfn ../storage/app/public public/storage 建立符號連結」;新增 web 階段(nginx:alpine)以 COPY --from=app /var/www/public /var/www/public 取得 Laravel 的 public/ 目錄,並再次獨立執行同一條 ln -sfn 指令建立自己的符號連結(不依賴 COPY --from 隱性帶過去,兩階段各自明確宣告)。新增 .dockerignore 排除 vendor/node_modules/.envstorage/app/public/*,避免機敏資訊或本機殘留檔案被烘進 image——這是本次的正確性要求,不是可選優化。
  • docker-compose.yml:移除 app、nginx、scheduler、queue-worker、reverb 五個服務的 ./:/var/www bind mountnginx 服務改從 image: nginx:alpine(直接拉取)改為本地 buildtarget: webimage 命名 cfdive-nginx-web)取得程式碼,不再依賴任何執行期共享機制。BREAKING:改 code 不再瞬間生效,必須重新 build image 才能部署新版本。
  • 上傳檔案(storage)處理方式:本次變更不強制先切換到 S3——決定改用具名 volume storage-app-public(已定名),掛載至 appnginx 服務容器內的絕對路徑 /var/www/storage/app/public,讓上傳檔案在 image 重建後仍保留;待日後正式切到 FILESYSTEM_DISK=s3 後,此 volume 可再移除(留給後續變更處理,不在本次範圍)。
  • .gitea/workflows/deploy.yml:部署流程從「git reset --hard 改主機檔案 → docker compose exec app composer install」改為「git reset --harddocker compose builddocker compose up -d」,並成為 migrationconfig:cacheroute:cacheview:cacheevent:cachel5-swagger:generate 這些「部署一次新版本」動作的唯一執行位置。BREAKING:部署時間變長(每次都要重建 image),不再有「改 code 幾乎瞬間生效」的能力。
  • .env 傳遞方式:拿掉 bind mount 後 .env 不能再依賴主機檔案直接出現在容器裡,只在 appschedulerqueue-workerreverb 四個 Laravel runtime 服務改用 YAML list 格式的 env_file:env_file:\n - .env)指向主機上的 .env 路徑——env_file: 是把檔案內容以環境變數形式注入容器程序,不會在容器內生成一份實體 .env 檔案。nginx 服務env_file:,它不需要讀取任何 .env 內容,避免不必要的機敏資訊暴露。
  • docker-entrypoint.sh:移除「composer.lock 內容比對後才 composer install」「.env 不存在則從 .env.example 複製 + key:generate」「強制改寫 DB_HOST」三段假設容器內是 bind mount 主機目錄的邏輯;同時移除 migrationcache clearswagger 生成(改由 deploy.yml 統一負責,避免與 deploy.yml 職責重疊、也避免 app/scheduler/queue-worker 三個服務各自啟動時重複跑)與移除 storage:linksymlink 已在 image build 階段建立,執行期不需要)。entrypoint 最終只保留目錄與權限設定這項啟動必要工作。

Capabilities

New Capabilities

  • image-baked-deployment:涵蓋 image 建置時內嵌程式碼與 vendor、compose 移除 bind mount、部署流程改為 build-then-up、.env 改用 env_file 傳遞、entrypoint 職責調整後的完整行為規格。

Modified Capabilities

  • scheduler-container:現有 requirement「Scheduler 以獨立 container 執行」隱含透過 bind mount 取得程式碼,需更新為透過 image 內建程式碼執行,不再掛 ./:/var/www

Impact

  • 受影響檔案Dockerfile(改為 multi-stageapp + web)、.dockerignore(新增)、docker-compose.yml.gitea/workflows/deploy.ymldocker/php/docker-entrypoint.sh
  • 受影響服務app、nginx(改為本地 build 而非拉取 nginx:alpine)、scheduler、queue-worker、reverb(全部五個掛 bind mount 的服務)
  • 受影響流程VPS 部署流程(Gitea Actions self-hosted runner)、本機開發流程(開發者需改用 docker compose build 才能讓程式碼變動生效,或另外規劃開發環境仍用 bind mount 的 override 方案)
  • 不受影響file-storage-s3(本次不強制切換到 S3,上傳檔案改走具名 volume 過渡)、compose-cloud-baselinehealthcheck/開發工具隔離邏輯不變)