AWS S3 Upload Failed: The Bucket Does Not Allow ACLs

問題發生 在將 Production 環境複製到 Staging 環境後,發現 Strapi CMS 無法上傳圖片到媒體庫,畫面只顯示 Internal Server Error。 Strapi 是一個開源的 Headless CMS(無頭內容管理系統),可以讓開發者快速建立 API,並提供管理後台來管理內容。在這個專案中,我們使用 Strapi 搭配 AWS S3 來儲存上傳的圖片和檔案。 追查過程 第一步:查看 Kubernetes Logs 由於 Strapi 部署在 EKS(Elastic Kubernetes Service,AWS 的託管 Kubernetes 服務)上,我透過 kubectl 指令查看 Pod 的日誌: kubectl logs -f deployment/strapi-stg --tail=100 kubectl 是 Kubernetes 的命令列工具,用來與 Kubernetes 叢集互動。logs 指令可以查看容器的輸出日誌。 第二步:找到錯誤訊息 在日誌中發現關鍵錯誤: error: The bucket does not allow ACLs AccessControlListNotSupported: The bucket does not allow ACLs 這個錯誤訊息指出 S3 Bucket(AWS 的物件儲存服務中的儲存桶)不允許使用 ACL。 ...

January 30, 2026 · 3 分鐘 · Peter

資料庫同步的隱藏陷阱:Link Table 的重要性

問題現象:登入成功卻被拒於門外 最近在 Staging 環境遇到一個詭異的問題:使用者登入成功,拿到了有效的 JWT Token,但存取任何需要認證的 API 都回傳 401 Unauthorized。 # 登入成功,拿到 token POST /api/auth/local → 200 OK { "jwt": "eyJhbGc...xxxxx...your-jwt-token", "user": { "id": 1001, "email": "user@example.com" } } # 但存取個人資料失敗 GET /api/users/me → 401 Unauthorized Token 驗證通過、使用者存在、帳號未被封鎖。問題到底在哪? 根本原因:遺失的 Link Table 經過一番追查,發現問題出在資料庫同步時漏掉了關聯表(Link Table)。 什麼是 Link Table? 在關聯式資料庫中,多對多關係需要透過中間表來建立。這個中間表就是 Link Table(也稱為 Junction Table、Join Table、或 Pivot Table)。 使用者與角色的關係: 一個使用者可以有多個角色(User → Roles) 一個角色可以分配給多個使用者(Role → Users) 這是典型的多對多關係 各種 ORM 的 Link Table 命名 不同框架的 Link Table 命名慣例不同,但概念完全相同: ORM/Framework Link Table 範例 備註 Django user_groups, user_permissions 使用 _ 連接 Laravel role_user, permission_role 字母順序排列 TypeORM user_roles_role 較長的命名 Prisma _UserToRole 以 _ 開頭 Sequelize UserRoles 駝峰命名 問題的本質:資料不完整 當我們同步資料庫時,通常會注意主要的資料表: ...

January 20, 2026 · 4 分鐘 · Peter

Flutter CI/CD Debugging: Three Build Failures in One Day

前言:當建置一直紅燈 CI/CD pipeline 亮紅燈是開發日常,但連續遇到三個不同層面的問題,從 iOS codesigning、Android Gradle、到 Google Play API,這就值得記錄下來了。 這篇文章記錄我在同一天內遇到的三個建置失敗,以及逐步排除的過程。每個問題都有其獨特的根因,但也反映出 CI/CD 環境的複雜性。 問題一:iOS Keychain 解鎖失敗 症狀 Jenkins 建置在 iOS 階段失敗,錯誤訊息: [!] Error unlocking keychain at path: fastlane_keychain Command failed with exit status 51 macOS Keychain 運作機制 在深入問題之前,先了解 macOS Keychain 的運作方式: 關鍵概念: macOS 可以有多個 Keychain,每個都有獨立密碼 憑證必須在「已解鎖」的 Keychain 中才能被 codesign 使用 CI 環境通常會建立專用的 Keychain,避免影響系統 Keychain Fastlane Match 與 Keychain 的互動流程 調查過程 Exit status 51 代表「密碼錯誤」。SSH 進 Jenkins Mac mini 確認: ...

