解決 Strapi CMS 正式環境空白頁的踩坑經驗分享

前言:一個簡單的環境變數引發的災難 在部署 Strapi CMS 到 Kubernetes 正式環境時,只是加了一行看似無害的環境變數設定: env: - name: NODE_ENV value: production # 就是這一行! 結果卻導致整個管理後台變成一片空白,連登入頁面都看不到。更詭異的是: ✅ API 完全正常,GraphQL 和 REST 都能回應 ✅ Pod 狀態正常,沒有任何錯誤訊息 ✅ 日誌顯示 Strapi 成功啟動 ❌ 瀏覽器打開 /admin 卻是一片空白 這種「Schrodinger 的服務」(同時正常又不正常)讓人抓狂。經過一番排查,終於發現罪魁禍首是 CSP (Content Security Policy) 在作怪。 本文將深入探討: 為什麼正式環境會出現空白頁 CSP 的工作原理與安全機制 完整的問題排查步驟 如何正確配置 Strapi 的安全策略 生產環境的安全最佳實踐 問題背景:開發正常,正式環境空白 環境差異對比 graph LR subgraph "開發環境 (Development)" D1[NODE_ENV=development] D1 --> D2[✅ CSP 寬鬆] D1 --> D3[✅ 詳細錯誤訊息] D1 --> D4[✅ Hot Reload] D2 --> D5[✅ Admin Panel 正常] end subgraph "正式環境 (Production)" P1[NODE_ENV=production] P1 --> P2[🔒 CSP 嚴格] P1 --> P3[⚠️ 精簡錯誤訊息] P1 --> P4[📦 壓縮打包] P2 --> P5[❌ Admin Panel 空白] end style D5 fill:#22c55e style P5 fill:#ef4444 問題現象詳細描述 Kubernetes Deployment 設定: ...

May 7, 2025 · 9 分鐘 · Peter

解決 Kubernetes 多餘 Pod 問題與 CrashLoopBackOff 的實戰心得

前言:一次神秘的 Pod 複製事件 在一次例行的 Strapi CMS 更新部署到 AWS EKS 時,遇到了一個詭異的現象:明明 Deployment 設定檔中清楚寫著 replicas: 1,但實際運行的 Pod 卻有兩個!更奇怪的是,其中一個 Pod 持續處於 CrashLoopBackOff 狀態,而另一個則正常運行。 無論怎麼刪除多餘的 Pod,它總是會像打不死的蟑螂一樣再次出現。這種「靈異事件」讓我開始懷疑 Kubernetes 是不是有自己的想法… 本文將深入探討: 為什麼會出現多餘的 Pod CrashLoopBackOff 背後的機制 Kubernetes Deployment 和 ReplicaSet 的運作原理 實戰排查步驟與解決方案 Secret 編碼陷阱與預防措施 問題背景:Deployment 說一個,實際卻有兩個 問題現象 預期行為: # my-strapi-prod-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-strapi-prod spec: replicas: 1 # 只要 1 個 Pod selector: matchLabels: app: my-strapi-prod 實際情況: $ kubectl get pods -n default | grep my-strapi-prod NAME READY STATUS RESTARTS AGE my-strapi-prod-7d4b5c8f9d-x2k4p 1/1 Running 0 10m my-strapi-prod-8c9a6d7e5f-w8n2q 0/1 CrashLoopBackOff 5 5m 兩個 Pod 同時存在,卻只有一個正常運行! ...

May 6, 2025 · 9 分鐘 · Peter

EKS Pod 卡在 Pending?從 Too Many Pods 到 ENI / CNI 限制全面解析

前言:一個讓人懷疑人生的 Pending 狀態 最近部署 Strapi CMS 到 AWS EKS 時,遇到一個詭異的情況: $ kubectl get pods -n default NAME READY STATUS RESTARTS AGE mycompany-strapi-prod-695854fbd4-dzw66 0/1 Pending 0 3h42m 一個 Pod 卡在 Pending 狀態超過三小時,CPU 和 Memory 明明還很充足,但就是起不來。 如果你曾經盯著 kubectl get pods 看著那個永遠不會變成 Running 的 Pending 狀態,同時懷疑是不是 Kubernetes 在跟你開玩笑——恭喜你,你不孤單。 在嘗試了 Google 前五個搜尋結果、檢查了三次 YAML 設定、並認真考慮是否該轉行當咖啡師之後,我終於找到了問題的根源… ⚠️ 劇透警告:問題的根源不是 CPU、不是 Memory,而是一個你可能從沒注意過的限制——網卡(ENI)和 IP 數量。 問題診斷:一步步找出真兇 Step 1:查看 Pod 事件 遇到 Pending 狀態,第一步當然是看看 Kubernetes 到底在抱怨什麼: $ kubectl describe pod mycompany-strapi-prod-695854fbd4-dzw66 -n default 輸出內容很長,但最重要的是 Events 區塊: ...

June 15, 2024 · 13 分鐘 · Peter

全端專案 AWS EKS 雲端架構深度解析

