Merge pull request 'feat(infra): 雲端就緒零影響改動 (compose overlay + healthcheck + env)' (#48) from feat/cloud-ready-zero-impact into master
Reviewed-on: #48
This commit was merged in pull request #48.
This commit is contained in:
+4
-4
@@ -16,7 +16,7 @@ APP_MAINTENANCE_STORE=database
|
||||
BCRYPT_ROUNDS=12
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=daily
|
||||
LOG_STACK=daily # 雲端建議改為 stderr 以接入雲端 logging aggregator
|
||||
LOG_DAILY_DAYS=14
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
@@ -29,15 +29,15 @@ DB_CONNECTION=sqlite
|
||||
# DB_PASSWORD=
|
||||
# MYSQL_ROOT_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_DRIVER=database # 雲端建議改為 redis
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=false
|
||||
SESSION_PATH=/
|
||||
SESSION_DOMAIN=null
|
||||
|
||||
BROADCAST_CONNECTION=log
|
||||
FILESYSTEM_DISK=local
|
||||
QUEUE_CONNECTION=database
|
||||
FILESYSTEM_DISK=local # 雲端應改為 s3(local 在容器重啟後會遺失上傳檔案)
|
||||
QUEUE_CONNECTION=redis # 雲端建議值;database 效能較差且不利擴容
|
||||
|
||||
CACHE_STORE=redis
|
||||
CACHE_PREFIX=
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
services:
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
container_name: cfdive-phpmyadmin
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:8081:80"
|
||||
environment:
|
||||
PMA_HOST: db
|
||||
PMA_PORT: 3306
|
||||
PMA_USER: ${DB_USERNAME:-cfdiveuser}
|
||||
PMA_PASSWORD: ${DB_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
networks:
|
||||
- cfdive-network
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
mailpit:
|
||||
image: axllent/mailpit
|
||||
container_name: cfdive-mailpit
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:8025:8025"
|
||||
networks:
|
||||
- cfdive-network
|
||||
+5
-26
@@ -38,11 +38,11 @@ services:
|
||||
|
||||
# 健康檢查配置
|
||||
healthcheck:
|
||||
test: ["CMD", "php", "-v"] # 檢查 PHP 版本確認服務正常
|
||||
interval: 30s # 每30秒檢查一次
|
||||
timeout: 10s # 超時時間10秒
|
||||
retries: 3 # 重試3次
|
||||
start_period: 40s # 容器啟動後40秒開始檢查
|
||||
test: ["CMD-SHELL", "nc -z 127.0.0.1 9000 || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
@@ -109,21 +109,6 @@ services:
|
||||
ports:
|
||||
- "127.0.0.1:3306:3306" # 只綁 localhost,不對外
|
||||
|
||||
phpmyadmin:
|
||||
image: phpmyadmin/phpmyadmin
|
||||
container_name: cfdive-phpmyadmin
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PMA_HOST: db
|
||||
PMA_PORT: 3306
|
||||
PMA_USER: ${DB_USERNAME:-cfdiveuser}
|
||||
PMA_PASSWORD: ${DB_PASSWORD}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
networks:
|
||||
- cfdive-network
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
queue-worker:
|
||||
image: cfdive-platform
|
||||
@@ -146,12 +131,6 @@ services:
|
||||
app:
|
||||
condition: service_healthy
|
||||
|
||||
mailpit:
|
||||
image: axllent/mailpit
|
||||
container_name: cfdive-mailpit
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- cfdive-network
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# CFDivePlatform 啟動指令
|
||||
|
||||
## 部署模式
|
||||
|
||||
專案根目錄有兩個 compose 檔:
|
||||
|
||||
| 檔案 | 用途 |
|
||||
|------|------|
|
||||
| `docker-compose.yml` | 正式服務(app、nginx、frontend、db、redis、reverb、queue-worker) |
|
||||
| `compose.override.yml` | 開發工具(phpmyadmin、mailpit),已進版控 |
|
||||
|
||||
**本機 / VPS(預設)**:Docker Compose 自動合併兩檔,開發工具一同啟動:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
**雲端正式環境**:明確指定單一檔案,排除開發工具:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.yml up -d
|
||||
```
|
||||
|
||||
> VPS 首次部署或更新後執行 `git pull` 即可取得最新的 `compose.override.yml`,不需手動建立。
|
||||
|
||||
---
|
||||
|
||||
## 專案位置
|
||||
|
||||
```powershell
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-06-17
|
||||
@@ -0,0 +1,76 @@
|
||||
## Context
|
||||
|
||||
CFDivePlatform 跑在單台 VPS 上,全部服務以 Docker Compose 管理。現有設定有三個雲端就緒問題:
|
||||
1. `app` service healthcheck 用 `php -v`,只驗證 binary 存在,無法確認 PHP-FPM 是否監聽
|
||||
2. `phpmyadmin`、`mailpit` 這兩個開發/管理工具寫死在 `docker-compose.yml`,雲端正式環境不應存在
|
||||
3. `.env.example` 的 `QUEUE_CONNECTION=database` 與 VPS 實際使用 Redis 不一致,新環境按範本初始化會跑在效能較差的 DB queue
|
||||
|
||||
本次只改 compose 設定和 `.env.example`,不觸碰任何 PHP 程式碼。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- healthcheck 改為確認 PHP-FPM FastCGI port 9000 正常監聽,比 `php -v` 更能反映 FPM 是否就緒
|
||||
- 透過 `compose.override.yml` 機制隔離開發工具,VPS 行為不變,雲端部署只需 `-f docker-compose.yml`
|
||||
- `.env.example` 的 queue 預設值與雲端慣例對齊,並補充雲端必要變數的說明
|
||||
|
||||
**Non-Goals:**
|
||||
- 不修改 Session driver(留待 P1 change)
|
||||
- 不修改 Log 輸出方式(留待 P1 change)
|
||||
- 不修改 Scheduler 架構(留待 P1 change)
|
||||
- 不改任何 PHP 程式碼或 image 內容
|
||||
- 不處理 S3 檔案儲存(P0 項目,需獨立 change)
|
||||
|
||||
## Decisions
|
||||
|
||||
### D1:healthcheck 用 `nc -z 127.0.0.1 9000` 檢查 PHP-FPM port
|
||||
|
||||
**為什麼不用 `/health` HTTP 端點:**
|
||||
app container 跑的是 PHP-FPM(FastCGI,port 9000),容器內**沒有 HTTP server**。
|
||||
`/health` 路由必須經過 Nginx 才能到達 PHP-FPM,而 Nginx 是另一個 container。
|
||||
所以 `curl` 或 `wget` 打 `http://127.0.0.1/health` 在 app container 內部完全打不到任何東西。
|
||||
|
||||
**為什麼不用 `wget`:**
|
||||
Dockerfile 安裝清單確認 `wget` 未安裝(僅裝 `curl`)。Nginx container 的 `wget` 是 busybox-wget(Alpine),兩者環境不同,不可混用。
|
||||
|
||||
**選定方案:**
|
||||
```yaml
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "nc -z 127.0.0.1 9000 || exit 1"]
|
||||
```
|
||||
`netcat-openbsd` 已在 Dockerfile 安裝。`nc -z` 只做 TCP connect,確認 PHP-FPM 的 FastCGI port 正在監聽,是 app container 內部能做到最準確的 FPM 就緒判斷。
|
||||
|
||||
**能力邊界:** 此 healthcheck 確認 PHP-FPM 程序已啟動並監聽 port,但不驗證 Nginx;Nginx 有自己的獨立 healthcheck。
|
||||
|
||||
### D2:`compose.override.yml` 放在 repo 根目錄並加進版控
|
||||
|
||||
**選項 A**:放進 `.gitignore`,每台機器手動建立
|
||||
**選項 B**:放進 repo,所有環境共用
|
||||
|
||||
選 B。`compose.override.yml` 只定義開發工具(phpmyadmin、mailpit),不含任何 secret 或環境特定值,放進版控讓新成員 `git clone` 後直接可用。雲端部署 CI 指定 `-f docker-compose.yml` 排除即可。
|
||||
|
||||
### D3:`mailpit` 同步移入 override
|
||||
|
||||
`mailpit` 與 `phpmyadmin` 性質相同(開發輔助工具),一起移入 override,保持 `docker-compose.yml` 只含正式服務。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Risk] healthcheck 只驗證 TCP 連線,不驗證請求成功**:`nc -z` 確認 port 開著,但不確認 PHP-FPM 能正確處理 FastCGI 請求。
|
||||
→ **Mitigation**:對 `depends_on` 的用途(等待 FPM 啟動再起 Nginx)已足夠;若要更深層驗證需用 `cgi-fcgi` 工具(過度工程,暫不引入)。
|
||||
|
||||
- **[Risk] VPS 若沒有 `compose.override.yml`**:移除後首次 `docker compose up` 會少 phpmyadmin/mailpit。
|
||||
→ **Mitigation**:`compose.override.yml` 已進版控,VPS 執行 `git pull` 即可取得,不需手動建立。STARTUP.md 同步更新說明此流程。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. `docker-compose.yml`:改 healthcheck、移除 phpmyadmin service、移除 mailpit service
|
||||
2. 新增 `compose.override.yml`:加入 phpmyadmin、mailpit
|
||||
3. `.env.example`:改 QUEUE_CONNECTION 預設值、補說明
|
||||
4. `STARTUP.md`:新增「部署模式」章節,明確區分:
|
||||
- **VPS(預設)**:`docker compose up -d`,自動合併 override,含 phpmyadmin + mailpit
|
||||
- **雲端正式環境**:`docker compose -f docker-compose.yml up -d`,排除開發工具
|
||||
5. **VPS 部署**:執行 `git pull` 取得版控內的 `compose.override.yml`,不需 rebuild image,`docker compose up -d` 即可
|
||||
|
||||
## Open Questions
|
||||
|
||||
無。本次改動範圍明確,無待決事項。
|
||||
@@ -0,0 +1,27 @@
|
||||
## Why
|
||||
|
||||
現有 Docker Compose 設定存在若干與雲端部署不相容的配置(開發工具混入正式服務、healthcheck 無法真實反映 app 狀態、queue 預設值不一致),在不動任何 PHP 程式碼、不重建 image、不影響 VPS 現有運作的前提下,先修正這四個零風險項目,作為雲端就緒路線圖的第一步。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **`.env.example`**:`QUEUE_CONNECTION` 預設值從 `database` 改為 `redis`;補充 `FILESYSTEM_DISK` 與 log 相關變數的說明與分組,標記哪些是雲端部署時必須設定的項目
|
||||
- **`docker-compose.yml`**:app service healthcheck 從 `php -v` 改為呼叫 `/health` 端點;移除 `phpmyadmin` service
|
||||
- **新增 `compose.override.yml`**:將 `phpmyadmin`、`mailpit` 放入 override 檔,VPS/開發環境自動載入,正式雲端部署時只用 `-f docker-compose.yml` 即可排除
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `compose-cloud-baseline`:Docker Compose 雲端基準設定——healthcheck 使用真實端點、正式 compose 不含開發工具、dev-only 服務透過 override 隔離
|
||||
- `env-cloud-annotations`:`.env.example` 補充雲端部署必要環境變數的說明與正確預設值
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(本次不修改任何既有 spec 的需求行為)
|
||||
|
||||
## Impact
|
||||
|
||||
- **`docker-compose.yml`**:healthcheck 指令、移除 phpmyadmin service
|
||||
- **新增 `compose.override.yml`**:phpmyadmin、mailpit service 定義搬移至此
|
||||
- **`.env.example`**:QUEUE_CONNECTION 預設值、新增說明行
|
||||
- **不影響**:所有 PHP 程式碼、VPS `.env`、image 內容、Scheduler、Session、Log
|
||||
@@ -0,0 +1,32 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: App service healthcheck 驗證 PHP-FPM FastCGI port
|
||||
`docker-compose.yml` 的 `app` service healthcheck SHALL 使用 `nc -z 127.0.0.1 9000` 確認 PHP-FPM FastCGI port 正在監聽,而非執行 `php -v`(只驗證 binary 存在)。
|
||||
|
||||
注意:app container 內無 HTTP server,無法透過 HTTP 打 `/health`;`netcat-openbsd` 已在 Dockerfile 安裝。
|
||||
|
||||
#### Scenario: PHP-FPM 啟動後 healthcheck 通過
|
||||
- **WHEN** `app` container 啟動且 PHP-FPM 程序已監聽 port 9000
|
||||
- **THEN** `nc -z 127.0.0.1 9000` 回傳 exit code 0,container 標記為 healthy
|
||||
|
||||
#### Scenario: PHP-FPM 未啟動時 healthcheck 失敗
|
||||
- **WHEN** `app` container 啟動但 PHP-FPM 程序尚未就緒(port 9000 未開)
|
||||
- **THEN** `nc -z 127.0.0.1 9000` 回傳非 0 exit code,container 維持 unhealthy 狀態直到重試成功
|
||||
|
||||
### Requirement: 正式 compose 不含開發工具服務
|
||||
`docker-compose.yml` SHALL 不包含 `phpmyadmin` 及 `mailpit` service 定義。這兩個服務屬開發/管理工具,不得出現在正式雲端部署的 compose 設定中。
|
||||
|
||||
#### Scenario: 只使用 docker-compose.yml 啟動
|
||||
- **WHEN** 執行 `docker compose -f docker-compose.yml up -d`
|
||||
- **THEN** 啟動的服務不包含 `phpmyadmin`(port 8081)及 `mailpit`(port 8025)
|
||||
|
||||
### Requirement: 開發工具服務透過 compose.override.yml 提供
|
||||
`compose.override.yml` SHALL 定義 `phpmyadmin` 與 `mailpit` service,供本機開發與 VPS 管理使用。
|
||||
|
||||
#### Scenario: 有 override 檔時開發工具正常啟動
|
||||
- **WHEN** 專案根目錄存在 `compose.override.yml` 且執行 `docker compose up -d`(不指定 -f)
|
||||
- **THEN** Docker Compose 自動合併 override,`phpmyadmin`(port 8081)與 `mailpit`(port 8025)一同啟動
|
||||
|
||||
#### Scenario: 雲端部署排除開發工具
|
||||
- **WHEN** CI/CD 執行 `docker compose -f docker-compose.yml up -d`(明確指定單一檔案)
|
||||
- **THEN** `phpmyadmin` 與 `mailpit` 不啟動,不佔用任何 port 或資源
|
||||
@@ -0,0 +1,19 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: QUEUE_CONNECTION 預設值為 redis
|
||||
`.env.example` 的 `QUEUE_CONNECTION` SHALL 預設為 `redis`,與 VPS 實際運作設定一致,避免新環境按範本初始化後跑在效能較差的 database queue。
|
||||
|
||||
#### Scenario: 新環境照 .env.example 初始化
|
||||
- **WHEN** 開發者或 CI 以 `.env.example` 為基礎建立 `.env`,未手動修改 `QUEUE_CONNECTION`
|
||||
- **THEN** Laravel queue driver 使用 Redis,queue worker 正常消費 Redis 佇列中的 job
|
||||
|
||||
### Requirement: .env.example 標示雲端必要變數
|
||||
`.env.example` SHALL 以行內註解或分組說明標示以下雲端部署時必須明確設定的變數,協助操作者識別必填項目:
|
||||
- `FILESYSTEM_DISK`:雲端應設為 `s3`(目前預設 `local`,雲端會導致檔案在容器重啟後遺失)
|
||||
- `LOG_CHANNEL` / `LOG_STACK`:雲端建議改為 `stderr` 以接入雲端 logging aggregator
|
||||
- `QUEUE_CONNECTION`:應為 `redis`
|
||||
- `SESSION_DRIVER`:雲端建議改為 `redis`
|
||||
|
||||
#### Scenario: 操作者閱讀 .env.example 進行雲端部署
|
||||
- **WHEN** 操作者參照 `.env.example` 設定雲端環境的 `.env`
|
||||
- **THEN** 每個雲端關鍵變數旁有說明,提示預設值在雲端環境的限制與建議替代值
|
||||
@@ -0,0 +1,31 @@
|
||||
## 1. docker-compose.yml 調整
|
||||
|
||||
- [x] 1.1 [後端] 修改 `docker-compose.yml` app service healthcheck:將 `test: ["CMD", "php", "-v"]` 改為 `test: ["CMD-SHELL", "nc -z 127.0.0.1 9000 || exit 1"]`(app container 無 HTTP server,用 nc 驗證 PHP-FPM FastCGI port 9000)
|
||||
- [x] 1.2 [後端] 從 `docker-compose.yml` 移除 `phpmyadmin` service 完整定義(包含 image、container_name、environment、networks、depends_on)
|
||||
- [x] 1.3 [後端] 從 `docker-compose.yml` 移除 `mailpit` service 完整定義
|
||||
|
||||
## 2. 新增 compose.override.yml
|
||||
|
||||
- [x] 2.1 [後端] 在專案根目錄新建 `compose.override.yml`,加入 `phpmyadmin` service(保留原有的 PMA_HOST、PMA_PORT、PMA_USER、PMA_PASSWORD、MYSQL_ROOT_PASSWORD 環境變數設定與 networks、depends_on)
|
||||
- [x] 2.2 [後端] 在 `compose.override.yml` 加入 `mailpit` service(保留原有設定與 networks)
|
||||
|
||||
## 3. .env.example 更新
|
||||
|
||||
- [x] 3.1 [後端] 將 `.env.example` 的 `QUEUE_CONNECTION` 值從 `database` 改為 `redis`
|
||||
- [x] 3.2 [後端] 在 `.env.example` 的 `FILESYSTEM_DISK=local` 旁加上行內說明,標示雲端應改為 `s3`
|
||||
- [x] 3.3 [後端] 在 `.env.example` 的 `LOG_CHANNEL` / `LOG_STACK` 區段加上說明,標示雲端建議改為 `stderr`
|
||||
- [x] 3.4 [後端] 在 `.env.example` 的 `SESSION_DRIVER=database` 旁加上說明,標示雲端建議改為 `redis`
|
||||
- [x] 3.5 [後端] 在 `.env.example` 的 `QUEUE_CONNECTION=redis` 旁加上說明,確認此為雲端建議值
|
||||
|
||||
## 4. 文件更新
|
||||
|
||||
- [x] 4.1 [後端] 更新 `docs/STARTUP.md`,新增「部署模式」章節,明確列出兩組指令:
|
||||
- **本機 / VPS**:`docker compose up -d`(自動合併 override,含 phpmyadmin + mailpit)
|
||||
- **雲端正式環境**:`docker compose -f docker-compose.yml up -d`(排除開發工具)
|
||||
- 說明 `compose.override.yml` 已進版控,VPS `git pull` 後即可取得,不需手動建立
|
||||
|
||||
## 5. 手動驗證
|
||||
|
||||
- [x] 5.1 [整合測試] 在本機執行 `docker compose up -d`,確認 phpmyadmin(8081)與 mailpit(8025)仍可正常存取
|
||||
- [x] 5.2 [整合測試] 執行 `docker compose -f docker-compose.yml up -d --remove-orphans`,確認 phpmyadmin 與 mailpit 不啟動
|
||||
- [x] 5.3 [整合測試] 確認 `app` container 的 healthcheck 狀態在啟動後顯示 healthy(`docker compose ps` 查看)
|
||||
Reference in New Issue
Block a user