January 17, 2026 · 2 分鐘 · Peter

AWS 跨區域遷移後的技術債清理:Strapi URL 的隱藏陷阱

接手專案,先看帳單 因為老闆信用卡到期了要換新卡,我順便看了一下 AWS 帳單金額,發現比預期高。之前詢問外包商技術長(已離職),得到的回覆是:「服務都已經從新加坡遷移到台北了,除了 S3 有保留做備份,其他都刪除了。」 身為工程師,最不能接受的就是「應該是這樣」。我決定親自盤點。 名詞解釋 在繼續之前,先解釋一下會提到的 AWS 服務: 服務 說明 費用特性 S3 (Simple Storage Service) 物件儲存服務,用來存放檔案、圖片、影片 按儲存容量和請求次數計費 NAT Gateway 讓私有子網路的資源能存取網際網路 按小時計費,即使沒流量也要錢 Elastic IP 固定的公開 IP 位址 使用中免費,未關聯則收費 VPC (Virtual Private Cloud) 虛擬私有網路,隔離你的雲端資源 VPC 本身免費,但相關資源收費 Network Load Balancer 負載平衡器,分散流量到多台伺服器 按小時和處理的資料量計費 ECR (Elastic Container Registry) Docker 映像檔儲存庫 按儲存容量計費 重點是:有些資源即使沒有流量,只要存在就會收費。NAT Gateway 和未關聯的 Elastic IP 就是典型的「隱形殺手」。 盤點遺留資源 # 檢查 EKS 叢集(Kubernetes 服務) aws eks list-clusters --region ap-southeast-1 # 結果:空的 ✓ # 檢查 RDS(資料庫) aws rds describe-db-instances --region ap-southeast-1 # 結果:空的 ✓ # 檢查 NAT Gateway aws ec2 describe-nat-gateways --region ap-southeast-1 \ --filter "Name=state,Values=available" # 結果:2 個還在跑 完整盤點結果: ...

January 10, 2026 · 3 分鐘 · Peter

Kubernetes Staging 環境省錢術:從踩坑到正確實作

起因:老闆想省錢 「Staging 環境平常沒人用,每個月還要燒 $45-60 美金,能不能想辦法省一點?」 Staging 環境的成本來自兩個地方:RDS 資料庫(約 $15-20/月)和 EKS 節點(約 $30-40/月)。既然平常沒在用,我想到了一個方案:不用的時候關掉,需要的時候再打開。 於是我寫了兩個腳本: staging-start.sh:啟動 RDS、擴充節點、部署應用 staging-stop.sh:刪除部署、縮減節點、停止 RDS # staging-stop.sh 核心邏輯 kubectl delete deployment app-strapi-stg app-web-stg aws eks update-nodegroup-config \ --cluster-name my-cluster \ --nodegroup-name my-nodegroup \ --scaling-config minSize=0,maxSize=2,desiredSize=1 # 從 2 縮到 1 aws rds stop-db-instance --db-instance-identifier my-stg-rds 看起來很合理,但這裡有個問題:Production 和 Staging 共用同一個 nodegroup。 踩坑:AWS 隨機選擇刪除節點 執行 staging-stop.sh 縮減節點時,AWS 會隨機選擇要終止哪個節點。當時的配置: 節點 A:運行 Production pods 節點 B:運行 Staging pods 我期望刪除節點 B,但 AWS 選了節點 A。Production pods 被強制遷移,觸發了重新調度。 ...

January 6, 2026 · 3 分鐘 · Peter

15 次 Build Failed:一場 Jenkins + Flutter CI/CD 的史詩級除錯之旅