前言:從本地開發到雲端生產環境 本文將深入解析一個全端專案在 AWS 上的完整基礎設施架構,展示如何透過 Kubernetes (EKS) 實現高可用性、可擴展性和成本效益的生產環境。這個平台提供線上課程、預約服務、會員管理和金流整合等功能。 本文涵蓋內容: 完整的 AWS EKS 叢集架構 Strapi CMS 和 Vue.js 前端的容器化部署 Jenkins CI/CD 自動化部署流程 Ingress NGINX 負載均衡和 SSL 憑證管理 與 AWS RDS、S3、ECR 的整合 第三方服務整合 (Firebase FCM、台灣金流) 監控與日誌管理 架構概覽 整體架構圖 flowchart TB subgraph Internet["網際網路"] Users["使用者"] Admin["管理員"] MobileUsers["App 使用者<br/>iOS / Android"] end subgraph OnPremise["本地機房 Mac mini"] Jenkins["Jenkins CI/CD"] subgraph MobileBuild["行動應用建置"] Fastlane["📲 Fastlane<br/>自動化打包工具"] FastlaneMatch["🔐 Fastlane Match<br/>iOS 憑證管理"] XcodeBuild["🍎 Xcode Build<br/>iOS App 編譯"] GradleBuild["🤖 Gradle Build<br/>Android App 編譯"] end end subgraph AppStores["應用商店"] TestFlight["✈️ Apple TestFlight<br/>iOS 測試版發布"] AppStore["🍎 App Store<br/>iOS 正式上架"] PlayConsole["▶️ Google Play Console<br/>Android 上架"] end GitRepo["📂 Git Repository<br/>Fastlane Match 憑證庫"] subgraph AWS["AWS Cloud (ap-southeast-1)"] subgraph EKS["EKS Cluster: mycom-taipei-cluster"] subgraph IngressNS["ingress-nginx namespace"] LB["AWS ELB<br/>LoadBalancer"] Ingress["Ingress NGINX<br/>Controller"] end subgraph CertManager["cert-manager namespace"] CertMgr["Cert Manager"] CertInj["CA Injector"] CertWebhook["Webhook"] end subgraph DefaultNS["default namespace"] StrapiPod["Strapi Pod<br/>mycom-strapi-prod<br/>(1.5 CPU / 2Gi RAM)"] WebPod["Vue.js Pod<br/>mycom-web<br/>(500m CPU / 512Mi RAM)"] PSQLClient["PostgreSQL Client<br/>(Debug)"] end subgraph KubeSystem["kube-system namespace"] CoreDNS["CoreDNS<br/>(2 replicas)"] MetricsServer["Metrics Server<br/>(2 replicas)"] AWSNode["AWS VPC CNI"] KubeProxy["Kube Proxy"] end subgraph CloudWatch["amazon-cloudwatch namespace"] FluentBit["Fluent Bit<br/>(日誌收集)"] end end subgraph Storage["儲存服務"] RDS["RDS PostgreSQL<br/>postgres-strapi-taipei<br/>(ap-southeast-1)"] S3["S3 Bucket<br/>mycom-strapi-prod-s3-taipei"] end subgraph Registry["容器映像倉儲"] ECR["AWS ECR<br/>AWS_Account_ID.dkr.ecr"] end subgraph Monitoring["監控服務"] CW["CloudWatch<br/>Logs & Metrics"] end end subgraph ThirdParty["第三方服務"] Firebase["Firebase FCM<br/>(推播通知)"] Newebpay["Newebpay<br/>(台灣金流)"] EZPay["EZPay<br/>(電子發票)"] SendGrid["SendGrid<br/>(郵件服務)"] TWCA["TWCA<br/>(OV SSL 憑證)"] end Jenkins -->|建置映像檔| ECR Jenkins -->|部署更新| EKS Jenkins -->|觸發建置| Fastlane Fastlane --> FastlaneMatch FastlaneMatch -->|同步憑證| GitRepo Fastlane --> XcodeBuild Fastlane --> GradleBuild XcodeBuild -->|自動上傳| TestFlight TestFlight -.->|正式發布| AppStore GradleBuild -->|自動上傳| PlayConsole Users -->|HTTPS| LB Admin -->|HTTPS| LB MobileUsers -->|下載 App| TestFlight MobileUsers -->|下載 App| PlayConsole LB -->|:80,:443| Ingress Ingress -->|CMS Backend| StrapiPod Ingress -->|Web Frontend| WebPod CertMgr -.->|管理 SSL 憑證| Ingress TWCA -.->|OV SSL 憑證| CertMgr StrapiPod -->|讀寫資料| RDS StrapiPod -->|上傳媒體檔案| S3 StrapiPod -->|推播通知| Firebase StrapiPod -->|金流處理| Newebpay StrapiPod -->|電子發票| EZPay StrapiPod -->|寄送郵件| SendGrid WebPod -->|GraphQL API| StrapiPod FluentBit -->|收集日誌| CW MetricsServer -.->|資源監控| CW ECR -->|拉取映像檔| StrapiPod ECR -->|拉取映像檔| WebPod 核心技術棧 基礎設施層: ...

June 5, 2024 · 12 分鐘 · Peter