前言:當 Build Failed 成為日常 在過去的 19 個小時裡,我經歷了 15 次 build failed,產生了 15 個 fix commits。如果你覺得這很誇張,讓我告訴你更誇張的:最後一個 bug 是 git describe 在多個 tag 指向同一 commit 時會隨機返回其中一個。 是的,隨機。在 CI/CD Pipeline 裡。 這篇文章完整記錄這場除錯馬拉松,從最初的 Fastlane 版本問題,到 Discord 通知功能的實作與修復,再到 Ruby 相容性地獄,最後揭開 git 鮮為人知的行為。泡杯咖啡,這會是一段旅程。 第一章:Fastlane 與 Bundler 的糾葛 問題 1:Fastlane 版本不一致 Commit: fix(jenkins): use bundle exec for fastlane to ensure version consistency Jenkins 機器上有全域安裝的 Fastlane,但版本與 Gemfile.lock 指定的不同。這導致某些 action 行為不一致。 // Before: 使用全域 fastlane sh 'fastlane ios build' // After: 透過 Bundler 執行,確保版本一致 sh 'bundle exec fastlane ios build' 學習:在 CI 環境中,永遠使用 bundle exec 執行 Ruby 工具,確保版本與 lockfile 一致。 ...

December 21, 2025 · 5 分鐘 · Peter

Linux 壓縮工具完全指南:gzip、bzip2、xz、zstd、7z 效能全面比較

引言:選擇正確的壓縮工具為什麼重要? 在日常開發與維運工作中,我們經常需要壓縮檔案:備份資料庫、傳輸日誌檔、打包部署映像檔。選擇適當的壓縮工具,可能讓您的備份時間從 10 分鐘縮短到 2 分鐘,或是將 500MB 的檔案壓縮到 50MB。 本文將透過實際測試數據,深入比較常見的 Linux 壓縮工具,幫助您在不同場景下做出最佳選擇。 測試環境: macOS (Apple Silicon M1 Pro, 10 cores) 測試檔案:PostgreSQL 資料庫備份 (174 MB, my_DB_backup.sql) 測試項目:壓縮率、壓縮速度、解壓速度、特殊功能 壓縮工具快速對照表 工具 壓縮率 壓縮速度 解壓速度 多執行緒 加密 最佳場景 gzip ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ❌ ❌ 通用場景、快速壓縮 pigz ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅ ❌ 大檔案快速壓縮 bzip2 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ❌ ❌ 中等壓縮需求 xz ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ✅ ❌ 最高壓縮率 zstd ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ✅ ❌ 平衡速度與壓縮率 7z ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ✅ ✅ 跨平台、加密需求 tar - - - - ❌ 打包工具(需搭配壓縮) 1. gzip:經典的壓縮工具 簡介 gzip 是 Linux 系統中最常用的壓縮工具,基於 DEFLATE 演算法(LZ77 + Huffman 編碼)。 ...

December 19, 2025 · 10 分鐘 · Peter

在 Kubernetes 上部署 OV SSL 證書:完整實戰指南

為什麼選擇 TWCA OV 證書 在生產環境中,使用自簽憑證會導致瀏覽器顯示不安全警告,影響使用者信任。雖然 Let’s Encrypt 提供免費的自動化證書,但某些企業或政府專案需要台灣在地的認證機構簽發證書以符合法規要求。 SSL 證書的三個等級 SSL 證書依據驗證強度分為三個等級: 證書類型 驗證內容 適用場景 信任標記 價格 DV (Domain Validation) 僅驗證網域所有權 個人網站、部落格 🔒 基本鎖頭 免費~低 OV (Organization Validation) 驗證組織身份 企業網站、SaaS 服務 🔒 組織名稱 中 EV (Extended Validation) 嚴格驗證企業 金融、電商、政府 🟢 綠色網址列 高 本文使用的是 TWCA OV SSL 證書,它提供: ✅ 組織身份驗證(瀏覽器可顯示公司名稱) ✅ 完整的證書鏈(受所有主流瀏覽器信任) ✅ 12 個月有效期 ✅ 台灣在地技術支援 HTTPS 與 SSL/TLS 運作原理 在深入部署之前,先理解 HTTPS 如何保護資料傳輸: 關鍵機制說明: 非對稱加密(RSA/ECDSA):只用於金鑰交換,確保 session key 安全傳輸 對稱加密(AES):實際資料傳輸使用,效能更好 證書鏈驗證(完全離線):瀏覽器使用內建的 TWCA 根憑證驗證整個證書鏈,不需要連線到 TWCA 中間人攻擊防護:因為攻擊者沒有伺服器的私鑰,無法解密通訊 💡 重要觀念: TWCA 只在簽發證書時參與,TLS 握手過程中完全不涉及。瀏覽器使用內建的根憑證庫(包含 TWCA 根憑證)進行離線驗證。 ...

December 10, 2025 · 6 分鐘 · Peter

手把手實戰:打造你的第一個 Claude Skill(微服務健康監控儀表板)

系列文章第 2 篇:從零開始建立一個企業級實用的 Skill,完整的程式碼和詳細步驟教學。 前言 在上一篇文章中,我們了解了 Skills 的核心概念。今天,讓我們捲起袖子,動手打造一個真正實用的企業級 Skill! 你將學到: ✅ Skills 的完整目錄結構 ✅ 如何規劃和設計企業級 Skill ✅ 撰寫 SKILL.md 的技巧 ✅ 建立 scripts、references 和 assets ✅ 產生視覺化儀表板 ✅ 整合監控和告警系統 專案目標: 建立一個「微服務健康監控儀表板」Skill 這個 Skill 能夠: 🔍 自動檢查所有微服務健康狀態 📊 產生視覺化即時儀表板 📈 追蹤服務回應時間趨勢 ⚠️ 偵測異常並自動告警 📄 產生專業監控報告 🔄 支援定期自動執行 預計閱讀時間:15 分鐘 實作時間:40-50 分鐘 讓我們開始吧! 為什麼選擇這個範例? 與 Postman 的本質差異 很多人會問:「這不就是 Postman 嗎?」 完全不同!讓我們看看差異: 比較項目 Postman 我們的監控 Skill 使用場景 開發時測試單一 API 營運時監控所有服務 執行方式 手動點擊測試 自動化定期執行 目標 驗證功能正確性 確保服務健康運作 使用者 開發者個人 整個團隊 + 管理層 視覺化 簡單的回應顯示 完整的儀表板 + 趨勢圖 告警 無 自動 Discord/Email 通知 歷史記錄 無 完整趨勢追蹤 CI/CD 整合 需要 Newman + 複雜設定 一行指令 簡單來說: ...

October 26, 2025 · 12 分鐘 · Peter

深入理解 Kubernetes Pod:從基礎概念到實戰應用

前言:為什麼需要 Pod? 在 Kubernetes 的世界裡,Pod 是一切的基礎。如果把 Kubernetes 比喻成一座城市,那麼 Pod 就是城市中的「最小住宅單位」。 但為什麼 Kubernetes 不直接管理容器(Container),而要多一層 Pod 的抽象? 簡單回答:因為容器太小,Pod 剛剛好。 想像你要管理一座城市的住宅: 如果直接管理每個「房間」(容器)→ 太細碎,管理成本太高 如果直接管理整棟「大樓」(Node)→ 太粗糙,缺乏彈性 所以我們需要「住宅單位」(Pod)→ 大小適中,便於管理 本文將深入探討: Pod 的核心概念與設計哲學 Pod 的內部架構與運作機制 Pod 網路模型與通訊方式 Pod 生命週期與狀態管理 Pod 設計模式與最佳實踐 實戰範例與 YAML 配置 Pod 核心概念:容器的邏輯主機 什麼是 Pod? 官方定義: Pod 是 Kubernetes 中最小的可部署計算單元,可以包含一個或多個容器,這些容器共享網路、儲存和其他資源。 生活化比喻: Pod 就像一個「邏輯主機」: 在傳統架構中,多個應用程式運行在同一台虛擬機上 在 Kubernetes 中,多個容器運行在同一個 Pod 上 Pod 提供了容器之間的「緊密耦合」環境 Pod 的三大核心特性 1. 共享網路命名空間 同一個 Pod 內的容器: ✅ 共享同一個 IP 位址 ✅ 可以透過 localhost 互相通訊 ✅ 但 Port 不能衝突(每個容器用不同 Port) 2. 共享儲存卷(Volume) ...

June 12, 2025 · 8 分鐘 · Peter