<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Infra 知識卡 on Tarragon</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/</link><description>Recent content in Infra 知識卡 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 26 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/infra/knowledge-cards/index.xml" rel="self" type="application/rss+xml"/><item><title>Infrastructure as Code (IaC)</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/iac/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/iac/</guid><description>&lt;p>Infrastructure as Code（IaC）的核心概念是用版本控制的程式碼描述基礎設施應該長什麼樣，再由工具負責比對「程式碼描述的目標狀態」與「雲端上的實際狀態」，算出差異並收斂。這個機制把基礎設施從「某個人在 Console 手動點出來的東西」變成「可版本控制、可 review、可重建的描述」。&lt;/p>
&lt;p>IaC 工具分兩條路線：宣告式 DSL（Terraform / OpenTofu，用 HCL 描述資源）與程式語言（AWS CDK / Pulumi，用 TypeScript / Python / Go 生成資源）。兩者都能達成「用程式碼描述、由工具收斂」的目標，差別在閱讀門檻與抽象能力。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>IaC 是 infra 系列的根概念，貫穿所有模組。&lt;a href="https://tarrragon.github.io/blog/infra/00-infra-mindset/infra-responsibility-maturity/" data-link-title="infra 的責任邊界、成熟度階梯與 day 1 鐵律" data-link-desc="基礎設施承擔五個面向的責任，每一面都有獨立的失效模式；成熟度階梯用來對齊現況而非追求滿分，day 1 鐵律則劃出早期團隊該優先鋪的地基">成熟度階梯&lt;/a>的第二階（宣告式 IaC）是 IaC 正式生效的起點，第三階（環境分離）和第四階（PR 流程治理）都建立在 IaC 之上。沒有 IaC，後續所有模組的能力都無法落地。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要 IaC 的訊號是規模與協作的函數：環境數量超過一套、多人同時改資源、環境事故頻率上升、外部稽核要求變更紀錄。詳見&lt;a href="https://tarrragon.github.io/blog/infra/before-infra/manual-environment-baseline/" data-link-title="手動環境的可控底線與納管準備" data-link-desc="還沒有 IaC 的環境怎麼守住底線、讓變更可追溯、降低未來納管成本，以及辨識何時該開始導入 IaC">模組負一：該開始導入 IaC 的訊號&lt;/a>。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>採用 IaC 時要決定的核心問題：&lt;/p>
&lt;ul>
&lt;li>工具選型：宣告式 DSL vs 程式語言，取捨在審查透明度 vs 抽象複用能力&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a> 的存放：remote backend 的選擇與保護&lt;/li>
&lt;li>Console 唯讀紀律：所有寫入操作回到程式碼，Console 只作觀察&lt;/li>
&lt;li>納管範圍：哪些資源先進 IaC、哪些暫時留在手動&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a> — IaC 工具追蹤現實的記憶機制&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift&lt;/a> — state 與現實不一致時的狀態&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/environment-separation/" data-link-title="環境分離" data-link-desc="把同一套基礎設施定義複製成多份隔離的執行實例，各有獨立 state 與故障半徑">環境分離&lt;/a> — 同一份 IaC 描述套用到多環境&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Infrastructure as Code（IaC）的核心概念是用版本控制的程式碼描述基礎設施應該長什麼樣，再由工具負責比對「程式碼描述的目標狀態」與「雲端上的實際狀態」，算出差異並收斂。這個機制把基礎設施從「某個人在 Console 手動點出來的東西」變成「可版本控制、可 review、可重建的描述」。</p>
<p>IaC 工具分兩條路線：宣告式 DSL（Terraform / OpenTofu，用 HCL 描述資源）與程式語言（AWS CDK / Pulumi，用 TypeScript / Python / Go 生成資源）。兩者都能達成「用程式碼描述、由工具收斂」的目標，差別在閱讀門檻與抽象能力。</p>
<h2 id="概念位置">概念位置</h2>
<p>IaC 是 infra 系列的根概念，貫穿所有模組。<a href="/blog/infra/00-infra-mindset/infra-responsibility-maturity/" data-link-title="infra 的責任邊界、成熟度階梯與 day 1 鐵律" data-link-desc="基礎設施承擔五個面向的責任，每一面都有獨立的失效模式；成熟度階梯用來對齊現況而非追求滿分，day 1 鐵律則劃出早期團隊該優先鋪的地基">成熟度階梯</a>的第二階（宣告式 IaC）是 IaC 正式生效的起點，第三階（環境分離）和第四階（PR 流程治理）都建立在 IaC 之上。沒有 IaC，後續所有模組的能力都無法落地。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要 IaC 的訊號是規模與協作的函數：環境數量超過一套、多人同時改資源、環境事故頻率上升、外部稽核要求變更紀錄。詳見<a href="/blog/infra/before-infra/manual-environment-baseline/" data-link-title="手動環境的可控底線與納管準備" data-link-desc="還沒有 IaC 的環境怎麼守住底線、讓變更可追溯、降低未來納管成本，以及辨識何時該開始導入 IaC">模組負一：該開始導入 IaC 的訊號</a>。</p>
<h2 id="設計責任">設計責任</h2>
<p>採用 IaC 時要決定的核心問題：</p>
<ul>
<li>工具選型：宣告式 DSL vs 程式語言，取捨在審查透明度 vs 抽象複用能力</li>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a> 的存放：remote backend 的選擇與保護</li>
<li>Console 唯讀紀律：所有寫入操作回到程式碼，Console 只作觀察</li>
<li>納管範圍：哪些資源先進 IaC、哪些暫時留在手動</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a> — IaC 工具追蹤現實的記憶機制</li>
<li><a href="/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift</a> — state 與現實不一致時的狀態</li>
<li><a href="/blog/infra/knowledge-cards/environment-separation/" data-link-title="環境分離" data-link-desc="把同一套基礎設施定義複製成多份隔離的執行實例，各有獨立 state 與故障半徑">環境分離</a> — 同一份 IaC 描述套用到多環境</li>
</ul>
]]></content:encoded></item><item><title>State（IaC 狀態檔）</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/state/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/state/</guid><description>&lt;p>State 是 IaC 工具用來記錄「上一次 apply 之後，每個資源在雲端長什麼樣」的快照。它的作用是讓工具能算出「程式碼描述的目標」與「雲端上的現況」之間的最小差異。沒有 state，工具每次都得把所有資源重新查一遍才知道該不該動，而且無法分辨「這個資源是我建的、該由我管」還是「別人手動建的、不歸我管」。&lt;/p>
&lt;p>State 裡通常含有資源的真實 ID、相依關係，以及部分敏感屬性（例如資料庫的初始密碼、private key 的輸出值）。這帶來兩條硬邊界：state 不能進 git（含敏感值，推進版控等於把密碼寫進每個 clone 的歷史）、state 不能只放本地（本地 state 的失敗模式是記憶綁在一台筆電上，多人並行 apply 會互相覆蓋）。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>State 是 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> 的記憶機制。&lt;a href="https://tarrragon.github.io/blog/infra/01-minimal-iac/iac-tool-state-backend/" data-link-title="IaC 工具選型與 state 地基" data-link-desc="Terraform / OpenTofu / CDK / Pulumi 的選型判準，state 作為 IaC 工具對現實的唯一記憶，以及 remote state backend 的自管與託管路線">模組一：最小可行 IaC&lt;/a> 的核心主題就是怎麼把 state 管好——remote backend、加密、鎖機制。State 管不好，後續所有 IaC 操作都建立在不可靠的記憶上。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>State 出問題的訊號包括：&lt;code>terraform plan&lt;/code> 顯示大量非預期的變更（state 與現實不一致）、兩個人同時 apply 後環境出現矛盾狀態、&lt;code>state list&lt;/code> 的資源數與 Console 上看到的不一致。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>管理 state 時要決定：&lt;/p>
&lt;ul>
&lt;li>存放位置：S3 + DynamoDB（自管）vs Terraform Cloud（託管），取捨在維運負擔 vs 控制權&lt;/li>
&lt;li>加密：state 含敏感值，落地加密（S3 SSE）是底線&lt;/li>
&lt;li>版本保留：bucket versioning 讓 state 損壞時能回捲到上一個正確版本&lt;/li>
&lt;li>鎖機制：防止兩個人同時 apply 互相覆蓋&lt;/li>
&lt;li>分割策略：一個大 state vs 多個小 state，取捨在引用便利性 vs 影響範圍控制&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> — state 是 IaC 工具的核心依賴&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift&lt;/a> — state 與現實的落差&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>State 是 IaC 工具用來記錄「上一次 apply 之後，每個資源在雲端長什麼樣」的快照。它的作用是讓工具能算出「程式碼描述的目標」與「雲端上的現況」之間的最小差異。沒有 state，工具每次都得把所有資源重新查一遍才知道該不該動，而且無法分辨「這個資源是我建的、該由我管」還是「別人手動建的、不歸我管」。</p>
<p>State 裡通常含有資源的真實 ID、相依關係，以及部分敏感屬性（例如資料庫的初始密碼、private key 的輸出值）。這帶來兩條硬邊界：state 不能進 git（含敏感值，推進版控等於把密碼寫進每個 clone 的歷史）、state 不能只放本地（本地 state 的失敗模式是記憶綁在一台筆電上，多人並行 apply 會互相覆蓋）。</p>
<h2 id="概念位置">概念位置</h2>
<p>State 是 <a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> 的記憶機制。<a href="/blog/infra/01-minimal-iac/iac-tool-state-backend/" data-link-title="IaC 工具選型與 state 地基" data-link-desc="Terraform / OpenTofu / CDK / Pulumi 的選型判準，state 作為 IaC 工具對現實的唯一記憶，以及 remote state backend 的自管與託管路線">模組一：最小可行 IaC</a> 的核心主題就是怎麼把 state 管好——remote backend、加密、鎖機制。State 管不好，後續所有 IaC 操作都建立在不可靠的記憶上。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>State 出問題的訊號包括：<code>terraform plan</code> 顯示大量非預期的變更（state 與現實不一致）、兩個人同時 apply 後環境出現矛盾狀態、<code>state list</code> 的資源數與 Console 上看到的不一致。</p>
<h2 id="設計責任">設計責任</h2>
<p>管理 state 時要決定：</p>
<ul>
<li>存放位置：S3 + DynamoDB（自管）vs Terraform Cloud（託管），取捨在維運負擔 vs 控制權</li>
<li>加密：state 含敏感值，落地加密（S3 SSE）是底線</li>
<li>版本保留：bucket versioning 讓 state 損壞時能回捲到上一個正確版本</li>
<li>鎖機制：防止兩個人同時 apply 互相覆蓋</li>
<li>分割策略：一個大 state vs 多個小 state，取捨在引用便利性 vs 影響範圍控制</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> — state 是 IaC 工具的核心依賴</li>
<li><a href="/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift</a> — state 與現實的落差</li>
</ul>
]]></content:encoded></item><item><title>Drift（設定漂移）</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/drift/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/drift/</guid><description>&lt;p>Drift 指的是 IaC 的 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">state&lt;/a> 記錄與雲端上的實際資源狀態之間的不一致。最常見的來源是有人繞過 IaC、直接在 Console 手動修改資源設定——state 不知道這次改動發生了，下一次 &lt;code>plan&lt;/code> 時工具會把手動改的設定判定為「不在我的記憶裡、要修正回程式碼的版本」。&lt;/p>
&lt;p>Drift 的代價會延遲浮現。手動改的當下看起來沒問題——設定改了、服務正常。問題出在後續某次不相關的 &lt;code>apply&lt;/code>：工具用過時的 state 去比對，把手動改的設定覆蓋掉，服務因此斷線，而且在 PR 裡看不到這件事發生過。Drift 累積越多，每次 &lt;code>apply&lt;/code> 的不確定性越高，最終團隊會開始害怕跑 &lt;code>apply&lt;/code>，IaC 名存實亡。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Drift 是 Console 唯讀鐵律存在的根本理由。&lt;a href="https://tarrragon.github.io/blog/infra/01-minimal-iac/console-readonly-minimal-viable/" data-link-title="Console 唯讀鐵律與最小可行資源集合" data-link-desc="Console 只用來看不用來改的操作紀律、drift 的延遲浮現與偵測，以及能跑出第一個完整 apply 迴路的最小資源集合">模組一：Console 唯讀鐵律&lt;/a>用權限機制（人類身分唯讀、寫入權限留給自動化身分）讓「在 Console 改不動」成為預設狀態，從源頭消除 drift 的產生。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>Drift 存在的訊號：&lt;code>terraform plan&lt;/code> 在沒人改過程式碼的情況下顯示變更（代表有人在 Console 動了東西）、團隊開始說「跑 plan 前先看看有沒有奇怪的差異」、某次例行 apply 意外改掉了不該改的設定。&lt;/p>
&lt;p>偵測 drift 的主動方式是定期跑 &lt;code>terraform plan&lt;/code> 但不 apply，把 diff 輸出當成 drift 偵測的報告。Terraform Cloud 有內建的 drift detection 功能，定期比對 state 與雲端現實。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>處理 drift 時要決定：&lt;/p>
&lt;ul>
&lt;li>偵測頻率：每次 PR 觸發 plan（被動偵測）vs 定期排程 plan（主動偵測）&lt;/li>
&lt;li>修正方向：把雲端改回程式碼的版本（&lt;code>apply&lt;/code>），還是把程式碼改成雲端的版本（更新 HCL）——取捨在「程式碼是 source of truth」vs「手動改的設定有它的理由」&lt;/li>
&lt;li>預防機制：Console 唯讀權限、CI gate 攔截未經 review 的 apply&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a> — drift 是 state 與現實的落差&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> — drift 破壞 IaC 的 source of truth 地位&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Drift 指的是 IaC 的 <a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">state</a> 記錄與雲端上的實際資源狀態之間的不一致。最常見的來源是有人繞過 IaC、直接在 Console 手動修改資源設定——state 不知道這次改動發生了，下一次 <code>plan</code> 時工具會把手動改的設定判定為「不在我的記憶裡、要修正回程式碼的版本」。</p>
<p>Drift 的代價會延遲浮現。手動改的當下看起來沒問題——設定改了、服務正常。問題出在後續某次不相關的 <code>apply</code>：工具用過時的 state 去比對，把手動改的設定覆蓋掉，服務因此斷線，而且在 PR 裡看不到這件事發生過。Drift 累積越多，每次 <code>apply</code> 的不確定性越高，最終團隊會開始害怕跑 <code>apply</code>，IaC 名存實亡。</p>
<h2 id="概念位置">概念位置</h2>
<p>Drift 是 Console 唯讀鐵律存在的根本理由。<a href="/blog/infra/01-minimal-iac/console-readonly-minimal-viable/" data-link-title="Console 唯讀鐵律與最小可行資源集合" data-link-desc="Console 只用來看不用來改的操作紀律、drift 的延遲浮現與偵測，以及能跑出第一個完整 apply 迴路的最小資源集合">模組一：Console 唯讀鐵律</a>用權限機制（人類身分唯讀、寫入權限留給自動化身分）讓「在 Console 改不動」成為預設狀態，從源頭消除 drift 的產生。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>Drift 存在的訊號：<code>terraform plan</code> 在沒人改過程式碼的情況下顯示變更（代表有人在 Console 動了東西）、團隊開始說「跑 plan 前先看看有沒有奇怪的差異」、某次例行 apply 意外改掉了不該改的設定。</p>
<p>偵測 drift 的主動方式是定期跑 <code>terraform plan</code> 但不 apply，把 diff 輸出當成 drift 偵測的報告。Terraform Cloud 有內建的 drift detection 功能，定期比對 state 與雲端現實。</p>
<h2 id="設計責任">設計責任</h2>
<p>處理 drift 時要決定：</p>
<ul>
<li>偵測頻率：每次 PR 觸發 plan（被動偵測）vs 定期排程 plan（主動偵測）</li>
<li>修正方向：把雲端改回程式碼的版本（<code>apply</code>），還是把程式碼改成雲端的版本（更新 HCL）——取捨在「程式碼是 source of truth」vs「手動改的設定有它的理由」</li>
<li>預防機制：Console 唯讀權限、CI gate 攔截未經 review 的 apply</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a> — drift 是 state 與現實的落差</li>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> — drift 破壞 IaC 的 source of truth 地位</li>
</ul>
]]></content:encoded></item><item><title>VPC（Virtual Private Cloud）</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/</guid><description>&lt;p>VPC（Virtual Private Cloud）是雲端帳號內的一塊邏輯隔離私有網段，是其餘所有網路切分的起點。在 VPC 裡開出來的所有資源預設只看得到同一個 VPC 內的成員，與其他 VPC、與其他帳號的網路天然隔離。沒有 VPC，&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">subnet&lt;/a> 與 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">security group&lt;/a> 無處依附。&lt;/p>
&lt;p>VPC 用 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/cidr/" data-link-title="CIDR（Classless Inter-Domain Routing）" data-link-desc="用前綴長度表示 IP 地址範圍的表示法，決定 VPC 與 subnet 的地址空間大小">CIDR&lt;/a> 區塊定義地址空間。建立時的 CIDR 大小是一次性決策——事後擴張地址空間在多數雲端平台上是麻煩且容易出錯的操作（AWS 允許追加 secondary CIDR，但追加的網段在 routing 與服務相容性上有限制）。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>VPC 是&lt;a href="https://tarrragon.github.io/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基&lt;/a>的最外層邊界。Infra 系列的網路設計從 VPC 開始：先圈定地址空間，再往內切 subnet、掛 route table、設 security group。環境之間的 VPC 怎麼分（每個環境一個 VPC），屬於&lt;a href="https://tarrragon.github.io/blog/infra/04-environment-separation/directory-module-parameterization/" data-link-title="環境分離與模組化 — 目錄結構、module 參數化與 retrofit 路徑" data-link-desc="用目錄結構在第一天就隔開 dev 與 prod 的 state，用 module 讓環境共用同一套邏輯只差參數，以及已經單環境跑起來後怎麼安全拆分">模組四：環境分離&lt;/a>的設計決策。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>VPC 設計需要關注的訊號：CIDR 空間快用完（subnet 切不出新的子網段）、需要跟其他 VPC 或地端互連時發現 CIDR 重疊（peering 無法建立）、服務被放在預設 VPC 裡（預設 VPC 是所有人共享的、CIDR 不可控的、security group 預設全通的）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>規劃 VPC 時要決定：&lt;/p>
&lt;ul>
&lt;li>CIDR 大小：&lt;code>/16&lt;/code> 提供約六萬五千個位址，對多數單一環境足夠&lt;/li>
&lt;li>不重疊：多個 VPC（不同環境或產品線）用連續但不重疊的大段分配&lt;/li>
&lt;li>DNS 設定：&lt;code>enable_dns_support&lt;/code> 和 &lt;code>enable_dns_hostnames&lt;/code> 在多數場景都該開啟&lt;/li>
&lt;li>預設 VPC 的處理：正式服務不該放在預設 VPC，新帳號的預設 VPC 可以刪除或保留唯讀&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — VPC 內按可用區與暴露程度切出的子網段&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — 掛在資源上的有狀態防火牆&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/cidr/" data-link-title="CIDR（Classless Inter-Domain Routing）" data-link-desc="用前綴長度表示 IP 地址範圍的表示法，決定 VPC 與 subnet 的地址空間大小">CIDR&lt;/a> — VPC 的地址空間定義方式&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT&lt;/a> — 讓 private subnet 出站的地址轉換機制&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>VPC（Virtual Private Cloud）是雲端帳號內的一塊邏輯隔離私有網段，是其餘所有網路切分的起點。在 VPC 裡開出來的所有資源預設只看得到同一個 VPC 內的成員，與其他 VPC、與其他帳號的網路天然隔離。沒有 VPC，<a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">subnet</a> 與 <a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">security group</a> 無處依附。</p>
<p>VPC 用 <a href="/blog/infra/knowledge-cards/cidr/" data-link-title="CIDR（Classless Inter-Domain Routing）" data-link-desc="用前綴長度表示 IP 地址範圍的表示法，決定 VPC 與 subnet 的地址空間大小">CIDR</a> 區塊定義地址空間。建立時的 CIDR 大小是一次性決策——事後擴張地址空間在多數雲端平台上是麻煩且容易出錯的操作（AWS 允許追加 secondary CIDR，但追加的網段在 routing 與服務相容性上有限制）。</p>
<h2 id="概念位置">概念位置</h2>
<p>VPC 是<a href="/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基</a>的最外層邊界。Infra 系列的網路設計從 VPC 開始：先圈定地址空間，再往內切 subnet、掛 route table、設 security group。環境之間的 VPC 怎麼分（每個環境一個 VPC），屬於<a href="/blog/infra/04-environment-separation/directory-module-parameterization/" data-link-title="環境分離與模組化 — 目錄結構、module 參數化與 retrofit 路徑" data-link-desc="用目錄結構在第一天就隔開 dev 與 prod 的 state，用 module 讓環境共用同一套邏輯只差參數，以及已經單環境跑起來後怎麼安全拆分">模組四：環境分離</a>的設計決策。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>VPC 設計需要關注的訊號：CIDR 空間快用完（subnet 切不出新的子網段）、需要跟其他 VPC 或地端互連時發現 CIDR 重疊（peering 無法建立）、服務被放在預設 VPC 裡（預設 VPC 是所有人共享的、CIDR 不可控的、security group 預設全通的）。</p>
<h2 id="設計責任">設計責任</h2>
<p>規劃 VPC 時要決定：</p>
<ul>
<li>CIDR 大小：<code>/16</code> 提供約六萬五千個位址，對多數單一環境足夠</li>
<li>不重疊：多個 VPC（不同環境或產品線）用連續但不重疊的大段分配</li>
<li>DNS 設定：<code>enable_dns_support</code> 和 <code>enable_dns_hostnames</code> 在多數場景都該開啟</li>
<li>預設 VPC 的處理：正式服務不該放在預設 VPC，新帳號的預設 VPC 可以刪除或保留唯讀</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — VPC 內按可用區與暴露程度切出的子網段</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — 掛在資源上的有狀態防火牆</li>
<li><a href="/blog/infra/knowledge-cards/cidr/" data-link-title="CIDR（Classless Inter-Domain Routing）" data-link-desc="用前綴長度表示 IP 地址範圍的表示法，決定 VPC 與 subnet 的地址空間大小">CIDR</a> — VPC 的地址空間定義方式</li>
<li><a href="/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT</a> — 讓 private subnet 出站的地址轉換機制</li>
</ul>
]]></content:encoded></item><item><title>Subnet（子網路）</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/</guid><description>&lt;p>Subnet 是 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> 內部按可用區（Availability Zone）與暴露程度切出來的子網段。一塊資源對外暴露到什麼程度，取決於它被放進哪個 subnet——技術上的差別在於該 subnet 關聯的 route table 裡有沒有一條指向 Internet Gateway 的預設路由。&lt;/p>
&lt;p>Subnet 分兩類：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Public subnet&lt;/strong>：route table 有 &lt;code>0.0.0.0/0 → Internet Gateway&lt;/code>，讓資源能被外部 IP 直接觸及。典型住戶是對外負載平衡器、&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT&lt;/a> Gateway。&lt;/li>
&lt;li>&lt;strong>Private subnet&lt;/strong>：route table 把 &lt;code>0.0.0.0/0&lt;/code> 指向 NAT Gateway，外部無法主動連入。典型住戶是應用伺服器、資料庫、快取。&lt;/li>
&lt;/ul>
&lt;p>Public subnet 的真實樣貌是「薄薄一層」——它通常只住入口設施，業務邏輯跟資料儲存都在 private subnet。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Subnet 是&lt;a href="https://tarrragon.github.io/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基&lt;/a>的中層邊界。VPC 定好地址空間後，subnet 決定「哪些資源能被外網碰到、哪些只能在內網存取」。每個 subnet 綁定單一可用區，高可用設計通常是每種角色跨至少兩個可用區各開一個 subnet。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>Subnet 配置有問題的訊號：應用伺服器被放在 public subnet 並配了公網 IP（管理埠暴露在掃描流量下）、private subnet 的服務拉不到外部套件（route table 沒指向健康的 NAT）、新服務上線時找不到適合的 subnet（CIDR 切得太小、空間不夠）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>規劃 subnet 時要決定：&lt;/p>
&lt;ul>
&lt;li>CIDR 切法：VPC 是 &lt;code>/16&lt;/code> 時，每個 subnet 用 &lt;code>/20&lt;/code>（約四千位址）可以在三個可用區各開 public + private 共六個 subnet&lt;/li>
&lt;li>跨可用區對稱：每種角色至少跨兩個 AZ，讓單一 AZ 故障時另一區能承接&lt;/li>
&lt;li>public 的住戶限制：只放入口設施，業務邏輯一律放 private&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> — subnet 的容器&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT&lt;/a> — 讓 private subnet 出站的機制&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — 掛在資源上的埠級存取控制&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Subnet 是 <a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> 內部按可用區（Availability Zone）與暴露程度切出來的子網段。一塊資源對外暴露到什麼程度，取決於它被放進哪個 subnet——技術上的差別在於該 subnet 關聯的 route table 裡有沒有一條指向 Internet Gateway 的預設路由。</p>
<p>Subnet 分兩類：</p>
<ul>
<li><strong>Public subnet</strong>：route table 有 <code>0.0.0.0/0 → Internet Gateway</code>，讓資源能被外部 IP 直接觸及。典型住戶是對外負載平衡器、<a href="/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT</a> Gateway。</li>
<li><strong>Private subnet</strong>：route table 把 <code>0.0.0.0/0</code> 指向 NAT Gateway，外部無法主動連入。典型住戶是應用伺服器、資料庫、快取。</li>
</ul>
<p>Public subnet 的真實樣貌是「薄薄一層」——它通常只住入口設施，業務邏輯跟資料儲存都在 private subnet。</p>
<h2 id="概念位置">概念位置</h2>
<p>Subnet 是<a href="/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基</a>的中層邊界。VPC 定好地址空間後，subnet 決定「哪些資源能被外網碰到、哪些只能在內網存取」。每個 subnet 綁定單一可用區，高可用設計通常是每種角色跨至少兩個可用區各開一個 subnet。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>Subnet 配置有問題的訊號：應用伺服器被放在 public subnet 並配了公網 IP（管理埠暴露在掃描流量下）、private subnet 的服務拉不到外部套件（route table 沒指向健康的 NAT）、新服務上線時找不到適合的 subnet（CIDR 切得太小、空間不夠）。</p>
<h2 id="設計責任">設計責任</h2>
<p>規劃 subnet 時要決定：</p>
<ul>
<li>CIDR 切法：VPC 是 <code>/16</code> 時，每個 subnet 用 <code>/20</code>（約四千位址）可以在三個可用區各開 public + private 共六個 subnet</li>
<li>跨可用區對稱：每種角色至少跨兩個 AZ，讓單一 AZ 故障時另一區能承接</li>
<li>public 的住戶限制：只放入口設施，業務邏輯一律放 private</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> — subnet 的容器</li>
<li><a href="/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT</a> — 讓 private subnet 出站的機制</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — 掛在資源上的埠級存取控制</li>
</ul>
]]></content:encoded></item><item><title>Security Group</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/</guid><description>&lt;p>Security group 是掛在資源網卡（ENI）層級的有狀態防火牆，規則描述的是「哪些來源能連到這個資源的哪個埠」。「有狀態」的意思是放行一條入站連線後，對應的回應出站自動允許——規則只需描述入站方向想開放什麼。&lt;/p>
&lt;p>設計原則是最小開放：每條規則只開「這個服務確實需要被誰連的那個埠」。資料庫的 security group 入站只允許來自應用層 security group 的資料庫埠（如 5432），而不是某個 IP 範圍。用 security group 互相引用（source 指向另一個 group 而非 CIDR）讓規則跟著成員身分走、不跟著位址走——應用節點會隨擴縮而換 IP，引用 group 不會因此失效。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Security group 是&lt;a href="https://tarrragon.github.io/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基&lt;/a>的最內層邊界——貼著服務的最後一道網路防線。即使封包順著 route table 抵達了 private &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">subnet&lt;/a>，security group 仍能逐埠決定放不放行。&lt;a href="https://tarrragon.github.io/blog/infra/07-infra-as-pr/plan-review-apply-guardrails/" data-link-title="infra 走 PR 流程與自動化護欄" data-link-desc="infra 變更走 PR → plan → review diff → 合併 → apply，配 fmt / validate / tflint / checkov / tfsec 與 Atlantis 自動化，讓基礎設施可審查、可回溯、可交接">模組七：infra 走 PR 流程&lt;/a>用 tfsec / checkov 在 CI 攔截 &lt;code>0.0.0.0/0&lt;/code> 全開的規則。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>Security group 需要收斂的訊號：入站來源是 &lt;code>0.0.0.0/0&lt;/code>（允許全網連入），且目標埠是資料庫（5432、3306、6379）或管理埠（22、3389）——合理出現 &lt;code>0.0.0.0/0&lt;/code> 的位置只有對外負載平衡器的 80 / 443。盤點方式是列出所有 source 為 &lt;code>0.0.0.0/0&lt;/code> 的規則，逐條問「這個埠需要全世界都連得到嗎」。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>設計 security group 時要決定：&lt;/p>
&lt;ul>
&lt;li>引用方式：用 group 互相引用（推薦）vs 用 CIDR 限定範圍&lt;/li>
&lt;li>開放範圍：只開需要的埠與來源，&lt;code>0.0.0.0/0&lt;/code> 只給對外 LB&lt;/li>
&lt;li>管理埠存取：SSH（22）改用 SSM Session Manager 取代，從公網清單上拿掉&lt;/li>
&lt;li>與 NACL 的分工：security group 是主力（有狀態、group 引用），NACL 留給少數需要 subnet 層顯式 deny 的情境&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> — security group 依附的網路容器&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — security group 與 subnet 各守不同層級的邊界&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Security group 是掛在資源網卡（ENI）層級的有狀態防火牆，規則描述的是「哪些來源能連到這個資源的哪個埠」。「有狀態」的意思是放行一條入站連線後，對應的回應出站自動允許——規則只需描述入站方向想開放什麼。</p>
<p>設計原則是最小開放：每條規則只開「這個服務確實需要被誰連的那個埠」。資料庫的 security group 入站只允許來自應用層 security group 的資料庫埠（如 5432），而不是某個 IP 範圍。用 security group 互相引用（source 指向另一個 group 而非 CIDR）讓規則跟著成員身分走、不跟著位址走——應用節點會隨擴縮而換 IP，引用 group 不會因此失效。</p>
<h2 id="概念位置">概念位置</h2>
<p>Security group 是<a href="/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基</a>的最內層邊界——貼著服務的最後一道網路防線。即使封包順著 route table 抵達了 private <a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">subnet</a>，security group 仍能逐埠決定放不放行。<a href="/blog/infra/07-infra-as-pr/plan-review-apply-guardrails/" data-link-title="infra 走 PR 流程與自動化護欄" data-link-desc="infra 變更走 PR → plan → review diff → 合併 → apply，配 fmt / validate / tflint / checkov / tfsec 與 Atlantis 自動化，讓基礎設施可審查、可回溯、可交接">模組七：infra 走 PR 流程</a>用 tfsec / checkov 在 CI 攔截 <code>0.0.0.0/0</code> 全開的規則。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>Security group 需要收斂的訊號：入站來源是 <code>0.0.0.0/0</code>（允許全網連入），且目標埠是資料庫（5432、3306、6379）或管理埠（22、3389）——合理出現 <code>0.0.0.0/0</code> 的位置只有對外負載平衡器的 80 / 443。盤點方式是列出所有 source 為 <code>0.0.0.0/0</code> 的規則，逐條問「這個埠需要全世界都連得到嗎」。</p>
<h2 id="設計責任">設計責任</h2>
<p>設計 security group 時要決定：</p>
<ul>
<li>引用方式：用 group 互相引用（推薦）vs 用 CIDR 限定範圍</li>
<li>開放範圍：只開需要的埠與來源，<code>0.0.0.0/0</code> 只給對外 LB</li>
<li>管理埠存取：SSH（22）改用 SSM Session Manager 取代，從公網清單上拿掉</li>
<li>與 NACL 的分工：security group 是主力（有狀態、group 引用），NACL 留給少數需要 subnet 層顯式 deny 的情境</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> — security group 依附的網路容器</li>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — security group 與 subnet 各守不同層級的邊界</li>
</ul>
]]></content:encoded></item><item><title>NAT Gateway</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/nat/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/nat/</guid><description>&lt;p>NAT Gateway（Network Address Translation Gateway）的核心職責是讓 private subnet 的資源能主動發起對外連線（拉套件、呼叫第三方 API、下載 OS 更新），同時不開放任何外部主動發起的入站連線。它借用一個公網 IP 把出站封包送出去，再把回應導回原請求者。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>NAT Gateway 在網路地基裡的角色是 private subnet 的出站閘道。它解決的問題是：private subnet 的設計意圖是「外部連不進來」，但服務仍需要主動對外。沒有 NAT，private subnet 的資源完全無法對外通訊 — 連 &lt;code>apt update&lt;/code> 或 &lt;code>pip install&lt;/code> 都做不到。&lt;/p>
&lt;p>NAT Gateway 是綁定單一可用區的資源，活在某個 public subnet 裡。這帶來一個架構取捨：共享一個 NAT（成本低、出站方向有單點）還是每個可用區各放一個（成本高、出站與 subnet 冗餘對齊）。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下狀況指向 NAT 相關問題：&lt;/p>
&lt;ul>
&lt;li>Private subnet 的服務拉不到外部套件或第三方 API 全部逾時 — 先查 route table 有沒有指向健康的 NAT&lt;/li>
&lt;li>只有某一個可用區的節點受影響 — 該區的 NAT 或其所在 subnet 可能故障&lt;/li>
&lt;li>雲帳單裡 NAT Gateway 的流量費用異常高 — 大量走 NAT 的流量（S3 備份、跨區同步）可用 VPC Endpoint 繞過&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 NAT Gateway 時要決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>數量&lt;/strong>：每個可用區一個（可用性優先）還是全 VPC 共享一個（成本優先）。每個 NAT 固定月費約 $32 加流量費 $0.045/GB&lt;/li>
&lt;li>&lt;strong>高流量路徑&lt;/strong>：對 AWS 自家服務的流量（S3、DynamoDB）改用 Gateway Endpoint 直連，繞過 NAT 省流量費&lt;/li>
&lt;li>&lt;strong>route table 關聯&lt;/strong>：每個 private subnet 的 route table 要明確指向哪個 NAT&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — NAT 放在 public subnet、服務放在 private subnet&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> — NAT 屬於 VPC 內部的出站路徑設施&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>NAT Gateway（Network Address Translation Gateway）的核心職責是讓 private subnet 的資源能主動發起對外連線（拉套件、呼叫第三方 API、下載 OS 更新），同時不開放任何外部主動發起的入站連線。它借用一個公網 IP 把出站封包送出去，再把回應導回原請求者。</p>
<h2 id="概念位置">概念位置</h2>
<p>NAT Gateway 在網路地基裡的角色是 private subnet 的出站閘道。它解決的問題是：private subnet 的設計意圖是「外部連不進來」，但服務仍需要主動對外。沒有 NAT，private subnet 的資源完全無法對外通訊 — 連 <code>apt update</code> 或 <code>pip install</code> 都做不到。</p>
<p>NAT Gateway 是綁定單一可用區的資源，活在某個 public subnet 裡。這帶來一個架構取捨：共享一個 NAT（成本低、出站方向有單點）還是每個可用區各放一個（成本高、出站與 subnet 冗餘對齊）。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下狀況指向 NAT 相關問題：</p>
<ul>
<li>Private subnet 的服務拉不到外部套件或第三方 API 全部逾時 — 先查 route table 有沒有指向健康的 NAT</li>
<li>只有某一個可用區的節點受影響 — 該區的 NAT 或其所在 subnet 可能故障</li>
<li>雲帳單裡 NAT Gateway 的流量費用異常高 — 大量走 NAT 的流量（S3 備份、跨區同步）可用 VPC Endpoint 繞過</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>使用 NAT Gateway 時要決定：</p>
<ul>
<li><strong>數量</strong>：每個可用區一個（可用性優先）還是全 VPC 共享一個（成本優先）。每個 NAT 固定月費約 $32 加流量費 $0.045/GB</li>
<li><strong>高流量路徑</strong>：對 AWS 自家服務的流量（S3、DynamoDB）改用 Gateway Endpoint 直連，繞過 NAT 省流量費</li>
<li><strong>route table 關聯</strong>：每個 private subnet 的 route table 要明確指向哪個 NAT</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — NAT 放在 public subnet、服務放在 private subnet</li>
<li><a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> — NAT 屬於 VPC 內部的出站路徑設施</li>
</ul>
]]></content:encoded></item><item><title>OIDC 聯合</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/oidc/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/oidc/</guid><description>&lt;p>OIDC（OpenID Connect）聯合的核心職責是讓跑在雲外的 CI/CD 平台（GitHub Actions、GitLab CI）用每次執行才簽發、幾分鐘後就失效的短期憑證存取雲端資源，從根本上消除「在 CI 環境裡存放長期 access key」這個攻擊面。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>OIDC 聯合在身分與憑證地基裡的角色是「雲外機器身分的認證機制」。跑在雲上的 workload（EC2、ECS task）可以用平台原生的 instance profile 或 task role 取得短期憑證；跑在雲外的 CI/CD 沒有這個管道，OIDC 就是替代方案。&lt;/p>
&lt;p>運作方式是建立信任關係：雲端帳號信任某個外部 identity provider（如 GitHub Actions 的 OIDC issuer），CI 執行時平台簽發一個帶 claim 的 token（描述哪個 repo、哪個 branch、哪個 workflow），雲端用這個 token 換出一段臨時憑證。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下狀況指向 OIDC 相關問題：&lt;/p>
&lt;ul>
&lt;li>CI pipeline 裡有 &lt;code>AWS_ACCESS_KEY_ID&lt;/code> 和 &lt;code>AWS_SECRET_ACCESS_KEY&lt;/code> 環境變數 — 這是長期 key，應該替換成 OIDC&lt;/li>
&lt;li>Trust policy 只驗 issuer 不驗 repo — 任何掛在同一個 CI 平台的專案都能假扮這個 role&lt;/li>
&lt;li>Pipeline 突然無法取得權限 — 可能是 trust policy 的 condition 跟 token claim 不匹配（常見於 repo 改名或 branch 改名後）&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>設定 OIDC 聯合時要決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Trust policy 的 claim 收斂&lt;/strong>：限定 issuer + audience + 特定 repo + 特定 branch，每個條件都收到最緊&lt;/li>
&lt;li>&lt;strong>Role 的權限範圍&lt;/strong>：OIDC 換到的 role 仍然要遵循最小權限 — 只給 pipeline 需要的 action&lt;/li>
&lt;li>&lt;strong>Plan 與 apply 分開的 role&lt;/strong>：plan 只需要 read 權限、apply 需要 write 權限，用兩個 role 降低 PR 階段的風險&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> — OIDC 是 IAM 身分系統的一種外部身分來源&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — OIDC 解的是身分層的認證問題，跟網路層的 security group 正交&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>OIDC（OpenID Connect）聯合的核心職責是讓跑在雲外的 CI/CD 平台（GitHub Actions、GitLab CI）用每次執行才簽發、幾分鐘後就失效的短期憑證存取雲端資源，從根本上消除「在 CI 環境裡存放長期 access key」這個攻擊面。</p>
<h2 id="概念位置">概念位置</h2>
<p>OIDC 聯合在身分與憑證地基裡的角色是「雲外機器身分的認證機制」。跑在雲上的 workload（EC2、ECS task）可以用平台原生的 instance profile 或 task role 取得短期憑證；跑在雲外的 CI/CD 沒有這個管道，OIDC 就是替代方案。</p>
<p>運作方式是建立信任關係：雲端帳號信任某個外部 identity provider（如 GitHub Actions 的 OIDC issuer），CI 執行時平台簽發一個帶 claim 的 token（描述哪個 repo、哪個 branch、哪個 workflow），雲端用這個 token 換出一段臨時憑證。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下狀況指向 OIDC 相關問題：</p>
<ul>
<li>CI pipeline 裡有 <code>AWS_ACCESS_KEY_ID</code> 和 <code>AWS_SECRET_ACCESS_KEY</code> 環境變數 — 這是長期 key，應該替換成 OIDC</li>
<li>Trust policy 只驗 issuer 不驗 repo — 任何掛在同一個 CI 平台的專案都能假扮這個 role</li>
<li>Pipeline 突然無法取得權限 — 可能是 trust policy 的 condition 跟 token claim 不匹配（常見於 repo 改名或 branch 改名後）</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>設定 OIDC 聯合時要決定：</p>
<ul>
<li><strong>Trust policy 的 claim 收斂</strong>：限定 issuer + audience + 特定 repo + 特定 branch，每個條件都收到最緊</li>
<li><strong>Role 的權限範圍</strong>：OIDC 換到的 role 仍然要遵循最小權限 — 只給 pipeline 需要的 action</li>
<li><strong>Plan 與 apply 分開的 role</strong>：plan 只需要 read 權限、apply 需要 write 權限，用兩個 role 降低 PR 階段的風險</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> — OIDC 是 IAM 身分系統的一種外部身分來源</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — OIDC 解的是身分層的認證問題，跟網路層的 security group 正交</li>
</ul>
]]></content:encoded></item><item><title>環境分離</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/environment-separation/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/environment-separation/</guid><description>&lt;p>環境分離的核心職責是讓 dev 的實驗、staging 的驗證、production 的真實流量彼此不可見也不可達 — 在 dev 跑壞一個資料庫、套錯一條 security group 規則時，production 完全無感。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>環境分離在 infra 成熟度階梯上對應第三階。它建立在宣告式 IaC（第二階）的基礎上 — 有了 state 追蹤和模組化描述之後，才能用「同一份 code、不同參數」的方式複製出多個隔離環境。&lt;/p>
&lt;p>分離的實作方式有一條隔離強度光譜：從帳號級（不同雲端帳號，最強隔離）到目錄級（同一 repo 內各環境一個目錄，各自持有 state）到 workspace 級（同一份 code 用執行期切換 state，隔離最弱）。多數早期團隊在目錄級落腳，因為它在顯式邊界與維運成本之間取得平衡。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下狀況指向環境分離不足：&lt;/p>
&lt;ul>
&lt;li>在 staging 測試的變更意外影響了 production 的資源 — dev 跟 prod 共用同一份 state&lt;/li>
&lt;li>某人的 &lt;code>terraform apply&lt;/code> 把另一個環境的資源改掉了 — workspace 的隱性狀態切換導致打錯環境&lt;/li>
&lt;li>dev 與 prod 的設定差異散落在 code 裡的 &lt;code>if env == &amp;quot;prod&amp;quot;&lt;/code> 判斷 — 環境差異沒有集中在參數值裡&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>環境分離的設計要決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>隔離層級&lt;/strong>：帳號級、目錄級、還是 workspace 級。判斷依據是團隊規模、合規要求、與維運餘裕&lt;/li>
&lt;li>&lt;strong>參數化邊界&lt;/strong>：dev 與 prod 之間的差異全部用參數表達（instance size、multi-AZ、backup retention），module 內部不寫環境判斷&lt;/li>
&lt;li>&lt;strong>state 位址分離&lt;/strong>：每個環境的 state backend 位址獨立，互不交叉&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> — 環境分離的前提是有可重用的 IaC 描述&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a> — 每個環境持有獨立的 state 檔&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift&lt;/a> — 環境分離降低 drift 的跨環境影響範圍&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>環境分離的核心職責是讓 dev 的實驗、staging 的驗證、production 的真實流量彼此不可見也不可達 — 在 dev 跑壞一個資料庫、套錯一條 security group 規則時，production 完全無感。</p>
<h2 id="概念位置">概念位置</h2>
<p>環境分離在 infra 成熟度階梯上對應第三階。它建立在宣告式 IaC（第二階）的基礎上 — 有了 state 追蹤和模組化描述之後，才能用「同一份 code、不同參數」的方式複製出多個隔離環境。</p>
<p>分離的實作方式有一條隔離強度光譜：從帳號級（不同雲端帳號，最強隔離）到目錄級（同一 repo 內各環境一個目錄，各自持有 state）到 workspace 級（同一份 code 用執行期切換 state，隔離最弱）。多數早期團隊在目錄級落腳，因為它在顯式邊界與維運成本之間取得平衡。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下狀況指向環境分離不足：</p>
<ul>
<li>在 staging 測試的變更意外影響了 production 的資源 — dev 跟 prod 共用同一份 state</li>
<li>某人的 <code>terraform apply</code> 把另一個環境的資源改掉了 — workspace 的隱性狀態切換導致打錯環境</li>
<li>dev 與 prod 的設定差異散落在 code 裡的 <code>if env == &quot;prod&quot;</code> 判斷 — 環境差異沒有集中在參數值裡</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>環境分離的設計要決定：</p>
<ul>
<li><strong>隔離層級</strong>：帳號級、目錄級、還是 workspace 級。判斷依據是團隊規模、合規要求、與維運餘裕</li>
<li><strong>參數化邊界</strong>：dev 與 prod 之間的差異全部用參數表達（instance size、multi-AZ、backup retention），module 內部不寫環境判斷</li>
<li><strong>state 位址分離</strong>：每個環境的 state backend 位址獨立，互不交叉</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> — 環境分離的前提是有可重用的 IaC 描述</li>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a> — 每個環境持有獨立的 state 檔</li>
<li><a href="/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift</a> — 環境分離降低 drift 的跨環境影響範圍</li>
</ul>
]]></content:encoded></item><item><title>CloudTrail</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/cloudtrail/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/cloudtrail/</guid><description>&lt;p>CloudTrail 的核心職責是把 AWS 帳號內每一個 API 呼叫記錄成可查詢的稽核日誌 — 哪個身分、在什麼時間、對哪個資源、呼叫了哪個 API、結果是成功還是拒絕。它是事故排查和合規稽核的事實來源。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>CloudTrail 在 infra 治理裡的角色是「發生了什麼」的最後防線。人工變更日誌記錄「為什麼改」，CloudTrail 記錄「改了什麼」— 兩者一起才能從事故回推到可回退的操作。&lt;/p>
&lt;p>CloudTrail 預設記錄 management event（建立、修改、刪除資源的 API 呼叫）並保留 90 天可查閱。要長期保存或記錄 data event（S3 物件存取、Lambda 呼叫等更細粒度的操作），需要建立 trail 並指定 S3 bucket 儲存。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下狀況指向 CloudTrail 的使用場景：&lt;/p>
&lt;ul>
&lt;li>事故排查需要回答「誰在過去 24 小時改過這個 security group」— CloudTrail 的 &lt;code>LookupEvents&lt;/code> API 可以按事件名稱、資源類型或使用者名稱查詢&lt;/li>
&lt;li>安全稽核要求提供「過去 90 天內所有 IAM policy 變更的紀錄」— CloudTrail 是標準的證據來源&lt;/li>
&lt;li>發現不預期的資源變更（drift），需要確認是人為操作還是自動化觸發 — CloudTrail 的 &lt;code>userIdentity&lt;/code> 欄位區分人類使用者和 assume-role 的服務&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 CloudTrail 時要決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>保留期限&lt;/strong>：預設 90 天免費查閱；超過需要建 trail 存到 S3，費用是 S3 儲存成本&lt;/li>
&lt;li>&lt;strong>事件範圍&lt;/strong>：management event 預設開啟；data event（S3 物件讀寫、Lambda invoke）要額外設定，且量大時儲存成本可觀&lt;/li>
&lt;li>&lt;strong>跨帳號整合&lt;/strong>：多帳號架構下，Organization trail 可以把所有帳號的事件集中到一個 S3 bucket&lt;/li>
&lt;li>&lt;strong>存取控制&lt;/strong>：CloudTrail 的 S3 bucket 本身要限制存取 — 能修改稽核日誌等於能掩蓋操作痕跡&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> — CloudTrail 記錄的是 IAM 身分的 API 呼叫&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift&lt;/a> — CloudTrail 是追查 drift 來源（誰手動改了什麼）的工具&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>CloudTrail 的核心職責是把 AWS 帳號內每一個 API 呼叫記錄成可查詢的稽核日誌 — 哪個身分、在什麼時間、對哪個資源、呼叫了哪個 API、結果是成功還是拒絕。它是事故排查和合規稽核的事實來源。</p>
<h2 id="概念位置">概念位置</h2>
<p>CloudTrail 在 infra 治理裡的角色是「發生了什麼」的最後防線。人工變更日誌記錄「為什麼改」，CloudTrail 記錄「改了什麼」— 兩者一起才能從事故回推到可回退的操作。</p>
<p>CloudTrail 預設記錄 management event（建立、修改、刪除資源的 API 呼叫）並保留 90 天可查閱。要長期保存或記錄 data event（S3 物件存取、Lambda 呼叫等更細粒度的操作），需要建立 trail 並指定 S3 bucket 儲存。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下狀況指向 CloudTrail 的使用場景：</p>
<ul>
<li>事故排查需要回答「誰在過去 24 小時改過這個 security group」— CloudTrail 的 <code>LookupEvents</code> API 可以按事件名稱、資源類型或使用者名稱查詢</li>
<li>安全稽核要求提供「過去 90 天內所有 IAM policy 變更的紀錄」— CloudTrail 是標準的證據來源</li>
<li>發現不預期的資源變更（drift），需要確認是人為操作還是自動化觸發 — CloudTrail 的 <code>userIdentity</code> 欄位區分人類使用者和 assume-role 的服務</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>使用 CloudTrail 時要決定：</p>
<ul>
<li><strong>保留期限</strong>：預設 90 天免費查閱；超過需要建 trail 存到 S3，費用是 S3 儲存成本</li>
<li><strong>事件範圍</strong>：management event 預設開啟；data event（S3 物件讀寫、Lambda invoke）要額外設定，且量大時儲存成本可觀</li>
<li><strong>跨帳號整合</strong>：多帳號架構下，Organization trail 可以把所有帳號的事件集中到一個 S3 bucket</li>
<li><strong>存取控制</strong>：CloudTrail 的 S3 bucket 本身要限制存取 — 能修改稽核日誌等於能掩蓋操作痕跡</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> — CloudTrail 記錄的是 IAM 身分的 API 呼叫</li>
<li><a href="/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift</a> — CloudTrail 是追查 drift 來源（誰手動改了什麼）的工具</li>
</ul>
]]></content:encoded></item><item><title>ECS</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/</guid><description>&lt;p>ECS（Elastic Container Service）的核心職責是把容器映像排程到運算資源上執行，並管理它們的生命週期 — 健康檢查、失敗重啟、滾動更新。它是 AWS 上容器工作負載的預設起點，心智負擔低於 Kubernetes（EKS），但編排彈性也較受限。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>ECS 在核心服務層裡的角色是「應用程式的執行載體」。它跑在 VPC 的 private subnet 裡，用 IAM task role 存取其他 AWS 資源，前面掛 ALB 接收流量。IaC 描述 ECS 時，重點在「接線」（subnet、security group、IAM role、target group）而非容器映像版本 — 映像版本由 CI/CD 在部署期注入。&lt;/p>
&lt;p>ECS 的執行模式分 EC2 launch type（自己管運算實例、要管 AMI 更新與 capacity provider）和 Fargate launch type（AWS 代管運算、不需管實例）。Fargate 進一步降低運維面，代價是單位成本較高（同規格約多 20-40%）且不支援 GPU workload。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下狀況指向 ECS 相關問題：&lt;/p>
&lt;ul>
&lt;li>Task 頻繁被 kill 後重啟 — 健康檢查失敗或 OOM，先看 task 的 stopped reason 和 CloudWatch log&lt;/li>
&lt;li>部署後新版本遲遲不上線 — rolling update 的 minimum healthy percent 設太高，新 task 啟動空間不足&lt;/li>
&lt;li>Task 無法拉到 ECR image — 通常是 private subnet 沒有 NAT 或 VPC Endpoint 到 ECR&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 ECS 時要決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Launch type&lt;/strong>：Fargate（低運維、較高成本）還是 EC2（低成本、要管實例）。多數 web API 的初始選擇是 Fargate，流量穩定後再評估 EC2&lt;/li>
&lt;li>&lt;strong>Task IAM role&lt;/strong>：task execution role（拉 image 和寫 log 用）和 task role（應用程式存取其他 AWS 資源用）是兩個不同的 role，不要混用&lt;/li>
&lt;li>&lt;strong>映像版本解耦&lt;/strong>：task definition 裡的 image tag 由 CI/CD 部署期注入，infra code 不寫死版本號&lt;/li>
&lt;li>&lt;strong>Auto-scaling 指標&lt;/strong>：用 CPU / memory 還是 ALB request count，取決於服務是計算密集還是 IO 密集&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — ECS task 跑在 private subnet 裡&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — ECS service 套用 security group 控制入站&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> — task role 與 execution role 是 ECS 的兩個身分接線&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a> — 流量透過 ALB target group 導入 ECS task&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>ECS（Elastic Container Service）的核心職責是把容器映像排程到運算資源上執行，並管理它們的生命週期 — 健康檢查、失敗重啟、滾動更新。它是 AWS 上容器工作負載的預設起點，心智負擔低於 Kubernetes（EKS），但編排彈性也較受限。</p>
<h2 id="概念位置">概念位置</h2>
<p>ECS 在核心服務層裡的角色是「應用程式的執行載體」。它跑在 VPC 的 private subnet 裡，用 IAM task role 存取其他 AWS 資源，前面掛 ALB 接收流量。IaC 描述 ECS 時，重點在「接線」（subnet、security group、IAM role、target group）而非容器映像版本 — 映像版本由 CI/CD 在部署期注入。</p>
<p>ECS 的執行模式分 EC2 launch type（自己管運算實例、要管 AMI 更新與 capacity provider）和 Fargate launch type（AWS 代管運算、不需管實例）。Fargate 進一步降低運維面，代價是單位成本較高（同規格約多 20-40%）且不支援 GPU workload。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下狀況指向 ECS 相關問題：</p>
<ul>
<li>Task 頻繁被 kill 後重啟 — 健康檢查失敗或 OOM，先看 task 的 stopped reason 和 CloudWatch log</li>
<li>部署後新版本遲遲不上線 — rolling update 的 minimum healthy percent 設太高，新 task 啟動空間不足</li>
<li>Task 無法拉到 ECR image — 通常是 private subnet 沒有 NAT 或 VPC Endpoint 到 ECR</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>使用 ECS 時要決定：</p>
<ul>
<li><strong>Launch type</strong>：Fargate（低運維、較高成本）還是 EC2（低成本、要管實例）。多數 web API 的初始選擇是 Fargate，流量穩定後再評估 EC2</li>
<li><strong>Task IAM role</strong>：task execution role（拉 image 和寫 log 用）和 task role（應用程式存取其他 AWS 資源用）是兩個不同的 role，不要混用</li>
<li><strong>映像版本解耦</strong>：task definition 裡的 image tag 由 CI/CD 部署期注入，infra code 不寫死版本號</li>
<li><strong>Auto-scaling 指標</strong>：用 CPU / memory 還是 ALB request count，取決於服務是計算密集還是 IO 密集</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — ECS task 跑在 private subnet 裡</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — ECS service 套用 security group 控制入站</li>
<li><a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> — task role 與 execution role 是 ECS 的兩個身分接線</li>
<li><a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a> — 流量透過 ALB target group 導入 ECS task</li>
</ul>
]]></content:encoded></item><item><title>ALB</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/alb/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/alb/</guid><description>&lt;p>ALB（Application Load Balancer）的核心職責是接收外部流量、根據規則（path、host header）把請求路由到後端的 target group，並用健康檢查持續驗證後端是否能服務。它是系統對外的第一個接觸點，跑在 public subnet 裡。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>ALB 在核心服務層裡的角色是「入口設施」。它掛在 public subnet 的 security group 上（入站允許 80/443），把流量導向 private subnet 裡的 ECS task 或 EC2 instance。ALB 本身是 stateless 的 — 重建一個 ALB 不會遺失資料，但會換掉它的 DNS 名稱，所以對外服務通常在 ALB 前面掛一個穩定的 Route 53 alias record。&lt;/p>
&lt;p>TLS 終結是 ALB 的標準職責：HTTPS listener 引用 ACM（AWS Certificate Manager）簽發的憑證，ALB 處理加解密，後端收到的是 HTTP 明文。憑證由 ACM 自動續期，IaC 用 DNS 驗證方式描述憑證 — 讓「憑證存在、續期、掛載」整條鏈都進版本控制。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下狀況指向 ALB 相關問題：&lt;/p>
&lt;ul>
&lt;li>使用者看到 502 — ALB 轉發請求但後端回應異常（健康檢查可能通過但實際請求處理失敗），查 target group 的健康狀態和後端 log&lt;/li>
&lt;li>使用者看到 503 — target group 裡沒有健康的後端，通常是部署期間所有舊 task 停了但新 task 還沒通過健康檢查&lt;/li>
&lt;li>HTTPS 憑證過期警告 — 如果用 ACM 搭配 DNS 驗證，憑證自動續期；看到過期警告代表 DNS 驗證記錄被刪了或 ACM 服務異常&lt;/li>
&lt;/ul>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 ALB 時要決定：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>健康檢查參數&lt;/strong>：檢查路徑（用應用層的 health endpoint、不用根路徑）、間隔、閾值。閾值太寬鬆會把壞掉的後端留在輪替裡，太嚴格會在部署瞬間誤判&lt;/li>
&lt;li>&lt;strong>HTTP → HTTPS redirect&lt;/strong>：port 80 的 listener 設定固定回應 301 redirect 到 443，確保所有流量走加密&lt;/li>
&lt;li>&lt;strong>TLS 憑證&lt;/strong>：用 ACM 搭配 DNS 驗證，讓憑證的簽發和續期自動化&lt;/li>
&lt;li>&lt;strong>穩定 DNS&lt;/strong>：ALB 前面掛 Route 53 alias record，對外暴露的是自己的 domain name 而非 ALB 的隨機 hostname&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — ALB 跑在 public subnet，後端跑在 private subnet&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — ALB 的 security group 是系統對外唯一合理開放 0.0.0.0/0 的位置（僅限 80/443）&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS&lt;/a> — ALB 透過 target group 把流量導向 ECS task&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>ALB（Application Load Balancer）的核心職責是接收外部流量、根據規則（path、host header）把請求路由到後端的 target group，並用健康檢查持續驗證後端是否能服務。它是系統對外的第一個接觸點，跑在 public subnet 裡。</p>
<h2 id="概念位置">概念位置</h2>
<p>ALB 在核心服務層裡的角色是「入口設施」。它掛在 public subnet 的 security group 上（入站允許 80/443），把流量導向 private subnet 裡的 ECS task 或 EC2 instance。ALB 本身是 stateless 的 — 重建一個 ALB 不會遺失資料，但會換掉它的 DNS 名稱，所以對外服務通常在 ALB 前面掛一個穩定的 Route 53 alias record。</p>
<p>TLS 終結是 ALB 的標準職責：HTTPS listener 引用 ACM（AWS Certificate Manager）簽發的憑證，ALB 處理加解密，後端收到的是 HTTP 明文。憑證由 ACM 自動續期，IaC 用 DNS 驗證方式描述憑證 — 讓「憑證存在、續期、掛載」整條鏈都進版本控制。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下狀況指向 ALB 相關問題：</p>
<ul>
<li>使用者看到 502 — ALB 轉發請求但後端回應異常（健康檢查可能通過但實際請求處理失敗），查 target group 的健康狀態和後端 log</li>
<li>使用者看到 503 — target group 裡沒有健康的後端，通常是部署期間所有舊 task 停了但新 task 還沒通過健康檢查</li>
<li>HTTPS 憑證過期警告 — 如果用 ACM 搭配 DNS 驗證，憑證自動續期；看到過期警告代表 DNS 驗證記錄被刪了或 ACM 服務異常</li>
</ul>
<h2 id="設計責任">設計責任</h2>
<p>使用 ALB 時要決定：</p>
<ul>
<li><strong>健康檢查參數</strong>：檢查路徑（用應用層的 health endpoint、不用根路徑）、間隔、閾值。閾值太寬鬆會把壞掉的後端留在輪替裡，太嚴格會在部署瞬間誤判</li>
<li><strong>HTTP → HTTPS redirect</strong>：port 80 的 listener 設定固定回應 301 redirect 到 443，確保所有流量走加密</li>
<li><strong>TLS 憑證</strong>：用 ACM 搭配 DNS 驗證，讓憑證的簽發和續期自動化</li>
<li><strong>穩定 DNS</strong>：ALB 前面掛 Route 53 alias record，對外暴露的是自己的 domain name 而非 ALB 的隨機 hostname</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — ALB 跑在 public subnet，後端跑在 private subnet</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — ALB 的 security group 是系統對外唯一合理開放 0.0.0.0/0 的位置（僅限 80/443）</li>
<li><a href="/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS</a> — ALB 透過 target group 把流量導向 ECS task</li>
</ul>
]]></content:encoded></item><item><title>CIDR（Classless Inter-Domain Routing）</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/cidr/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/cidr/</guid><description>&lt;p>CIDR（Classless Inter-Domain Routing）用前綴長度表示一段 IP 地址範圍。&lt;code>10.0.0.0/16&lt;/code> 表示前 16 bit 是網路位址、後 16 bit 是主機位址，提供約六萬五千個可用位址。前綴越短、範圍越大：&lt;code>/16&lt;/code> 比 &lt;code>/24&lt;/code>（約 256 個位址）大 256 倍。&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> 和 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">subnet&lt;/a> 的地址空間都用 CIDR 表示。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>CIDR 是 VPC 規劃的起點決策。建立 VPC 時指定的 CIDR 區塊決定了這個 VPC 能容納多少 subnet 和多少資源。這個決策在建立後難以修改——事後擴張意味著追加 secondary CIDR，而追加的網段在 routing 與服務相容性上有限制。&lt;/p>
&lt;p>在 infra 系列中，CIDR 規劃出現在&lt;a href="https://tarrragon.github.io/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基&lt;/a>的 VPC 段落。Terraform 的 &lt;code>cidrsubnet&lt;/code> 函式可以從 VPC 的 CIDR 自動切出 subnet 的子網段，避免手動計算。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>CIDR 規劃出問題的訊號有兩類。第一類是地址耗盡：subnet 切不出新的子網段、或 subnet 內的 IP 分配用完，新資源無法取得位址。第二類是網段衝突：需要透過 VPC peering、Transit Gateway 或 VPN 互連兩個 VPC 時，發現兩端的 CIDR 重疊，路由無法解析，peering 建立失敗。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>規劃 CIDR 時要決定：&lt;/p>
&lt;ul>
&lt;li>大小：單一環境用 &lt;code>/16&lt;/code> 通常足夠寬裕，切成 &lt;code>/20&lt;/code> 的 subnet 可分配 16 個子網段&lt;/li>
&lt;li>不重疊：多個環境（dev &lt;code>10.0.0.0/16&lt;/code>、staging &lt;code>10.1.0.0/16&lt;/code>、prod &lt;code>10.2.0.0/16&lt;/code>）用連續但不重疊的區段，為日後互連預留空間&lt;/li>
&lt;li>與地端的協調：如果未來可能接 VPN 回地端機房，CIDR 要避開地端已使用的私有網段&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> — 用 CIDR 區塊定義的邏輯隔離網段&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — 從 VPC CIDR 切出的子網段&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>CIDR（Classless Inter-Domain Routing）用前綴長度表示一段 IP 地址範圍。<code>10.0.0.0/16</code> 表示前 16 bit 是網路位址、後 16 bit 是主機位址，提供約六萬五千個可用位址。前綴越短、範圍越大：<code>/16</code> 比 <code>/24</code>（約 256 個位址）大 256 倍。<a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> 和 <a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">subnet</a> 的地址空間都用 CIDR 表示。</p>
<h2 id="概念位置">概念位置</h2>
<p>CIDR 是 VPC 規劃的起點決策。建立 VPC 時指定的 CIDR 區塊決定了這個 VPC 能容納多少 subnet 和多少資源。這個決策在建立後難以修改——事後擴張意味著追加 secondary CIDR，而追加的網段在 routing 與服務相容性上有限制。</p>
<p>在 infra 系列中，CIDR 規劃出現在<a href="/blog/infra/03-network-foundation/vpc-subnet-security-group/" data-link-title="網路地基 — VPC、subnet 分層與 security group 設計" data-link-desc="VPC CIDR 規劃、public / private subnet 切分、route table 與 NAT 的可用性成本取捨、security group 最小開放設計，以及 NACL 的定位">模組三：網路地基</a>的 VPC 段落。Terraform 的 <code>cidrsubnet</code> 函式可以從 VPC 的 CIDR 自動切出 subnet 的子網段，避免手動計算。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>CIDR 規劃出問題的訊號有兩類。第一類是地址耗盡：subnet 切不出新的子網段、或 subnet 內的 IP 分配用完，新資源無法取得位址。第二類是網段衝突：需要透過 VPC peering、Transit Gateway 或 VPN 互連兩個 VPC 時，發現兩端的 CIDR 重疊，路由無法解析，peering 建立失敗。</p>
<h2 id="設計責任">設計責任</h2>
<p>規劃 CIDR 時要決定：</p>
<ul>
<li>大小：單一環境用 <code>/16</code> 通常足夠寬裕，切成 <code>/20</code> 的 subnet 可分配 16 個子網段</li>
<li>不重疊：多個環境（dev <code>10.0.0.0/16</code>、staging <code>10.1.0.0/16</code>、prod <code>10.2.0.0/16</code>）用連續但不重疊的區段，為日後互連預留空間</li>
<li>與地端的協調：如果未來可能接 VPN 回地端機房，CIDR 要避開地端已使用的私有網段</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> — 用 CIDR 區塊定義的邏輯隔離網段</li>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — 從 VPC CIDR 切出的子網段</li>
</ul>
]]></content:encoded></item><item><title>IAM（Identity and Access Management）</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/iam/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/iam/</guid><description>&lt;p>IAM（Identity and Access Management）是雲端平台用來回答「某個身分能不能對某個資源做某件事」的授權系統。它把授權拆成三個獨立的元件：identity（身分，發起動作的主體）、policy（政策，描述「允許或拒絕對哪些資源做哪些動作」的規則）、role（角色，一組可以被臨時取得的權限集合）。這三者的分工是後面所有憑證決策的前提。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>IAM 是&lt;a href="https://tarrragon.github.io/blog/infra/02-identity-credentials/iam-oidc-privilege-boundary/" data-link-title="身分與憑證地基 — IAM 模型、OIDC 短期憑證與權限邊界設計" data-link-desc="IAM 的 identity / policy / role 三元件、最小權限的持續收斂、用 OIDC 取代長期 access key，以及 SCP 與 Permissions Boundary 的環境隔離">模組二：身分與憑證地基&lt;/a>的核心機制。它決定了誰能動什麼——人、服務、CI pipeline 各拿剛好夠用的權限（最小權限），憑證有明確的生命週期。身分層失守的代價在五個 infra 責任面向中最高，因為它是其他所有資源的閘門。&lt;/p>
&lt;p>在 infra 系列中，IAM 的設計從三個維度展開：最小權限的持續收斂（不是一次設定就結束）、用 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC&lt;/a> 短期憑證取代長期 access key、以及跨帳號的權限邊界（SCP + Permissions Boundary）。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>IAM 需要關注的訊號：某個 role 的 policy 有 &lt;code>*:*&lt;/code> 或 &lt;code>AdministratorAccess&lt;/code>（權限過大）；credential report 顯示有長期 access key 超過 90 天未輪替（憑證散落風險）；Access Analyzer 顯示某個 role 的實際使用 action 遠少於授予的 action（權限擴散）；dev 環境的 CI role 能列出 production 的資源（環境隔離失效）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>IAM 設計時要決定：&lt;/p>
&lt;ul>
&lt;li>身分類型區分：人用 SSO 登入（強制 MFA）、雲上服務用 instance profile / task role、雲外 CI 用 OIDC 聯合&lt;/li>
&lt;li>權限分級：admin / operator / viewer 三級，見&lt;a href="https://tarrragon.github.io/blog/infra/02-identity-credentials/team-access-management/" data-link-title="團隊權限分級與存取管理" data-link-desc="用 admin / operator / viewer 三級劃分團隊成員的雲端操作權限，設計臨時提權流程、定期 access review 節奏，以及 contractor 與外部 vendor 的存取邊界">團隊權限分級&lt;/a>&lt;/li>
&lt;li>環境隔離：每個環境的 role 不能存取其他環境的資源&lt;/li>
&lt;li>收斂節奏：定期用 Access Analyzer 觀察實際使用的 action，收掉沒用到的權限&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC&lt;/a> — 用短期 token 取代長期 access key 的聯合機制&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — 網路層的存取控制（IAM 是 API 層的存取控制）&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/cloudtrail/" data-link-title="CloudTrail" data-link-desc="AWS 的 API 層稽核日誌服務，記錄誰在什麼時候對什麼資源做了什麼操作">CloudTrail&lt;/a> — 記錄 IAM 身分的 API 呼叫歷史&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>IAM（Identity and Access Management）是雲端平台用來回答「某個身分能不能對某個資源做某件事」的授權系統。它把授權拆成三個獨立的元件：identity（身分，發起動作的主體）、policy（政策，描述「允許或拒絕對哪些資源做哪些動作」的規則）、role（角色，一組可以被臨時取得的權限集合）。這三者的分工是後面所有憑證決策的前提。</p>
<h2 id="概念位置">概念位置</h2>
<p>IAM 是<a href="/blog/infra/02-identity-credentials/iam-oidc-privilege-boundary/" data-link-title="身分與憑證地基 — IAM 模型、OIDC 短期憑證與權限邊界設計" data-link-desc="IAM 的 identity / policy / role 三元件、最小權限的持續收斂、用 OIDC 取代長期 access key，以及 SCP 與 Permissions Boundary 的環境隔離">模組二：身分與憑證地基</a>的核心機制。它決定了誰能動什麼——人、服務、CI pipeline 各拿剛好夠用的權限（最小權限），憑證有明確的生命週期。身分層失守的代價在五個 infra 責任面向中最高，因為它是其他所有資源的閘門。</p>
<p>在 infra 系列中，IAM 的設計從三個維度展開：最小權限的持續收斂（不是一次設定就結束）、用 <a href="/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC</a> 短期憑證取代長期 access key、以及跨帳號的權限邊界（SCP + Permissions Boundary）。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>IAM 需要關注的訊號：某個 role 的 policy 有 <code>*:*</code> 或 <code>AdministratorAccess</code>（權限過大）；credential report 顯示有長期 access key 超過 90 天未輪替（憑證散落風險）；Access Analyzer 顯示某個 role 的實際使用 action 遠少於授予的 action（權限擴散）；dev 環境的 CI role 能列出 production 的資源（環境隔離失效）。</p>
<h2 id="設計責任">設計責任</h2>
<p>IAM 設計時要決定：</p>
<ul>
<li>身分類型區分：人用 SSO 登入（強制 MFA）、雲上服務用 instance profile / task role、雲外 CI 用 OIDC 聯合</li>
<li>權限分級：admin / operator / viewer 三級，見<a href="/blog/infra/02-identity-credentials/team-access-management/" data-link-title="團隊權限分級與存取管理" data-link-desc="用 admin / operator / viewer 三級劃分團隊成員的雲端操作權限，設計臨時提權流程、定期 access review 節奏，以及 contractor 與外部 vendor 的存取邊界">團隊權限分級</a></li>
<li>環境隔離：每個環境的 role 不能存取其他環境的資源</li>
<li>收斂節奏：定期用 Access Analyzer 觀察實際使用的 action，收掉沒用到的權限</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC</a> — 用短期 token 取代長期 access key 的聯合機制</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — 網路層的存取控制（IAM 是 API 層的存取控制）</li>
<li><a href="/blog/infra/knowledge-cards/cloudtrail/" data-link-title="CloudTrail" data-link-desc="AWS 的 API 層稽核日誌服務，記錄誰在什麼時候對什麼資源做了什麼操作">CloudTrail</a> — 記錄 IAM 身分的 API 呼叫歷史</li>
</ul>
]]></content:encoded></item><item><title>Route Table</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/route-table/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/route-table/</guid><description>&lt;p>Route table 是一組轉送規則，掛在 subnet 上，定義「目的地是某個網段的封包該往哪送」。每個 subnet 關聯一張 route table，封包離開 subnet 時逐條比對規則、走最長前綴匹配的那一條。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Route table 決定了一個 subnet 是 public 還是 private。技術上的差別只有一行：route table 裡有沒有一條 &lt;code>0.0.0.0/0 → Internet Gateway&lt;/code> 的預設路由。有這條路由的 subnet 是 public（封包可以直接出網、外部也可以連入）；把預設路由指向 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT Gateway&lt;/a> 的 subnet 是 private（只能主動出站、外部無法入站）。subnet 本身的屬性不含 public/private 標記，性質完全由關聯的 route table 賦予。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>private subnet 的服務突然拉不到外部套件或第三方 API 全部逾時時，排查路徑的第一步是檢查該 subnet 關聯的 route table：預設路由是否指向健康的 NAT Gateway。如果只有某一個可用區的節點受影響，通常是那一區的 NAT Gateway 或其所在 subnet 出狀況。&lt;/p>
&lt;p>另一個常見訊號是新建的 subnet 沒有手動關聯 route table，被 VPC 的 main route table 自動關聯——main route table 的預設設定可能跟預期不符。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 route table 時要決定：每個 subnet 的預設路由指向什麼（Internet Gateway / NAT Gateway / Transit Gateway / 無）、VPC 內部流量是否需要自訂路由（peering、endpoint）、以及 main route table 是否該保持空白以避免新 subnet 意外取得對外路由。每一條路由的目的地網段和目標要在 IaC 裡明確描述，讓 route table 的語意可被 review。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a> — route table 掛在 subnet 上&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT&lt;/a> — private subnet 的預設路由目標&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC&lt;/a> — route table 存在於 VPC 內&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Route table 是一組轉送規則，掛在 subnet 上，定義「目的地是某個網段的封包該往哪送」。每個 subnet 關聯一張 route table，封包離開 subnet 時逐條比對規則、走最長前綴匹配的那一條。</p>
<h2 id="概念位置">概念位置</h2>
<p>Route table 決定了一個 subnet 是 public 還是 private。技術上的差別只有一行：route table 裡有沒有一條 <code>0.0.0.0/0 → Internet Gateway</code> 的預設路由。有這條路由的 subnet 是 public（封包可以直接出網、外部也可以連入）；把預設路由指向 <a href="/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT Gateway</a> 的 subnet 是 private（只能主動出站、外部無法入站）。subnet 本身的屬性不含 public/private 標記，性質完全由關聯的 route table 賦予。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>private subnet 的服務突然拉不到外部套件或第三方 API 全部逾時時，排查路徑的第一步是檢查該 subnet 關聯的 route table：預設路由是否指向健康的 NAT Gateway。如果只有某一個可用區的節點受影響，通常是那一區的 NAT Gateway 或其所在 subnet 出狀況。</p>
<p>另一個常見訊號是新建的 subnet 沒有手動關聯 route table，被 VPC 的 main route table 自動關聯——main route table 的預設設定可能跟預期不符。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 route table 時要決定：每個 subnet 的預設路由指向什麼（Internet Gateway / NAT Gateway / Transit Gateway / 無）、VPC 內部流量是否需要自訂路由（peering、endpoint）、以及 main route table 是否該保持空白以避免新 subnet 意外取得對外路由。每一條路由的目的地網段和目標要在 IaC 裡明確描述，讓 route table 的語意可被 review。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a> — route table 掛在 subnet 上</li>
<li><a href="/blog/infra/knowledge-cards/nat/" data-link-title="NAT Gateway" data-link-desc="讓 private subnet 的資源主動對外連線、同時不被外部入站觸及的網路地址轉換服務">NAT</a> — private subnet 的預設路由目標</li>
<li><a href="/blog/infra/knowledge-cards/vpc/" data-link-title="VPC（Virtual Private Cloud）" data-link-desc="雲端帳號內的一塊邏輯隔離私有網段，是所有網路切分的起點與容器">VPC</a> — route table 存在於 VPC 內</li>
</ul>
]]></content:encoded></item><item><title>SCP (Service Control Policy)</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/scp/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/scp/</guid><description>&lt;p>Service Control Policy（SCP）是 AWS Organizations 裡套用在 OU 或帳號上的權限上限。SCP 不授予權限——它設定一個天花板，限制該範圍內的 IAM 能做什麼。即使帳號內有 &lt;code>AdministratorAccess&lt;/code> 的 IAM role，SCP deny 的操作仍然被擋下。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>SCP 跟 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> policy 的關係是交集而非覆蓋：一個操作要同時被 SCP 允許且被 IAM policy 允許才會生效。SCP 的設計目的是讓組織管理者設定「即使帳號管理員也做不了」的護欄，常見的 day-1 SCP 包括：禁止關閉 CloudTrail、禁止離開指定 region、禁止刪除 VPC Flow Logs。&lt;/p>
&lt;p>SCP 套用在 OU 上時會繼承給 OU 下所有帳號和子 OU。Management account（Organizations 的根帳號）不受 SCP 約束——這是設計上的逃生門，也是 management account 應該盡量不跑 workload 的原因。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>當帳號內的 IAM role 執行某個操作時收到 &lt;code>AccessDeniedException&lt;/code>、但該 role 的 IAM policy 確實允許該操作，SCP 是第一個要檢查的位置。另一個訊號是新帳號加入 OU 後某些原本能用的服務突然不可用——通常是繼承了 OU 的 SCP deny list。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>SCP 的設計要決定：用 deny-list 策略（預設全開、明確列出禁止項）還是 allow-list 策略（預設全關、明確列出允許項）。Deny-list 較常見也較易維護——只需要管「哪些該禁」。Allow-list 更嚴格但維護成本高——每次有新服務需求都要更新 SCP。&lt;/p>
&lt;p>套用 SCP 前要確認不會擋到正在運作的服務——先在 sandbox OU 測試，確認既有 workload 不受影響再推到 workload OU。SCP 的變更跟 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> 一樣要走 PR review。跨帳號策略的完整設計見&lt;a href="https://tarrragon.github.io/blog/infra/02-identity-credentials/multi-account-strategy/" data-link-title="跨帳號策略 — Organizations、SCP 與帳號工廠" data-link-desc="用 AWS Organizations 把環境拆成獨立帳號、用 SCP 設定連管理員都越不過的護欄、用帳號工廠讓每個新帳號自帶安全基線">跨帳號策略文章&lt;/a>。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> — SCP 是 IAM policy 的上層天花板&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/environment-separation/" data-link-title="環境分離" data-link-desc="把同一套基礎設施定義複製成多份隔離的執行實例，各有獨立 state 與故障半徑">環境分離&lt;/a> — SCP 靠 OU 結構實現環境之間的權限隔離&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Service Control Policy（SCP）是 AWS Organizations 裡套用在 OU 或帳號上的權限上限。SCP 不授予權限——它設定一個天花板，限制該範圍內的 IAM 能做什麼。即使帳號內有 <code>AdministratorAccess</code> 的 IAM role，SCP deny 的操作仍然被擋下。</p>
<h2 id="概念位置">概念位置</h2>
<p>SCP 跟 <a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> policy 的關係是交集而非覆蓋：一個操作要同時被 SCP 允許且被 IAM policy 允許才會生效。SCP 的設計目的是讓組織管理者設定「即使帳號管理員也做不了」的護欄，常見的 day-1 SCP 包括：禁止關閉 CloudTrail、禁止離開指定 region、禁止刪除 VPC Flow Logs。</p>
<p>SCP 套用在 OU 上時會繼承給 OU 下所有帳號和子 OU。Management account（Organizations 的根帳號）不受 SCP 約束——這是設計上的逃生門，也是 management account 應該盡量不跑 workload 的原因。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>當帳號內的 IAM role 執行某個操作時收到 <code>AccessDeniedException</code>、但該 role 的 IAM policy 確實允許該操作，SCP 是第一個要檢查的位置。另一個訊號是新帳號加入 OU 後某些原本能用的服務突然不可用——通常是繼承了 OU 的 SCP deny list。</p>
<h2 id="設計責任">設計責任</h2>
<p>SCP 的設計要決定：用 deny-list 策略（預設全開、明確列出禁止項）還是 allow-list 策略（預設全關、明確列出允許項）。Deny-list 較常見也較易維護——只需要管「哪些該禁」。Allow-list 更嚴格但維護成本高——每次有新服務需求都要更新 SCP。</p>
<p>套用 SCP 前要確認不會擋到正在運作的服務——先在 sandbox OU 測試，確認既有 workload 不受影響再推到 workload OU。SCP 的變更跟 <a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> 一樣要走 PR review。跨帳號策略的完整設計見<a href="/blog/infra/02-identity-credentials/multi-account-strategy/" data-link-title="跨帳號策略 — Organizations、SCP 與帳號工廠" data-link-desc="用 AWS Organizations 把環境拆成獨立帳號、用 SCP 設定連管理員都越不過的護欄、用帳號工廠讓每個新帳號自帶安全基線">跨帳號策略文章</a>。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> — SCP 是 IAM policy 的上層天花板</li>
<li><a href="/blog/infra/knowledge-cards/environment-separation/" data-link-title="環境分離" data-link-desc="把同一套基礎設施定義複製成多份隔離的執行實例，各有獨立 state 與故障半徑">環境分離</a> — SCP 靠 OU 結構實現環境之間的權限隔離</li>
</ul>
]]></content:encoded></item><item><title>Remote State Backend</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/remote-state-backend/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/remote-state-backend/</guid><description>&lt;p>Remote state backend 是 IaC 工具用來存放 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">state&lt;/a> 的共享儲存機制。它要同時滿足三件事：持久保存（不會因為某台筆電故障而遺失）、防止並行寫入衝突（兩個人不能同時 apply）、以及保護敏感內容（state 內含資源的真實屬性，可能包含密碼或 key）。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>State 是 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> 工具對現實的唯一記憶。把它放在本地檔案系統等於把整個基礎設施的記憶綁在一台機器上——換人接手、換台電腦、或兩人同時 apply，記憶就分裂了。Remote state backend 解決的是「讓 state 變成團隊共用的、有保護的事實來源」。&lt;/p>
&lt;p>典型的自管組合是 S3（存放 state 檔、開 versioning 和加密）加上 DynamoDB（提供 apply 時的並行鎖）。託管服務（Terraform Cloud、Spacelift）把存放、鎖和加密包在一起，用月費換掉配置和維運負擔。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>本地 state 的失敗訊號是：跑 &lt;code>terraform plan&lt;/code> 時出現「想刪掉」明知存在的資源——通常代表本地 state 跟雲端實際狀態已經脫節。另一個訊號是兩個人同時跑 apply 但沒有任何鎖機制阻擋——結果是互相覆蓋對方的變更，state 進入不一致狀態。&lt;/p>
&lt;p>Remote backend 設定後，如果 &lt;code>terraform init&lt;/code> 提示 state 遷移確認，代表正在從本地搬到遠端——這是正確的一次性操作，但搬遷過程中不能有其他人在 apply。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>選擇 remote state backend 時要決定：自管還是託管（取決於團隊規模和維運餘裕）、state bucket 的加密與存取控制（誰能讀 state 等於誰能看到所有資源的敏感屬性）、versioning 是否開啟（是 state 回捲的唯一退路）、以及鎖表的設定（DynamoDB 的表名和 partition key）。&lt;/p>
&lt;p>State 絕不能進 git——它含明文敏感值，推進版控等於把密碼寫進每個 clone 的歷史裡。Backend 設定本身（bucket name、region、鎖表名稱）寫在 HCL 裡進 git，state 檔本身只存在 backend 裡。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a> — remote backend 存放的對象&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift&lt;/a> — state 與現實不一致時的現象&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> — remote state backend 是 IaC 工具的基礎設施&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Remote state backend 是 IaC 工具用來存放 <a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">state</a> 的共享儲存機制。它要同時滿足三件事：持久保存（不會因為某台筆電故障而遺失）、防止並行寫入衝突（兩個人不能同時 apply）、以及保護敏感內容（state 內含資源的真實屬性，可能包含密碼或 key）。</p>
<h2 id="概念位置">概念位置</h2>
<p>State 是 <a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> 工具對現實的唯一記憶。把它放在本地檔案系統等於把整個基礎設施的記憶綁在一台機器上——換人接手、換台電腦、或兩人同時 apply，記憶就分裂了。Remote state backend 解決的是「讓 state 變成團隊共用的、有保護的事實來源」。</p>
<p>典型的自管組合是 S3（存放 state 檔、開 versioning 和加密）加上 DynamoDB（提供 apply 時的並行鎖）。託管服務（Terraform Cloud、Spacelift）把存放、鎖和加密包在一起，用月費換掉配置和維運負擔。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>本地 state 的失敗訊號是：跑 <code>terraform plan</code> 時出現「想刪掉」明知存在的資源——通常代表本地 state 跟雲端實際狀態已經脫節。另一個訊號是兩個人同時跑 apply 但沒有任何鎖機制阻擋——結果是互相覆蓋對方的變更，state 進入不一致狀態。</p>
<p>Remote backend 設定後，如果 <code>terraform init</code> 提示 state 遷移確認，代表正在從本地搬到遠端——這是正確的一次性操作，但搬遷過程中不能有其他人在 apply。</p>
<h2 id="設計責任">設計責任</h2>
<p>選擇 remote state backend 時要決定：自管還是託管（取決於團隊規模和維運餘裕）、state bucket 的加密與存取控制（誰能讀 state 等於誰能看到所有資源的敏感屬性）、versioning 是否開啟（是 state 回捲的唯一退路）、以及鎖表的設定（DynamoDB 的表名和 partition key）。</p>
<p>State 絕不能進 git——它含明文敏感值，推進版控等於把密碼寫進每個 clone 的歷史裡。Backend 設定本身（bucket name、region、鎖表名稱）寫在 HCL 裡進 git，state 檔本身只存在 backend 裡。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a> — remote backend 存放的對象</li>
<li><a href="/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift</a> — state 與現實不一致時的現象</li>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> — remote state backend 是 IaC 工具的基礎設施</li>
</ul>
]]></content:encoded></item><item><title>Trust Policy</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/trust-policy/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/trust-policy/</guid><description>&lt;p>Trust policy 是附加在 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> role 上的一份 JSON 文件，定義「誰被允許臨時取得（assume）這個 role 的權限」。跟 IAM policy 的差別是：IAM policy 描述「這個 role 能做什麼」，trust policy 描述「誰能變成這個 role」。兩者合在一起才構成完整的授權——先過 trust policy 的門、再受 IAM policy 的限。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Trust policy 是 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC&lt;/a> 聯合的核心配件。當 CI/CD 平台（GitHub Actions、GitLab CI）要用短期憑證存取雲端資源時，trust policy 用 OIDC token 裡的 claim（issuer、audience、subject）決定「這個 token 代表的身分能不能 assume 這個 role」。&lt;/p>
&lt;p>Trust policy 的設計要點是 claim 的收斂程度。只驗 issuer 而不驗 repo 和 branch，等於同一個 CI 平台上所有專案都能 assume 這個 role——這是常見的設定陷阱。收到最緊意味著限定到「某個 org 的某個 repo 的某個 branch 或 environment」。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>&lt;code>sts:AssumeRoleWithWebIdentity&lt;/code> 呼叫失敗、回傳 &lt;code>AccessDenied&lt;/code> 時，問題通常在 trust policy 的 condition 比對不上。排查路徑是把 CI 平台簽發的 OIDC token decode（JWT 的 payload 部分），逐一比對 token 裡的 &lt;code>iss&lt;/code>、&lt;code>aud&lt;/code>、&lt;code>sub&lt;/code> 跟 trust policy 的 condition 值。&lt;/p>
&lt;p>另一個訊號是 trust policy 的 condition 用了 &lt;code>StringLike&lt;/code> 但 pattern 太寬（如 &lt;code>repo:my-org/*&lt;/code>），讓非預期的 repo 也能 assume——這類過寬的 trust policy 在安全稽核時會被標記。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>設計 trust policy 時要決定：允許哪些外部身分 assume（issuer + subject 的精確匹配）、audience 是否需要額外驗證（AWS 預設 &lt;code>sts.amazonaws.com&lt;/code>）、以及是否把 plan role 和 apply role 分開（plan 只需 read-only、apply 需要 write，用兩個 role 各自設不同 trust condition 來區分 branch 或 environment）。&lt;/p>
&lt;p>Trust policy 的變更跟 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> policy 一樣要走 PR review——因為改寬一個 condition 就等於給更多外部身分開門。設定指南見 &lt;a href="https://tarrragon.github.io/blog/infra/02-identity-credentials/oidc-trust-policy-setup/" data-link-title="OIDC Trust Policy 設定指南" data-link-desc="GitHub Actions 與 AWS 之間的 OIDC 聯合設定：建立 provider、設計 trust policy 的 claim 收斂、plan 與 apply role 分離、常見錯誤排查">OIDC Trust Policy 設定指南&lt;/a>。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> — trust policy 是 IAM role 的一部分&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC&lt;/a> — trust policy 用 OIDC token 的 claim 做 assume 判斷&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Trust policy 是附加在 <a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> role 上的一份 JSON 文件，定義「誰被允許臨時取得（assume）這個 role 的權限」。跟 IAM policy 的差別是：IAM policy 描述「這個 role 能做什麼」，trust policy 描述「誰能變成這個 role」。兩者合在一起才構成完整的授權——先過 trust policy 的門、再受 IAM policy 的限。</p>
<h2 id="概念位置">概念位置</h2>
<p>Trust policy 是 <a href="/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC</a> 聯合的核心配件。當 CI/CD 平台（GitHub Actions、GitLab CI）要用短期憑證存取雲端資源時，trust policy 用 OIDC token 裡的 claim（issuer、audience、subject）決定「這個 token 代表的身分能不能 assume 這個 role」。</p>
<p>Trust policy 的設計要點是 claim 的收斂程度。只驗 issuer 而不驗 repo 和 branch，等於同一個 CI 平台上所有專案都能 assume 這個 role——這是常見的設定陷阱。收到最緊意味著限定到「某個 org 的某個 repo 的某個 branch 或 environment」。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p><code>sts:AssumeRoleWithWebIdentity</code> 呼叫失敗、回傳 <code>AccessDenied</code> 時，問題通常在 trust policy 的 condition 比對不上。排查路徑是把 CI 平台簽發的 OIDC token decode（JWT 的 payload 部分），逐一比對 token 裡的 <code>iss</code>、<code>aud</code>、<code>sub</code> 跟 trust policy 的 condition 值。</p>
<p>另一個訊號是 trust policy 的 condition 用了 <code>StringLike</code> 但 pattern 太寬（如 <code>repo:my-org/*</code>），讓非預期的 repo 也能 assume——這類過寬的 trust policy 在安全稽核時會被標記。</p>
<h2 id="設計責任">設計責任</h2>
<p>設計 trust policy 時要決定：允許哪些外部身分 assume（issuer + subject 的精確匹配）、audience 是否需要額外驗證（AWS 預設 <code>sts.amazonaws.com</code>）、以及是否把 plan role 和 apply role 分開（plan 只需 read-only、apply 需要 write，用兩個 role 各自設不同 trust condition 來區分 branch 或 environment）。</p>
<p>Trust policy 的變更跟 <a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> policy 一樣要走 PR review——因為改寬一個 condition 就等於給更多外部身分開門。設定指南見 <a href="/blog/infra/02-identity-credentials/oidc-trust-policy-setup/" data-link-title="OIDC Trust Policy 設定指南" data-link-desc="GitHub Actions 與 AWS 之間的 OIDC 聯合設定：建立 provider、設計 trust policy 的 claim 收斂、plan 與 apply role 分離、常見錯誤排查">OIDC Trust Policy 設定指南</a>。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> — trust policy 是 IAM role 的一部分</li>
<li><a href="/blog/infra/knowledge-cards/oidc/" data-link-title="OIDC 聯合" data-link-desc="讓 CI/CD 平台用短期 token 取代長期 access key 存取雲端資源的身分聯合機制">OIDC</a> — trust policy 用 OIDC token 的 claim 做 assume 判斷</li>
</ul>
]]></content:encoded></item><item><title>Deletion Protection</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/deletion-protection/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/deletion-protection/</guid><description>&lt;p>Deletion protection 是雲端平台在資源層級提供的防護機制：開啟後，任何刪除該資源的操作（Console 點按、CLI 指令、IaC 的 destroy）都會被擋下，必須先顯式關閉保護才能執行刪除。這個額外步驟的目的是防止手滑、批次操作誤傷、以及 Terraform plan 裡意外出現的 destroy。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Deletion protection 是 &lt;a href="https://tarrragon.github.io/blog/infra/05-core-services/stateful-protection-dependency/" data-link-title="Stateful 資源保護與跨服務依賴表達" data-link-desc="stateful 資源的保護策略（multi-AZ、備份、刪除保護）、stateful 與 stateless 的操作差異，以及用 output 與 data source 表達服務間依賴">stateful 資源保護&lt;/a>的第一道防線。運算節點可以隨時重建，資料一旦遺失通常無法重來——這條分界線決定了哪些資源該開保護。對 stateful 資源（資料庫、持久化儲存）來說，這是 day-1 該開的設定，不是「等穩定再開」的選項。&lt;/p>
&lt;p>不同 AWS 服務的保護機制名稱不同但行為一致：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>服務&lt;/th>
 &lt;th>屬性名稱&lt;/th>
 &lt;th>保護對象&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>RDS&lt;/td>
 &lt;td>&lt;code>deletion_protection&lt;/code>&lt;/td>
 &lt;td>資料庫 instance&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>EC2&lt;/td>
 &lt;td>&lt;code>disable_api_termination&lt;/code>&lt;/td>
 &lt;td>運算 instance&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>S3&lt;/td>
 &lt;td>MFA delete&lt;/td>
 &lt;td>bucket 版本控制&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>DynamoDB&lt;/td>
 &lt;td>&lt;code>deletion_protection_enabled&lt;/code>&lt;/td>
 &lt;td>表格&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要開啟 deletion protection 的訊號是資源承載了不可重建的狀態。判斷方式是問一個問題：「這個資源被刪除後，能不能在 10 分鐘內從程式碼或備份完整恢復？」不能的就該開。&lt;/p>
&lt;p>&lt;code>terraform plan&lt;/code> 輸出裡出現 &lt;code>destroy&lt;/code> 或 &lt;code>forces replacement&lt;/code>（&lt;code>-/+&lt;/code>）時，deletion protection 是阻擋意外資料遺失的最後一道閘門。有保護的資源在 apply 時會報錯而非直接刪除，讓操作者有機會停下來確認。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>用 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> 描述 stateful 資源時，把 deletion protection 寫進程式碼而非手動在 Console 開啟——這讓保護策略本身成為可審查、可追蹤的設定。同時搭配 &lt;code>skip_final_snapshot = false&lt;/code>（RDS）確保刪除前自動做最後一份快照。&lt;/p>
&lt;p>Deletion protection 擋的是刪除操作，不擋資料覆寫或邏輯損壞——一段錯誤的 UPDATE 不會被 deletion protection 攔截。資料層的完整防線還需要備份保留與時間點還原（PITR），跟 deletion protection 正交。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a> — deletion protection 在 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">state&lt;/a> 裡記錄為資源屬性，plan 會顯示保護狀態&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> — 保護策略寫進 IaC 讓它可審查&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Deletion protection 是雲端平台在資源層級提供的防護機制：開啟後，任何刪除該資源的操作（Console 點按、CLI 指令、IaC 的 destroy）都會被擋下，必須先顯式關閉保護才能執行刪除。這個額外步驟的目的是防止手滑、批次操作誤傷、以及 Terraform plan 裡意外出現的 destroy。</p>
<h2 id="概念位置">概念位置</h2>
<p>Deletion protection 是 <a href="/blog/infra/05-core-services/stateful-protection-dependency/" data-link-title="Stateful 資源保護與跨服務依賴表達" data-link-desc="stateful 資源的保護策略（multi-AZ、備份、刪除保護）、stateful 與 stateless 的操作差異，以及用 output 與 data source 表達服務間依賴">stateful 資源保護</a>的第一道防線。運算節點可以隨時重建，資料一旦遺失通常無法重來——這條分界線決定了哪些資源該開保護。對 stateful 資源（資料庫、持久化儲存）來說，這是 day-1 該開的設定，不是「等穩定再開」的選項。</p>
<p>不同 AWS 服務的保護機制名稱不同但行為一致：</p>
<table>
  <thead>
      <tr>
          <th>服務</th>
          <th>屬性名稱</th>
          <th>保護對象</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>RDS</td>
          <td><code>deletion_protection</code></td>
          <td>資料庫 instance</td>
      </tr>
      <tr>
          <td>EC2</td>
          <td><code>disable_api_termination</code></td>
          <td>運算 instance</td>
      </tr>
      <tr>
          <td>S3</td>
          <td>MFA delete</td>
          <td>bucket 版本控制</td>
      </tr>
      <tr>
          <td>DynamoDB</td>
          <td><code>deletion_protection_enabled</code></td>
          <td>表格</td>
      </tr>
  </tbody>
</table>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要開啟 deletion protection 的訊號是資源承載了不可重建的狀態。判斷方式是問一個問題：「這個資源被刪除後，能不能在 10 分鐘內從程式碼或備份完整恢復？」不能的就該開。</p>
<p><code>terraform plan</code> 輸出裡出現 <code>destroy</code> 或 <code>forces replacement</code>（<code>-/+</code>）時，deletion protection 是阻擋意外資料遺失的最後一道閘門。有保護的資源在 apply 時會報錯而非直接刪除，讓操作者有機會停下來確認。</p>
<h2 id="設計責任">設計責任</h2>
<p>用 <a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> 描述 stateful 資源時，把 deletion protection 寫進程式碼而非手動在 Console 開啟——這讓保護策略本身成為可審查、可追蹤的設定。同時搭配 <code>skip_final_snapshot = false</code>（RDS）確保刪除前自動做最後一份快照。</p>
<p>Deletion protection 擋的是刪除操作，不擋資料覆寫或邏輯損壞——一段錯誤的 UPDATE 不會被 deletion protection 攔截。資料層的完整防線還需要備份保留與時間點還原（PITR），跟 deletion protection 正交。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a> — deletion protection 在 <a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">state</a> 裡記錄為資源屬性，plan 會顯示保護狀態</li>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> — 保護策略寫進 IaC 讓它可審查</li>
</ul>
]]></content:encoded></item><item><title>checkov</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/checkov/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/checkov/</guid><description>&lt;p>checkov 是一個開源的靜態分析工具，掃描 Terraform / CloudFormation / Kubernetes 等 IaC 程式碼，比對內建的規則庫找出安全漏洞與合規違規。它在 &lt;code>plan&lt;/code> 之前或之後執行、不建立任何雲端資源，所以是 CI pipeline 裡最便宜的安全檢查之一。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>checkov 在 &lt;a href="https://tarrragon.github.io/blog/infra/07-infra-as-pr/plan-review-apply-guardrails/" data-link-title="infra 走 PR 流程與自動化護欄" data-link-desc="infra 變更走 PR → plan → review diff → 合併 → apply，配 fmt / validate / tflint / checkov / tfsec 與 Atlantis 自動化，讓基礎設施可審查、可回溯、可交接">infra PR 流程&lt;/a>裡的位置是 &lt;code>fmt&lt;/code> → &lt;code>validate&lt;/code> → &lt;strong>checkov / tfsec&lt;/strong> → &lt;code>plan&lt;/code>。前兩步檢查語法正確，checkov 檢查語意安全，plan 檢查實際差異。checkov 補的是 reviewer 肉眼容易漏的盲區——一條 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">security group&lt;/a> 規則寫成 &lt;code>0.0.0.0/0&lt;/code> 在 HCL 裡只是一行字串，人會看漏，規則不會。&lt;/p>
&lt;p>三個常見的 IaC 掃描工具各有側重：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>工具&lt;/th>
 &lt;th>側重&lt;/th>
 &lt;th>維護方&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>checkov&lt;/td>
 &lt;td>安全 + 合規&lt;/td>
 &lt;td>Prisma Cloud (Palo Alto)&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>tfsec&lt;/td>
 &lt;td>安全&lt;/td>
 &lt;td>Aqua Security&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>tflint&lt;/td>
 &lt;td>provider 正確性&lt;/td>
 &lt;td>社群&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>checkov 的規則庫最廣（涵蓋 CIS Benchmark、SOC 2、PCI DSS 等合規框架），tfsec 的規則更聚焦安全面，tflint 偏向「這個 instance type 在這個 region 存不存在」的 provider 正確性。三者可疊加使用。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要引入 checkov 的訊號是 PR review 開始漏掉安全問題——S3 bucket 缺 public access block、RDS 沒開加密、IAM policy 過寬。這些問題的 pattern 是固定的、可以用規則比對，不應該靠人記憶來擋。&lt;/p>
&lt;p>checkov 命中後要區分「真漏洞」和「情境合理的例外」。ALB 的 HTTPS listener 在 port 443 開 &lt;code>0.0.0.0/0&lt;/code> 是設計本意，不是漏洞。豁免用行內註解標記並寫理由：&lt;code>#checkov:skip=CKV_AWS_260:ALB public HTTPS listener&lt;/code>。詳細的規則配置與豁免管理見 &lt;a href="https://tarrragon.github.io/blog/infra/07-infra-as-pr/checkov-tfsec-rule-customization/" data-link-title="checkov 與 tfsec 規則配置" data-link-desc="靜態掃描工具的規則選擇策略、自訂規則、豁免管理、false positive 處理與 CI 整合，讓掃描從噪音來源變成可信的品質關卡">checkov 與 tfsec 規則配置&lt;/a>。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>引入 checkov 時要決定兩件事：啟用哪些規則（全部 vs 漸進啟用），以及命中時 CI 要不要擋（hard fail vs warning）。常見的漸進策略是先從高嚴重度規則開始、設為 hard fail，中低嚴重度設為 warning，隨團隊習慣逐步收緊。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a> — checkov 掃描的對象&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a> — checkov 最常攔截的 &lt;code>0.0.0.0/0&lt;/code> 全開規則&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>checkov 是一個開源的靜態分析工具，掃描 Terraform / CloudFormation / Kubernetes 等 IaC 程式碼，比對內建的規則庫找出安全漏洞與合規違規。它在 <code>plan</code> 之前或之後執行、不建立任何雲端資源，所以是 CI pipeline 裡最便宜的安全檢查之一。</p>
<h2 id="概念位置">概念位置</h2>
<p>checkov 在 <a href="/blog/infra/07-infra-as-pr/plan-review-apply-guardrails/" data-link-title="infra 走 PR 流程與自動化護欄" data-link-desc="infra 變更走 PR → plan → review diff → 合併 → apply，配 fmt / validate / tflint / checkov / tfsec 與 Atlantis 自動化，讓基礎設施可審查、可回溯、可交接">infra PR 流程</a>裡的位置是 <code>fmt</code> → <code>validate</code> → <strong>checkov / tfsec</strong> → <code>plan</code>。前兩步檢查語法正確，checkov 檢查語意安全，plan 檢查實際差異。checkov 補的是 reviewer 肉眼容易漏的盲區——一條 <a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">security group</a> 規則寫成 <code>0.0.0.0/0</code> 在 HCL 裡只是一行字串，人會看漏，規則不會。</p>
<p>三個常見的 IaC 掃描工具各有側重：</p>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>側重</th>
          <th>維護方</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>checkov</td>
          <td>安全 + 合規</td>
          <td>Prisma Cloud (Palo Alto)</td>
      </tr>
      <tr>
          <td>tfsec</td>
          <td>安全</td>
          <td>Aqua Security</td>
      </tr>
      <tr>
          <td>tflint</td>
          <td>provider 正確性</td>
          <td>社群</td>
      </tr>
  </tbody>
</table>
<p>checkov 的規則庫最廣（涵蓋 CIS Benchmark、SOC 2、PCI DSS 等合規框架），tfsec 的規則更聚焦安全面，tflint 偏向「這個 instance type 在這個 region 存不存在」的 provider 正確性。三者可疊加使用。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要引入 checkov 的訊號是 PR review 開始漏掉安全問題——S3 bucket 缺 public access block、RDS 沒開加密、IAM policy 過寬。這些問題的 pattern 是固定的、可以用規則比對，不應該靠人記憶來擋。</p>
<p>checkov 命中後要區分「真漏洞」和「情境合理的例外」。ALB 的 HTTPS listener 在 port 443 開 <code>0.0.0.0/0</code> 是設計本意，不是漏洞。豁免用行內註解標記並寫理由：<code>#checkov:skip=CKV_AWS_260:ALB public HTTPS listener</code>。詳細的規則配置與豁免管理見 <a href="/blog/infra/07-infra-as-pr/checkov-tfsec-rule-customization/" data-link-title="checkov 與 tfsec 規則配置" data-link-desc="靜態掃描工具的規則選擇策略、自訂規則、豁免管理、false positive 處理與 CI 整合，讓掃描從噪音來源變成可信的品質關卡">checkov 與 tfsec 規則配置</a>。</p>
<h2 id="設計責任">設計責任</h2>
<p>引入 checkov 時要決定兩件事：啟用哪些規則（全部 vs 漸進啟用），以及命中時 CI 要不要擋（hard fail vs warning）。常見的漸進策略是先從高嚴重度規則開始、設為 hard fail，中低嚴重度設為 warning，隨團隊習慣逐步收緊。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a> — checkov 掃描的對象</li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a> — checkov 最常攔截的 <code>0.0.0.0/0</code> 全開規則</li>
</ul>
]]></content:encoded></item><item><title>Fargate</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/fargate/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/fargate/</guid><description>&lt;p>Fargate 是 AWS &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS&lt;/a> 的一種 launch type，把容器的運算實例交給 AWS 代管。使用 Fargate 時不需要配 EC2 instance、不需要管 capacity provider 的 scaling、不需要更新 AMI——只描述 task 需要多少 vCPU 和記憶體，AWS 負責分配運算資源。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>ECS 有兩種 launch type，差別在運算層的管理責任：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Launch type&lt;/th>
 &lt;th>運算層管理&lt;/th>
 &lt;th>適用情境&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Fargate&lt;/td>
 &lt;td>AWS 代管&lt;/td>
 &lt;td>web API、微服務、批次任務&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>EC2&lt;/td>
 &lt;td>自管 instance&lt;/td>
 &lt;td>GPU workload、高密度排程、成本敏感&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Fargate 降低的是運維面（不用管 OS patch、不用管 instance 容量），代價是單位成本較高（同規格約比 EC2 高 20-40%）和啟動延遲（cold start 通常在 30-60 秒，EC2 上的 task 因為 instance 已在所以秒級啟動）。多數 web API 的初始選擇是 Fargate，流量穩定且成本壓力大時再切回 EC2 launch type。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>評估是否從 Fargate 切到 EC2 的訊號是月費曲線。Fargate 按 vCPU-hour 和 memory-hour 計費，task 數量少時費用低、管理簡單。當 task 數量穩定在 10-20 個以上且流量模式可預測時，EC2 launch type 搭配 reserved instance 或 Savings Plans 的成本優勢開始顯著——但要承擔 instance 管理的運維負擔。詳細的成本分析見 &lt;a href="https://tarrragon.github.io/blog/infra/05-core-services/ecs-fargate-cost-optimization/" data-link-title="ECS Fargate 成本分析與優化" data-link-desc="Fargate 的計價模型、與 EC2 launch type 的成本交叉點、Spot 與 Savings Plans 的折扣機制、task 規格的 rightsizing 方法，以及何時該切回 EC2">ECS Fargate 成本分析與優化&lt;/a>。&lt;/p>
&lt;p>Fargate Spot 是介於兩者之間的選項：費用約為 on-demand Fargate 的 30%，但 AWS 可以隨時中斷 task（提前 2 分鐘通知）。適合可容忍中斷的 workload（批次處理、非即時的資料轉換），不適合面對使用者的即時 API。常見的混合策略是用 on-demand Fargate 跑基線流量、Fargate Spot 跑彈性擴張的部分。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>選 Fargate 時要決定三件事：task 的 vCPU / memory 規格（Fargate 的可選組合是固定的，不是任意搭配）、是否混用 Spot、以及 health check 的 grace period（Fargate 的 cold start 比 EC2 長，health check 太早判定失敗會讓 task 反覆重啟）。&lt;/p>
&lt;p>task 規格的 rightsizing 靠 CloudWatch Container Insights 的 CPU / memory utilization 決定——p95 使用率低於 30% 代表規格過大、持續高於 80% 代表該升級。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS&lt;/a> — Fargate 是 ECS 的 launch type 之一&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a> — Fargate task 通常掛在 ALB 的 target group 後面&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Fargate 是 AWS <a href="/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS</a> 的一種 launch type，把容器的運算實例交給 AWS 代管。使用 Fargate 時不需要配 EC2 instance、不需要管 capacity provider 的 scaling、不需要更新 AMI——只描述 task 需要多少 vCPU 和記憶體，AWS 負責分配運算資源。</p>
<h2 id="概念位置">概念位置</h2>
<p>ECS 有兩種 launch type，差別在運算層的管理責任：</p>
<table>
  <thead>
      <tr>
          <th>Launch type</th>
          <th>運算層管理</th>
          <th>適用情境</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Fargate</td>
          <td>AWS 代管</td>
          <td>web API、微服務、批次任務</td>
      </tr>
      <tr>
          <td>EC2</td>
          <td>自管 instance</td>
          <td>GPU workload、高密度排程、成本敏感</td>
      </tr>
  </tbody>
</table>
<p>Fargate 降低的是運維面（不用管 OS patch、不用管 instance 容量），代價是單位成本較高（同規格約比 EC2 高 20-40%）和啟動延遲（cold start 通常在 30-60 秒，EC2 上的 task 因為 instance 已在所以秒級啟動）。多數 web API 的初始選擇是 Fargate，流量穩定且成本壓力大時再切回 EC2 launch type。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>評估是否從 Fargate 切到 EC2 的訊號是月費曲線。Fargate 按 vCPU-hour 和 memory-hour 計費，task 數量少時費用低、管理簡單。當 task 數量穩定在 10-20 個以上且流量模式可預測時，EC2 launch type 搭配 reserved instance 或 Savings Plans 的成本優勢開始顯著——但要承擔 instance 管理的運維負擔。詳細的成本分析見 <a href="/blog/infra/05-core-services/ecs-fargate-cost-optimization/" data-link-title="ECS Fargate 成本分析與優化" data-link-desc="Fargate 的計價模型、與 EC2 launch type 的成本交叉點、Spot 與 Savings Plans 的折扣機制、task 規格的 rightsizing 方法，以及何時該切回 EC2">ECS Fargate 成本分析與優化</a>。</p>
<p>Fargate Spot 是介於兩者之間的選項：費用約為 on-demand Fargate 的 30%，但 AWS 可以隨時中斷 task（提前 2 分鐘通知）。適合可容忍中斷的 workload（批次處理、非即時的資料轉換），不適合面對使用者的即時 API。常見的混合策略是用 on-demand Fargate 跑基線流量、Fargate Spot 跑彈性擴張的部分。</p>
<h2 id="設計責任">設計責任</h2>
<p>選 Fargate 時要決定三件事：task 的 vCPU / memory 規格（Fargate 的可選組合是固定的，不是任意搭配）、是否混用 Spot、以及 health check 的 grace period（Fargate 的 cold start 比 EC2 長，health check 太早判定失敗會讓 task 反覆重啟）。</p>
<p>task 規格的 rightsizing 靠 CloudWatch Container Insights 的 CPU / memory utilization 決定——p95 使用率低於 30% 代表規格過大、持續高於 80% 代表該升級。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS</a> — Fargate 是 ECS 的 launch type 之一</li>
<li><a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a> — Fargate task 通常掛在 ALB 的 target group 後面</li>
</ul>
]]></content:encoded></item><item><title>phpMyAdmin</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/</guid><description>&lt;p>phpMyAdmin 是一套透過瀏覽器操作 MySQL 和 MariaDB 的 Web 應用程式。它提供圖形介面執行 SQL 查詢、瀏覽資料表、匯出與匯入資料庫、修改 schema（新增欄位、改索引、刪表）、以及管理使用者權限。多數主機商在安裝 cPanel 或 Plesk 時會一併預裝，讓租用主機的使用者不需要 SSH 就能管理資料庫。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>在無 SSH 的主機環境裡，phpMyAdmin 通常是唯一可用的資料庫管理入口。它取代了 &lt;code>mysql&lt;/code> CLI client 和 &lt;code>mysqldump&lt;/code> 指令的角色——查詢用 SQL 編輯器、匯出用匯出頁面、匯入用上傳 SQL 檔。接手維運時，phpMyAdmin 是拍下資料庫現況（SQL dump）的主要工具。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下情境會遇到 phpMyAdmin：主機面板（cPanel / Plesk）裡有「phpMyAdmin」按鈕可以進入；接手的專案的資料庫操作文件提到「在 phpMyAdmin 裡執行」；或者專案的部署流程包含「登入 phpMyAdmin 匯入 SQL」。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 phpMyAdmin 時要處理三個限制。第一是匯出 timeout：大資料庫（50MB 以上）的匯出可能因為 PHP 的 &lt;code>max_execution_time&lt;/code> 限制而中斷，需要分表匯出或調整 phpMyAdmin 設定。第二是沒有 CLI 可腳本化：所有操作都要手動點擊，無法排程自動備份。第三是安全暴露：phpMyAdmin 掛在 web 上、可被外部存取，如果沒有設密碼保護或 IP 白名單，等於把資料庫管理介面開給全世界。&lt;/p>
&lt;p>如果主機允許遠端 MySQL 連線（port 3306 開放），可以改用桌面工具（DBeaver、TablePlus、HeidiSQL）直連資料庫，繞過 phpMyAdmin 的 timeout 限制。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/cpanel/" data-link-title="cPanel" data-link-desc="Web 主機管理面板，提供 PHP 版本切換、cron、email、SSL、備份等功能的圖形介面">cPanel&lt;/a>：phpMyAdmin 通常內嵌在 cPanel 裡&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>phpMyAdmin 是一套透過瀏覽器操作 MySQL 和 MariaDB 的 Web 應用程式。它提供圖形介面執行 SQL 查詢、瀏覽資料表、匯出與匯入資料庫、修改 schema（新增欄位、改索引、刪表）、以及管理使用者權限。多數主機商在安裝 cPanel 或 Plesk 時會一併預裝，讓租用主機的使用者不需要 SSH 就能管理資料庫。</p>
<h2 id="概念位置">概念位置</h2>
<p>在無 SSH 的主機環境裡，phpMyAdmin 通常是唯一可用的資料庫管理入口。它取代了 <code>mysql</code> CLI client 和 <code>mysqldump</code> 指令的角色——查詢用 SQL 編輯器、匯出用匯出頁面、匯入用上傳 SQL 檔。接手維運時，phpMyAdmin 是拍下資料庫現況（SQL dump）的主要工具。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下情境會遇到 phpMyAdmin：主機面板（cPanel / Plesk）裡有「phpMyAdmin」按鈕可以進入；接手的專案的資料庫操作文件提到「在 phpMyAdmin 裡執行」；或者專案的部署流程包含「登入 phpMyAdmin 匯入 SQL」。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 phpMyAdmin 時要處理三個限制。第一是匯出 timeout：大資料庫（50MB 以上）的匯出可能因為 PHP 的 <code>max_execution_time</code> 限制而中斷，需要分表匯出或調整 phpMyAdmin 設定。第二是沒有 CLI 可腳本化：所有操作都要手動點擊，無法排程自動備份。第三是安全暴露：phpMyAdmin 掛在 web 上、可被外部存取，如果沒有設密碼保護或 IP 白名單，等於把資料庫管理介面開給全世界。</p>
<p>如果主機允許遠端 MySQL 連線（port 3306 開放），可以改用桌面工具（DBeaver、TablePlus、HeidiSQL）直連資料庫，繞過 phpMyAdmin 的 timeout 限制。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/cpanel/" data-link-title="cPanel" data-link-desc="Web 主機管理面板，提供 PHP 版本切換、cron、email、SSL、備份等功能的圖形介面">cPanel</a>：phpMyAdmin 通常內嵌在 cPanel 裡</li>
</ul>
]]></content:encoded></item><item><title>FileZilla</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/filezilla/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/filezilla/</guid><description>&lt;p>FileZilla 是一套開源的 FTP / SFTP / FTPS client，支援 Windows、macOS 和 Linux。它的介面分成本地和遠端兩側的檔案瀏覽器，讓使用者透過拖放或右鍵選單在本機與伺服器之間傳輸檔案。在無 SSH 的主機環境裡，FileZilla 是上傳程式碼和下載備份的主要工具。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>FTP 是無 SSH 環境裡傳輸檔案的主要協定。FileZilla 把 FTP 操作從 CLI（如 &lt;code>ftp&lt;/code> 或 &lt;code>lftp&lt;/code> 指令）包裝成圖形介面，降低操作門檻。接手維運時，FileZilla 的角色是「把整個站台拉回本地」和「把改好的檔案推上 prod」。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下情境會用到 FileZilla：接手的專案只有 FTP 帳密沒有 SSH key；部署方式是「FTP 上傳改過的檔案」；或者需要對比本地版本和伺服器版本的差異。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 FileZilla 時有三個關鍵功能和注意事項。&lt;/p>
&lt;p>&lt;strong>站台管理員&lt;/strong>：儲存多組 FTP 連線設定（主機、帳號、密碼、port），避免每次手動輸入。接手時第一步是在站台管理員建好 prod 的連線，並確認協定選擇正確（FTP 明文、FTPS 加密、SFTP 走 SSH）。&lt;/p>
&lt;p>&lt;strong>目錄比較&lt;/strong>：「檢視 → 目錄比較 → 啟用」功能會標示本地與遠端的檔案差異——哪些本地較新、哪些遠端較新、哪些只存在於一邊。上傳前先跑目錄比較可以看到即將改動的範圍。&lt;/p>
&lt;p>&lt;strong>隱藏檔&lt;/strong>：預設不顯示以 &lt;code>.&lt;/code> 開頭的檔案（如 &lt;code>.htaccess&lt;/code>、&lt;code>.env&lt;/code>、&lt;code>.user.ini&lt;/code>）。要在「伺服器 → 強制顯示隱藏檔案」啟用，否則接手時會漏拉這些關鍵設定檔。&lt;/p>
&lt;p>FTP 傳輸是逐檔覆寫、沒有原子性——上傳到一半斷線會讓伺服器上同時存在新舊版本的混合狀態。對關鍵檔案（&lt;code>index.php&lt;/code>、&lt;code>.htaccess&lt;/code>）的上傳需要額外小心。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;p>無。FileZilla 是獨立工具。替代工具包括 WinSCP（Windows）、Cyberduck（macOS）、Transmit（macOS）。&lt;/p></description><content:encoded><![CDATA[<p>FileZilla 是一套開源的 FTP / SFTP / FTPS client，支援 Windows、macOS 和 Linux。它的介面分成本地和遠端兩側的檔案瀏覽器，讓使用者透過拖放或右鍵選單在本機與伺服器之間傳輸檔案。在無 SSH 的主機環境裡，FileZilla 是上傳程式碼和下載備份的主要工具。</p>
<h2 id="概念位置">概念位置</h2>
<p>FTP 是無 SSH 環境裡傳輸檔案的主要協定。FileZilla 把 FTP 操作從 CLI（如 <code>ftp</code> 或 <code>lftp</code> 指令）包裝成圖形介面，降低操作門檻。接手維運時，FileZilla 的角色是「把整個站台拉回本地」和「把改好的檔案推上 prod」。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下情境會用到 FileZilla：接手的專案只有 FTP 帳密沒有 SSH key；部署方式是「FTP 上傳改過的檔案」；或者需要對比本地版本和伺服器版本的差異。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 FileZilla 時有三個關鍵功能和注意事項。</p>
<p><strong>站台管理員</strong>：儲存多組 FTP 連線設定（主機、帳號、密碼、port），避免每次手動輸入。接手時第一步是在站台管理員建好 prod 的連線，並確認協定選擇正確（FTP 明文、FTPS 加密、SFTP 走 SSH）。</p>
<p><strong>目錄比較</strong>：「檢視 → 目錄比較 → 啟用」功能會標示本地與遠端的檔案差異——哪些本地較新、哪些遠端較新、哪些只存在於一邊。上傳前先跑目錄比較可以看到即將改動的範圍。</p>
<p><strong>隱藏檔</strong>：預設不顯示以 <code>.</code> 開頭的檔案（如 <code>.htaccess</code>、<code>.env</code>、<code>.user.ini</code>）。要在「伺服器 → 強制顯示隱藏檔案」啟用，否則接手時會漏拉這些關鍵設定檔。</p>
<p>FTP 傳輸是逐檔覆寫、沒有原子性——上傳到一半斷線會讓伺服器上同時存在新舊版本的混合狀態。對關鍵檔案（<code>index.php</code>、<code>.htaccess</code>）的上傳需要額外小心。</p>
<h2 id="鄰卡">鄰卡</h2>
<p>無。FileZilla 是獨立工具。替代工具包括 WinSCP（Windows）、Cyberduck（macOS）、Transmit（macOS）。</p>
]]></content:encoded></item><item><title>cPanel</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/cpanel/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/cpanel/</guid><description>&lt;p>cPanel 是最常見的 Web 主機管理面板，讓租用主機的使用者透過瀏覽器管理伺服器的常用功能——PHP 版本切換、cron job 排程、email 帳號管理、SSL 憑證安裝、檔案管理、資料庫管理、以及完整備份。Plesk 是同類產品，功能範圍相似但介面和設定路徑不同。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>cPanel 是無 SSH 環境裡的「控制中心」。它整合了多種工具的圖形入口：phpMyAdmin（資料庫）、檔案管理員（web 版 FTP）、PHP 設定、cron 編輯器、SSL/TLS 管理。接手維運時，第一步是確認有沒有 cPanel 存取權——有的話很多操作（備份、PHP 版本、cron）可以在面板裡完成，不需要 SSH。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>以下情境代表環境有 cPanel：主機商提供了 cPanel 登入 URL（通常是 &lt;code>domain:2083&lt;/code>）；接手時收到的帳密包含「cPanel 帳號」；或者主機商的服務說明提到 cPanel / WHM。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>接手維運時，cPanel 有幾個關鍵功能要確認：&lt;/p>
&lt;p>&lt;strong>完整備份&lt;/strong>：「備份精靈」可以一次打包整個帳號（檔案 + 資料庫 + email + cron + DNS 設定）。這是最快的「拍下現況」方式——比 FTP 逐檔拉 + phpMyAdmin 匯出快得多。但完整備份通常只能下載、不能自動排程到外部儲存（部分主機商限制）。&lt;/p>
&lt;p>&lt;strong>PHP 版本選擇器&lt;/strong>：可以切換整個帳號或單一域名的 PHP 版本。升級 PHP 時，可以先在 staging 子域名切到新版本測試、確認沒問題再切主域名。這是無 SSH 環境裡最安全的 PHP 升級方式。&lt;/p>
&lt;p>&lt;strong>cron job 管理&lt;/strong>：圖形介面設定排程任務，語法是 cron 標準格式。接手時要截圖或匯出所有 cron——它們可能是系統運作的隱性依賴（定期清快取、寄報表、同步資料）。&lt;/p>
&lt;p>&lt;strong>SSL/TLS&lt;/strong>：管理 HTTPS 憑證。部分主機商整合了 Let&amp;rsquo;s Encrypt 自動簽發，部分需要手動上傳憑證。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin&lt;/a>：通常內嵌在 cPanel 的「資料庫」區塊裡&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>cPanel 是最常見的 Web 主機管理面板，讓租用主機的使用者透過瀏覽器管理伺服器的常用功能——PHP 版本切換、cron job 排程、email 帳號管理、SSL 憑證安裝、檔案管理、資料庫管理、以及完整備份。Plesk 是同類產品，功能範圍相似但介面和設定路徑不同。</p>
<h2 id="概念位置">概念位置</h2>
<p>cPanel 是無 SSH 環境裡的「控制中心」。它整合了多種工具的圖形入口：phpMyAdmin（資料庫）、檔案管理員（web 版 FTP）、PHP 設定、cron 編輯器、SSL/TLS 管理。接手維運時，第一步是確認有沒有 cPanel 存取權——有的話很多操作（備份、PHP 版本、cron）可以在面板裡完成，不需要 SSH。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>以下情境代表環境有 cPanel：主機商提供了 cPanel 登入 URL（通常是 <code>domain:2083</code>）；接手時收到的帳密包含「cPanel 帳號」；或者主機商的服務說明提到 cPanel / WHM。</p>
<h2 id="設計責任">設計責任</h2>
<p>接手維運時，cPanel 有幾個關鍵功能要確認：</p>
<p><strong>完整備份</strong>：「備份精靈」可以一次打包整個帳號（檔案 + 資料庫 + email + cron + DNS 設定）。這是最快的「拍下現況」方式——比 FTP 逐檔拉 + phpMyAdmin 匯出快得多。但完整備份通常只能下載、不能自動排程到外部儲存（部分主機商限制）。</p>
<p><strong>PHP 版本選擇器</strong>：可以切換整個帳號或單一域名的 PHP 版本。升級 PHP 時，可以先在 staging 子域名切到新版本測試、確認沒問題再切主域名。這是無 SSH 環境裡最安全的 PHP 升級方式。</p>
<p><strong>cron job 管理</strong>：圖形介面設定排程任務，語法是 cron 標準格式。接手時要截圖或匯出所有 cron——它們可能是系統運作的隱性依賴（定期清快取、寄報表、同步資料）。</p>
<p><strong>SSL/TLS</strong>：管理 HTTPS 憑證。部分主機商整合了 Let&rsquo;s Encrypt 自動簽發，部分需要手動上傳憑證。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin</a>：通常內嵌在 cPanel 的「資料庫」區塊裡</li>
</ul>
]]></content:encoded></item><item><title>.htaccess</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/htaccess/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/htaccess/</guid><description>&lt;p>&lt;code>.htaccess&lt;/code>（Hypertext Access）是 Apache Web Server 的目錄層級設定檔。它讓使用者在沒有伺服器管理員權限的情況下，覆寫 Apache 的部分全域設定——包括 URL 重寫規則、目錄存取控制、PHP 設定覆寫、HTTPS 強制跳轉、以及 HTTP 安全標頭。每個目錄可以有自己的 &lt;code>.htaccess&lt;/code>，Apache 處理請求時會從根目錄到目標目錄逐層讀取並套用。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>在 Apache 為主的主機環境（多數共享主機和部分 VPS），&lt;code>.htaccess&lt;/code> 是不需要重啟伺服器就能調整行為的設定機制。WordPress、Laravel、Drupal 等 PHP 框架都依賴 &lt;code>.htaccess&lt;/code> 的 URL rewrite 規則來實現 pretty URL（把 &lt;code>/blog/post-title&lt;/code> 轉成 &lt;code>index.php?page=post-title&lt;/code>）。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>站台根目錄有 &lt;code>.htaccess&lt;/code> 檔案（注意它是隱藏檔，FTP client 要啟用「顯示隱藏檔案」才看得到）。上傳目錄（&lt;code>uploads/&lt;/code>）、後台目錄（&lt;code>admin/&lt;/code>、&lt;code>wp-admin/&lt;/code>）可能各有一份獨立的 &lt;code>.htaccess&lt;/code> 做額外的存取控制。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>接手維運時，&lt;code>.htaccess&lt;/code> 要注意四件事：&lt;/p>
&lt;p>&lt;strong>URL rewrite 規則&lt;/strong>：這些規則決定了站台的 URL 結構。亂改或刪除會讓所有內頁都回 404。修改前先備份原始版本。&lt;/p>
&lt;p>&lt;strong>安全設定&lt;/strong>：&lt;code>Options -Indexes&lt;/code> 禁止目錄列表、&lt;code>php_flag engine off&lt;/code> 禁止上傳目錄執行 PHP、&lt;code>Require all denied&lt;/code> 禁止存取 &lt;code>.env&lt;/code> 等機密檔案。這些設定分散在多個目錄的 &lt;code>.htaccess&lt;/code> 裡，接手時要全部找出來。&lt;/p>
&lt;p>&lt;strong>PHP 設定覆寫&lt;/strong>：部分 PHP 設定（如 &lt;code>upload_max_filesize&lt;/code>、&lt;code>max_execution_time&lt;/code>）可以在 &lt;code>.htaccess&lt;/code> 裡用 &lt;code>php_value&lt;/code> 或 &lt;code>php_flag&lt;/code> 指令覆寫。這些覆寫可能不在 &lt;code>php.ini&lt;/code> 裡，只存在於 &lt;code>.htaccess&lt;/code>。&lt;/p>
&lt;p>&lt;strong>遷移到 nginx 的影響&lt;/strong>：nginx 沒有 &lt;code>.htaccess&lt;/code> 的對等機制——所有設定都在集中的 nginx 設定檔裡。從 Apache 遷移到 nginx 時，&lt;code>.htaccess&lt;/code> 裡的每一條規則都要手動轉換成 nginx 語法。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/php-ini/" data-link-title="php.ini / .user.ini" data-link-desc="PHP 的執行期設定檔，控制記憶體上限、上傳大小、錯誤報告等 runtime 行為">php.ini / .user.ini&lt;/a>：&lt;code>.htaccess&lt;/code> 管 Apache 行為，&lt;code>.user.ini&lt;/code> 管 PHP 行為，兩者互補&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p><code>.htaccess</code>（Hypertext Access）是 Apache Web Server 的目錄層級設定檔。它讓使用者在沒有伺服器管理員權限的情況下，覆寫 Apache 的部分全域設定——包括 URL 重寫規則、目錄存取控制、PHP 設定覆寫、HTTPS 強制跳轉、以及 HTTP 安全標頭。每個目錄可以有自己的 <code>.htaccess</code>，Apache 處理請求時會從根目錄到目標目錄逐層讀取並套用。</p>
<h2 id="概念位置">概念位置</h2>
<p>在 Apache 為主的主機環境（多數共享主機和部分 VPS），<code>.htaccess</code> 是不需要重啟伺服器就能調整行為的設定機制。WordPress、Laravel、Drupal 等 PHP 框架都依賴 <code>.htaccess</code> 的 URL rewrite 規則來實現 pretty URL（把 <code>/blog/post-title</code> 轉成 <code>index.php?page=post-title</code>）。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>站台根目錄有 <code>.htaccess</code> 檔案（注意它是隱藏檔，FTP client 要啟用「顯示隱藏檔案」才看得到）。上傳目錄（<code>uploads/</code>）、後台目錄（<code>admin/</code>、<code>wp-admin/</code>）可能各有一份獨立的 <code>.htaccess</code> 做額外的存取控制。</p>
<h2 id="設計責任">設計責任</h2>
<p>接手維運時，<code>.htaccess</code> 要注意四件事：</p>
<p><strong>URL rewrite 規則</strong>：這些規則決定了站台的 URL 結構。亂改或刪除會讓所有內頁都回 404。修改前先備份原始版本。</p>
<p><strong>安全設定</strong>：<code>Options -Indexes</code> 禁止目錄列表、<code>php_flag engine off</code> 禁止上傳目錄執行 PHP、<code>Require all denied</code> 禁止存取 <code>.env</code> 等機密檔案。這些設定分散在多個目錄的 <code>.htaccess</code> 裡，接手時要全部找出來。</p>
<p><strong>PHP 設定覆寫</strong>：部分 PHP 設定（如 <code>upload_max_filesize</code>、<code>max_execution_time</code>）可以在 <code>.htaccess</code> 裡用 <code>php_value</code> 或 <code>php_flag</code> 指令覆寫。這些覆寫可能不在 <code>php.ini</code> 裡，只存在於 <code>.htaccess</code>。</p>
<p><strong>遷移到 nginx 的影響</strong>：nginx 沒有 <code>.htaccess</code> 的對等機制——所有設定都在集中的 nginx 設定檔裡。從 Apache 遷移到 nginx 時，<code>.htaccess</code> 裡的每一條規則都要手動轉換成 nginx 語法。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/php-ini/" data-link-title="php.ini / .user.ini" data-link-desc="PHP 的執行期設定檔，控制記憶體上限、上傳大小、錯誤報告等 runtime 行為">php.ini / .user.ini</a>：<code>.htaccess</code> 管 Apache 行為，<code>.user.ini</code> 管 PHP 行為，兩者互補</li>
</ul>
]]></content:encoded></item><item><title>.env</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/dotenv/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/dotenv/</guid><description>&lt;p>&lt;code>.env&lt;/code> 是一個純文字檔案，每行一組 &lt;code>KEY=VALUE&lt;/code> 的環境變數定義。它的用途是把機密值（資料庫密碼、API key、SMTP 憑證）和環境專屬設定（資料庫 host、debug 模式開關）從程式碼分離出來，讓同一份程式碼在不同環境（開發、staging、production）用不同的設定值，而且機密值不進版本控制。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>&lt;code>.env&lt;/code> 是跨語言的設定分離慣例。PHP 用 &lt;code>vlucas/phpdotenv&lt;/code> 套件讀取、Node.js 用 &lt;code>dotenv&lt;/code> 套件、Python 用 &lt;code>python-dotenv&lt;/code>、Go 用 &lt;code>godotenv&lt;/code>。這些套件的行為相同：程式啟動時讀 &lt;code>.env&lt;/code> 檔案，把裡面的變數載入到執行環境的環境變數裡，讓程式碼用 &lt;code>$_ENV['KEY']&lt;/code>（PHP）或 &lt;code>process.env.KEY&lt;/code>（Node）存取。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>站台根目錄有 &lt;code>.env&lt;/code> 或 &lt;code>.env.production&lt;/code> 檔案；&lt;code>.gitignore&lt;/code> 裡有 &lt;code>.env&lt;/code> 這一行；repo 裡有 &lt;code>.env.example&lt;/code> 或 &lt;code>.env.sample&lt;/code> 列出所有需要的變數但不填實際值。如果接手的專案沒有 &lt;code>.env&lt;/code> 但 &lt;code>config.php&lt;/code> 裡直接寫了資料庫密碼，代表設定分離還沒做——這是接手後應該處理的事。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 &lt;code>.env&lt;/code> 時有三個紀律：&lt;/p>
&lt;p>&lt;strong>不進 Git&lt;/strong>：&lt;code>.env&lt;/code> 包含明文密碼，進了 Git 就跟著每一次 clone、fork、CI 快取擴散。&lt;code>.gitignore&lt;/code> 必須排除 &lt;code>.env&lt;/code>。如果 &lt;code>.env&lt;/code> 已經在 Git 歷史裡，刪掉那一行不夠——密碼留在 history 裡，要輪替所有外洩的密碼。&lt;/p>
&lt;p>&lt;strong>範本檔進 Git&lt;/strong>：repo 裡放一份 &lt;code>.env.example&lt;/code>，列出所有必要的環境變數但不填實際值。新接手的人複製 &lt;code>.env.example&lt;/code> 成 &lt;code>.env&lt;/code>，再填入自己環境的值。&lt;/p>
&lt;p>&lt;strong>不用 &lt;code>.env&lt;/code> 管非機密設定&lt;/strong>：應用程式的功能開關、UI 設定、feature flag 不屬於 &lt;code>.env&lt;/code>——這些設定沒有機密性、應該進版本控制。&lt;code>.env&lt;/code> 只放「換一個環境就要改的值」和「不能被看到的值」。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/php-ini/" data-link-title="php.ini / .user.ini" data-link-desc="PHP 的執行期設定檔，控制記憶體上限、上傳大小、錯誤報告等 runtime 行為">php.ini / .user.ini&lt;/a>：&lt;code>.env&lt;/code> 管應用程式設定、php.ini 管 PHP runtime 設定&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p><code>.env</code> 是一個純文字檔案，每行一組 <code>KEY=VALUE</code> 的環境變數定義。它的用途是把機密值（資料庫密碼、API key、SMTP 憑證）和環境專屬設定（資料庫 host、debug 模式開關）從程式碼分離出來，讓同一份程式碼在不同環境（開發、staging、production）用不同的設定值，而且機密值不進版本控制。</p>
<h2 id="概念位置">概念位置</h2>
<p><code>.env</code> 是跨語言的設定分離慣例。PHP 用 <code>vlucas/phpdotenv</code> 套件讀取、Node.js 用 <code>dotenv</code> 套件、Python 用 <code>python-dotenv</code>、Go 用 <code>godotenv</code>。這些套件的行為相同：程式啟動時讀 <code>.env</code> 檔案，把裡面的變數載入到執行環境的環境變數裡，讓程式碼用 <code>$_ENV['KEY']</code>（PHP）或 <code>process.env.KEY</code>（Node）存取。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>站台根目錄有 <code>.env</code> 或 <code>.env.production</code> 檔案；<code>.gitignore</code> 裡有 <code>.env</code> 這一行；repo 裡有 <code>.env.example</code> 或 <code>.env.sample</code> 列出所有需要的變數但不填實際值。如果接手的專案沒有 <code>.env</code> 但 <code>config.php</code> 裡直接寫了資料庫密碼，代表設定分離還沒做——這是接手後應該處理的事。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 <code>.env</code> 時有三個紀律：</p>
<p><strong>不進 Git</strong>：<code>.env</code> 包含明文密碼，進了 Git 就跟著每一次 clone、fork、CI 快取擴散。<code>.gitignore</code> 必須排除 <code>.env</code>。如果 <code>.env</code> 已經在 Git 歷史裡，刪掉那一行不夠——密碼留在 history 裡，要輪替所有外洩的密碼。</p>
<p><strong>範本檔進 Git</strong>：repo 裡放一份 <code>.env.example</code>，列出所有必要的環境變數但不填實際值。新接手的人複製 <code>.env.example</code> 成 <code>.env</code>，再填入自己環境的值。</p>
<p><strong>不用 <code>.env</code> 管非機密設定</strong>：應用程式的功能開關、UI 設定、feature flag 不屬於 <code>.env</code>——這些設定沒有機密性、應該進版本控制。<code>.env</code> 只放「換一個環境就要改的值」和「不能被看到的值」。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/php-ini/" data-link-title="php.ini / .user.ini" data-link-desc="PHP 的執行期設定檔，控制記憶體上限、上傳大小、錯誤報告等 runtime 行為">php.ini / .user.ini</a>：<code>.env</code> 管應用程式設定、php.ini 管 PHP runtime 設定</li>
</ul>
]]></content:encoded></item><item><title>php.ini / .user.ini</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/php-ini/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/php-ini/</guid><description>&lt;p>&lt;code>php.ini&lt;/code> 是 PHP 的全域設定檔，控制 PHP 的 runtime 行為——記憶體上限、檔案上傳大小、最大執行時間、錯誤報告層級、時區、session 處理方式。&lt;code>.user.ini&lt;/code> 是 PHP 5.3 之後支援的目錄層級覆寫機制，放在站台目錄裡可以覆寫部分 &lt;code>php.ini&lt;/code> 的設定，不需要伺服器管理員權限。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>&lt;code>php.ini&lt;/code> 由伺服器管理員管理，租用主機的使用者通常不能直接修改。&lt;code>.user.ini&lt;/code> 是使用者層級的設定覆寫——功能上類似 &lt;code>.htaccess&lt;/code> 對 Apache 的角色，但只管 PHP 設定。在 cPanel 環境裡，部分設定也可以透過「PHP 選擇器」的圖形介面調整。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>PHP 行為異常時要檢查的第一個地方。常見的情境：上傳檔案失敗（&lt;code>upload_max_filesize&lt;/code> 太小）、長時間運算被中斷（&lt;code>max_execution_time&lt;/code> 太短）、記憶體不足錯誤（&lt;code>memory_limit&lt;/code> 太低）、看不到錯誤訊息（&lt;code>display_errors&lt;/code> 關閉）。用 &lt;code>phpinfo()&lt;/code> 可以看到每一項設定的目前值和來源（&lt;code>php.ini&lt;/code> / &lt;code>.user.ini&lt;/code> / &lt;code>.htaccess&lt;/code>）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>接手維運時要知道的關鍵設定：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>設定&lt;/th>
 &lt;th>作用&lt;/th>
 &lt;th>常見預設值&lt;/th>
 &lt;th>接手時要確認的事&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>memory_limit&lt;/code>&lt;/td>
 &lt;td>PHP 程式的記憶體上限&lt;/td>
 &lt;td>128M&lt;/td>
 &lt;td>大型操作（匯出、圖片處理）是否夠用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>upload_max_filesize&lt;/code>&lt;/td>
 &lt;td>單檔上傳大小上限&lt;/td>
 &lt;td>2M&lt;/td>
 &lt;td>是否符合業務需求&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>post_max_size&lt;/code>&lt;/td>
 &lt;td>POST 請求的總大小上限&lt;/td>
 &lt;td>8M&lt;/td>
 &lt;td>要大於 upload_max_filesize&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>max_execution_time&lt;/code>&lt;/td>
 &lt;td>PHP 腳本最大執行秒數&lt;/td>
 &lt;td>30&lt;/td>
 &lt;td>長時間操作（備份、匯入）是否需要加長&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>error_reporting&lt;/code>&lt;/td>
 &lt;td>顯示哪些層級的錯誤&lt;/td>
 &lt;td>E_ALL&lt;/td>
 &lt;td>開發時開到 E_ALL、production 時關 display_errors&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>display_errors&lt;/code>&lt;/td>
 &lt;td>是否在頁面上顯示錯誤&lt;/td>
 &lt;td>Off&lt;/td>
 &lt;td>production 應該關閉（錯誤寫 log 不顯示給使用者）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;code>.user.ini&lt;/code> 的修改不需要重啟 Apache/nginx，但有快取時間（預設 300 秒）——改完後要等最多 5 分鐘才生效。&lt;code>php.ini&lt;/code> 的修改在多數環境需要重啟 web server。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/htaccess/" data-link-title=".htaccess" data-link-desc="Apache Web Server 的目錄層級設定檔，控制 URL rewrite、存取權限、PHP 設定覆寫與安全標頭">.htaccess&lt;/a>：&lt;code>.htaccess&lt;/code> 管 Apache 行為（URL rewrite、存取控制），&lt;code>.user.ini&lt;/code> 管 PHP 行為（記憶體、執行時間），兩者互補&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/dotenv/" data-link-title=".env" data-link-desc="存放環境變數的純文字檔案，把機密值從程式碼分離出來">.env&lt;/a>：&lt;code>.env&lt;/code> 管應用程式設定（DB 密碼、API key），&lt;code>php.ini&lt;/code> 管 PHP runtime 設定（記憶體、上傳大小）&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p><code>php.ini</code> 是 PHP 的全域設定檔，控制 PHP 的 runtime 行為——記憶體上限、檔案上傳大小、最大執行時間、錯誤報告層級、時區、session 處理方式。<code>.user.ini</code> 是 PHP 5.3 之後支援的目錄層級覆寫機制，放在站台目錄裡可以覆寫部分 <code>php.ini</code> 的設定，不需要伺服器管理員權限。</p>
<h2 id="概念位置">概念位置</h2>
<p><code>php.ini</code> 由伺服器管理員管理，租用主機的使用者通常不能直接修改。<code>.user.ini</code> 是使用者層級的設定覆寫——功能上類似 <code>.htaccess</code> 對 Apache 的角色，但只管 PHP 設定。在 cPanel 環境裡，部分設定也可以透過「PHP 選擇器」的圖形介面調整。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>PHP 行為異常時要檢查的第一個地方。常見的情境：上傳檔案失敗（<code>upload_max_filesize</code> 太小）、長時間運算被中斷（<code>max_execution_time</code> 太短）、記憶體不足錯誤（<code>memory_limit</code> 太低）、看不到錯誤訊息（<code>display_errors</code> 關閉）。用 <code>phpinfo()</code> 可以看到每一項設定的目前值和來源（<code>php.ini</code> / <code>.user.ini</code> / <code>.htaccess</code>）。</p>
<h2 id="設計責任">設計責任</h2>
<p>接手維運時要知道的關鍵設定：</p>
<table>
  <thead>
      <tr>
          <th>設定</th>
          <th>作用</th>
          <th>常見預設值</th>
          <th>接手時要確認的事</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>memory_limit</code></td>
          <td>PHP 程式的記憶體上限</td>
          <td>128M</td>
          <td>大型操作（匯出、圖片處理）是否夠用</td>
      </tr>
      <tr>
          <td><code>upload_max_filesize</code></td>
          <td>單檔上傳大小上限</td>
          <td>2M</td>
          <td>是否符合業務需求</td>
      </tr>
      <tr>
          <td><code>post_max_size</code></td>
          <td>POST 請求的總大小上限</td>
          <td>8M</td>
          <td>要大於 upload_max_filesize</td>
      </tr>
      <tr>
          <td><code>max_execution_time</code></td>
          <td>PHP 腳本最大執行秒數</td>
          <td>30</td>
          <td>長時間操作（備份、匯入）是否需要加長</td>
      </tr>
      <tr>
          <td><code>error_reporting</code></td>
          <td>顯示哪些層級的錯誤</td>
          <td>E_ALL</td>
          <td>開發時開到 E_ALL、production 時關 display_errors</td>
      </tr>
      <tr>
          <td><code>display_errors</code></td>
          <td>是否在頁面上顯示錯誤</td>
          <td>Off</td>
          <td>production 應該關閉（錯誤寫 log 不顯示給使用者）</td>
      </tr>
  </tbody>
</table>
<p><code>.user.ini</code> 的修改不需要重啟 Apache/nginx，但有快取時間（預設 300 秒）——改完後要等最多 5 分鐘才生效。<code>php.ini</code> 的修改在多數環境需要重啟 web server。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/htaccess/" data-link-title=".htaccess" data-link-desc="Apache Web Server 的目錄層級設定檔，控制 URL rewrite、存取權限、PHP 設定覆寫與安全標頭">.htaccess</a>：<code>.htaccess</code> 管 Apache 行為（URL rewrite、存取控制），<code>.user.ini</code> 管 PHP 行為（記憶體、執行時間），兩者互補</li>
<li><a href="/blog/infra/knowledge-cards/dotenv/" data-link-title=".env" data-link-desc="存放環境變數的純文字檔案，把機密值從程式碼分離出來">.env</a>：<code>.env</code> 管應用程式設定（DB 密碼、API key），<code>php.ini</code> 管 PHP runtime 設定（記憶體、上傳大小）</li>
</ul>
]]></content:encoded></item><item><title>DNS</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/dns/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/dns/</guid><description>&lt;p>DNS（Domain Name System）是把人類可讀的域名（&lt;code>example.com&lt;/code>）轉成機器可達的 IP 位址（&lt;code>93.184.216.34&lt;/code>）的分散式查詢系統。瀏覽器輸入網址後，作業系統先查本地快取、再逐層查詢 DNS server，最終拿到 IP 才能建立連線。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>DNS 在 infra 裡扮演「服務的門牌」角色。平台遷移、環境切換、TLS 憑證驗證都經過 DNS。ALB 或 CDN 前面通常掛一層 DNS record 作為穩定入口——IP 會隨資源重建而變，DNS 名稱不變。&lt;/p>
&lt;h2 id="常見的記錄類型">常見的記錄類型&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>類型&lt;/th>
 &lt;th>指向什麼&lt;/th>
 &lt;th>典型用途&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>A&lt;/td>
 &lt;td>IPv4 位址&lt;/td>
 &lt;td>主要的域名 → IP 對應&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>AAAA&lt;/td>
 &lt;td>IPv6 位址&lt;/td>
 &lt;td>IPv6 環境&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>CNAME&lt;/td>
 &lt;td>另一個域名&lt;/td>
 &lt;td>別名（&lt;code>www&lt;/code> → &lt;code>example.com&lt;/code>）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>NS&lt;/td>
 &lt;td>負責管理的 DNS server&lt;/td>
 &lt;td>子域委派（dev.example.com）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>MX&lt;/td>
 &lt;td>郵件伺服器&lt;/td>
 &lt;td>email routing&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>TXT&lt;/td>
 &lt;td>任意文字&lt;/td>
 &lt;td>SPF / DKIM / 域名驗證（ACM）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Alias&lt;/td>
 &lt;td>AWS 特有，指向 ALB 等&lt;/td>
 &lt;td>跟 A record 等效但支援 zone apex&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>平台遷移時 DNS 切換是最後一步也是最不可控的一步——TTL（Time To Live）決定舊記錄被各地 DNS resolver 快取多久。TTL 300 秒代表切換後最多 5 分鐘全部 client 會指向新 IP；TTL 86400（1 天）代表最慢要等一天。遷移前 48 小時先降 TTL 到 300 秒，讓快取過期後所有 resolver 都拿到短 TTL 版本，切換時才能快速生效。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>DNS 設定要決定：誰管這個域名的 zone（Route 53 / Cloudflare / 域名商）、子域怎麼委派（dev / staging 用 NS delegation 交給不同 zone）、TTL 設多少（平常 3600 秒夠用、遷移前降到 300）。ACM 的 DNS 驗證也依賴 DNS——建立 TXT 或 CNAME 記錄證明域名歸屬。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a> — DNS 記錄通常指向 ALB 作為流量入口&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ssl-tls/" data-link-title="SSL / TLS" data-link-desc="加密 client 與 server 之間通訊的協定，讓 HTTPS 成為可能。TLS 是 SSL 的後繼者，但 SSL 憑證的稱呼仍廣泛使用">SSL/TLS&lt;/a> — TLS 憑證的 DNS 驗證依賴 DNS record&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>DNS（Domain Name System）是把人類可讀的域名（<code>example.com</code>）轉成機器可達的 IP 位址（<code>93.184.216.34</code>）的分散式查詢系統。瀏覽器輸入網址後，作業系統先查本地快取、再逐層查詢 DNS server，最終拿到 IP 才能建立連線。</p>
<h2 id="概念位置">概念位置</h2>
<p>DNS 在 infra 裡扮演「服務的門牌」角色。平台遷移、環境切換、TLS 憑證驗證都經過 DNS。ALB 或 CDN 前面通常掛一層 DNS record 作為穩定入口——IP 會隨資源重建而變，DNS 名稱不變。</p>
<h2 id="常見的記錄類型">常見的記錄類型</h2>
<table>
  <thead>
      <tr>
          <th>類型</th>
          <th>指向什麼</th>
          <th>典型用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>A</td>
          <td>IPv4 位址</td>
          <td>主要的域名 → IP 對應</td>
      </tr>
      <tr>
          <td>AAAA</td>
          <td>IPv6 位址</td>
          <td>IPv6 環境</td>
      </tr>
      <tr>
          <td>CNAME</td>
          <td>另一個域名</td>
          <td>別名（<code>www</code> → <code>example.com</code>）</td>
      </tr>
      <tr>
          <td>NS</td>
          <td>負責管理的 DNS server</td>
          <td>子域委派（dev.example.com）</td>
      </tr>
      <tr>
          <td>MX</td>
          <td>郵件伺服器</td>
          <td>email routing</td>
      </tr>
      <tr>
          <td>TXT</td>
          <td>任意文字</td>
          <td>SPF / DKIM / 域名驗證（ACM）</td>
      </tr>
      <tr>
          <td>Alias</td>
          <td>AWS 特有，指向 ALB 等</td>
          <td>跟 A record 等效但支援 zone apex</td>
      </tr>
  </tbody>
</table>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>平台遷移時 DNS 切換是最後一步也是最不可控的一步——TTL（Time To Live）決定舊記錄被各地 DNS resolver 快取多久。TTL 300 秒代表切換後最多 5 分鐘全部 client 會指向新 IP；TTL 86400（1 天）代表最慢要等一天。遷移前 48 小時先降 TTL 到 300 秒，讓快取過期後所有 resolver 都拿到短 TTL 版本，切換時才能快速生效。</p>
<h2 id="設計責任">設計責任</h2>
<p>DNS 設定要決定：誰管這個域名的 zone（Route 53 / Cloudflare / 域名商）、子域怎麼委派（dev / staging 用 NS delegation 交給不同 zone）、TTL 設多少（平常 3600 秒夠用、遷移前降到 300）。ACM 的 DNS 驗證也依賴 DNS——建立 TXT 或 CNAME 記錄證明域名歸屬。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a> — DNS 記錄通常指向 ALB 作為流量入口</li>
<li><a href="/blog/infra/knowledge-cards/ssl-tls/" data-link-title="SSL / TLS" data-link-desc="加密 client 與 server 之間通訊的協定，讓 HTTPS 成為可能。TLS 是 SSL 的後繼者，但 SSL 憑證的稱呼仍廣泛使用">SSL/TLS</a> — TLS 憑證的 DNS 驗證依賴 DNS record</li>
</ul>
]]></content:encoded></item><item><title>SSL / TLS</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ssl-tls/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ssl-tls/</guid><description>&lt;p>TLS（Transport Layer Security）加密 client 與 server 之間的通訊，防止中間人竊聽或竄改。HTTPS 就是 HTTP 加上 TLS 加密層。SSL 是 TLS 的前身、所有版本都已被棄用，但「SSL 憑證」這個稱呼仍然廣泛使用——實際上指的是 TLS 憑證。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>TLS 在 infra 裡負責「傳輸安全」。ALB 的 HTTPS listener 需要掛一張 TLS 憑證；ACM（AWS Certificate Manager）提供免費的憑證申請與自動續期；Let&amp;rsquo;s Encrypt 是跨平台的免費 CA（Certificate Authority，憑證簽發機構）。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>TLS 憑證有到期日。過期的憑證會讓瀏覽器顯示安全警告、部分 client 直接拒絕連線。ACM 管理的憑證會自動續期（前提是 DNS 驗證記錄仍然存在）；手動上傳的憑證需要人工追蹤到期日。接手維運時要確認：憑證的簽發者是誰、到期日是什麼時候、續期是自動還是手動。&lt;/p>
&lt;p>用 CLI 查看遠端憑證資訊：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="p">|&lt;/span> openssl s_client -connect example.com:443 2&amp;gt;/dev/null &lt;span class="p">|&lt;/span> openssl x509 -noout -dates -issuer&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>TLS 設定要決定：憑證從哪裡來（ACM 免費但只能用在 AWS 服務上、Let&amp;rsquo;s Encrypt 免費且跨平台）、驗證方式（DNS 驗證適合自動化、email 驗證較手動）、是否需要多域名的 SAN 憑證（一張憑證涵蓋 &lt;code>example.com&lt;/code> + &lt;code>*.example.com&lt;/code>）、HTTP → HTTPS 的強制跳轉怎麼設。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/dns/" data-link-title="DNS" data-link-desc="Domain Name System — 把域名轉成 IP 位址的系統，以及 A record、CNAME、NS、TTL 的角色">DNS&lt;/a> — TLS 憑證的 DNS 驗證依賴 DNS record&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a> — HTTPS listener 需要掛 TLS 憑證&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>TLS（Transport Layer Security）加密 client 與 server 之間的通訊，防止中間人竊聽或竄改。HTTPS 就是 HTTP 加上 TLS 加密層。SSL 是 TLS 的前身、所有版本都已被棄用，但「SSL 憑證」這個稱呼仍然廣泛使用——實際上指的是 TLS 憑證。</p>
<h2 id="概念位置">概念位置</h2>
<p>TLS 在 infra 裡負責「傳輸安全」。ALB 的 HTTPS listener 需要掛一張 TLS 憑證；ACM（AWS Certificate Manager）提供免費的憑證申請與自動續期；Let&rsquo;s Encrypt 是跨平台的免費 CA（Certificate Authority，憑證簽發機構）。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>TLS 憑證有到期日。過期的憑證會讓瀏覽器顯示安全警告、部分 client 直接拒絕連線。ACM 管理的憑證會自動續期（前提是 DNS 驗證記錄仍然存在）；手動上傳的憑證需要人工追蹤到期日。接手維運時要確認：憑證的簽發者是誰、到期日是什麼時候、續期是自動還是手動。</p>
<p>用 CLI 查看遠端憑證資訊：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="p">|</span> openssl s_client -connect example.com:443 2&gt;/dev/null <span class="p">|</span> openssl x509 -noout -dates -issuer</span></span></code></pre></div><h2 id="設計責任">設計責任</h2>
<p>TLS 設定要決定：憑證從哪裡來（ACM 免費但只能用在 AWS 服務上、Let&rsquo;s Encrypt 免費且跨平台）、驗證方式（DNS 驗證適合自動化、email 驗證較手動）、是否需要多域名的 SAN 憑證（一張憑證涵蓋 <code>example.com</code> + <code>*.example.com</code>）、HTTP → HTTPS 的強制跳轉怎麼設。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/dns/" data-link-title="DNS" data-link-desc="Domain Name System — 把域名轉成 IP 位址的系統，以及 A record、CNAME、NS、TTL 的角色">DNS</a> — TLS 憑證的 DNS 驗證依賴 DNS record</li>
<li><a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a> — HTTPS listener 需要掛 TLS 憑證</li>
</ul>
]]></content:encoded></item><item><title>SSH</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ssh/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ssh/</guid><description>&lt;p>SSH（Secure Shell）是加密的遠端 shell 連線協定，讓操作者在本地終端機執行遠端伺服器上的指令。連線建立後，操作者看到的是遠端伺服器的命令列——可以跑任何該伺服器上安裝的 CLI 工具。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>SSH 在接手維運的情境裡是一條關鍵分界線：有 SSH 存取就能用 &lt;code>mysqldump&lt;/code>、&lt;code>git&lt;/code>、&lt;code>systemctl&lt;/code> 等 CLI 工具操作伺服器；沒有 SSH 就只能用 FTP 傳檔案、用 phpMyAdmin 管資料庫、用 cPanel 改設定。兩種情境的操作流程和可用工具完全不同。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>判斷有沒有 SSH 存取：嘗試 &lt;code>ssh user@host&lt;/code>。如果連線成功進入命令列就有；如果 timeout 或被拒，可能是主機不開放 SSH（共享主機常見）、或 port 不是預設的 22、或需要 IP 白名單。cPanel 的「終端機」功能有時提供 web-based SSH，但功能受限。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>SSH 的認證方式有兩種：密碼（簡單但不安全，容易被暴力嘗試）和 SSH key pair（公鑰放在 server 的 &lt;code>~/.ssh/authorized_keys&lt;/code>，私鑰留在 client）。生產環境應該用 key 認證並關閉密碼登入。&lt;/p>
&lt;p>接手維運時要確認：SSH 的登入帳號是什麼、用密碼還是 key、key 在哪裡、有沒有其他人也有存取權限。前任維護者的 SSH key 如果還在 &lt;code>authorized_keys&lt;/code> 裡，離職後應該移除。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 產生 SSH key pair&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">ssh-keygen -t ed25519 -C &lt;span class="s2">&amp;#34;your-email@example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 把公鑰加到遠端 server&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ftp/" data-link-title="FTP" data-link-desc="File Transfer Protocol — 檔案傳輸協定，無 SSH 環境的主要檔案管理方式。SFTP 和 FTPS 是其加密變體">FTP&lt;/a> — 沒有 SSH 時的檔案傳輸替代方案&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>SSH（Secure Shell）是加密的遠端 shell 連線協定，讓操作者在本地終端機執行遠端伺服器上的指令。連線建立後，操作者看到的是遠端伺服器的命令列——可以跑任何該伺服器上安裝的 CLI 工具。</p>
<h2 id="概念位置">概念位置</h2>
<p>SSH 在接手維運的情境裡是一條關鍵分界線：有 SSH 存取就能用 <code>mysqldump</code>、<code>git</code>、<code>systemctl</code> 等 CLI 工具操作伺服器；沒有 SSH 就只能用 FTP 傳檔案、用 phpMyAdmin 管資料庫、用 cPanel 改設定。兩種情境的操作流程和可用工具完全不同。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>判斷有沒有 SSH 存取：嘗試 <code>ssh user@host</code>。如果連線成功進入命令列就有；如果 timeout 或被拒，可能是主機不開放 SSH（共享主機常見）、或 port 不是預設的 22、或需要 IP 白名單。cPanel 的「終端機」功能有時提供 web-based SSH，但功能受限。</p>
<h2 id="設計責任">設計責任</h2>
<p>SSH 的認證方式有兩種：密碼（簡單但不安全，容易被暴力嘗試）和 SSH key pair（公鑰放在 server 的 <code>~/.ssh/authorized_keys</code>，私鑰留在 client）。生產環境應該用 key 認證並關閉密碼登入。</p>
<p>接手維運時要確認：SSH 的登入帳號是什麼、用密碼還是 key、key 在哪裡、有沒有其他人也有存取權限。前任維護者的 SSH key 如果還在 <code>authorized_keys</code> 裡，離職後應該移除。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 產生 SSH key pair</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">ssh-keygen -t ed25519 -C <span class="s2">&#34;your-email@example.com&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># 把公鑰加到遠端 server</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host</span></span></code></pre></div><h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ftp/" data-link-title="FTP" data-link-desc="File Transfer Protocol — 檔案傳輸協定，無 SSH 環境的主要檔案管理方式。SFTP 和 FTPS 是其加密變體">FTP</a> — 沒有 SSH 時的檔案傳輸替代方案</li>
</ul>
]]></content:encoded></item><item><title>FTP</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ftp/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ftp/</guid><description>&lt;p>FTP（File Transfer Protocol）是把檔案在本地電腦與遠端伺服器之間上傳/下載的協定。操作者透過 FTP client（如 FileZilla）連線到伺服器，看到遠端的目錄結構，用拖放或指令傳輸檔案。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>FTP 在無 SSH 的環境裡是唯一的檔案管理途徑——程式碼部署靠 FTP 上傳、備份靠 FTP 下載、檔案比對靠 FTP client 的目錄比較功能。它是接手維運模組「無 SSH 環境」路線的核心工具。&lt;/p>
&lt;h2 id="ftp-的變體">FTP 的變體&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>協定&lt;/th>
 &lt;th>加密方式&lt;/th>
 &lt;th>常見情境&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>FTP&lt;/td>
 &lt;td>無加密（明文傳輸）&lt;/td>
 &lt;td>老舊主機、內部網路&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>FTPS&lt;/td>
 &lt;td>FTP + TLS 加密&lt;/td>
 &lt;td>支援 SSL 的主機&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>SFTP&lt;/td>
 &lt;td>走 SSH 通道（完全不同協定）&lt;/td>
 &lt;td>有 SSH 存取的伺服器&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>多數 FTP client（FileZilla、WinSCP）同時支援三種協定。如果伺服器有 SSH，用 SFTP 比 FTP 安全且功能更多。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>FTP 操作的三個限制在接手維運時要意識到：第一，非原子操作——檔案逐一上傳，上傳過程中伺服器上同時存在新舊版本的混合狀態。第二，不支援指令執行——只能傳檔案、不能跑腳本或重啟服務。第三，沒有版本控制——上傳覆蓋就是覆蓋，沒有 diff、沒有 rollback。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>用 FTP 部署時要建立的紀律：本地先 Git commit 再上傳（Git 提供版本控制、FTP 只負責傳輸）；上傳前用目錄比較確認差異；關鍵檔案（&lt;code>index.php&lt;/code>、&lt;code>.htaccess&lt;/code>）上傳前先從 server 下載一份備份。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ssh/" data-link-title="SSH" data-link-desc="Secure Shell — 加密的遠端 shell 連線，有 SSH 等於有 CLI 工具鏈，沒有就只能靠 FTP 和 web 面板">SSH&lt;/a> — 有 SSH 時用 SFTP 或 SCP 替代 FTP&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/filezilla/" data-link-title="FileZilla" data-link-desc="跨平台的 FTP/SFTP client，提供目錄同步瀏覽和檔案比較功能">FileZilla&lt;/a> — 最常用的 FTP client&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>FTP（File Transfer Protocol）是把檔案在本地電腦與遠端伺服器之間上傳/下載的協定。操作者透過 FTP client（如 FileZilla）連線到伺服器，看到遠端的目錄結構，用拖放或指令傳輸檔案。</p>
<h2 id="概念位置">概念位置</h2>
<p>FTP 在無 SSH 的環境裡是唯一的檔案管理途徑——程式碼部署靠 FTP 上傳、備份靠 FTP 下載、檔案比對靠 FTP client 的目錄比較功能。它是接手維運模組「無 SSH 環境」路線的核心工具。</p>
<h2 id="ftp-的變體">FTP 的變體</h2>
<table>
  <thead>
      <tr>
          <th>協定</th>
          <th>加密方式</th>
          <th>常見情境</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>FTP</td>
          <td>無加密（明文傳輸）</td>
          <td>老舊主機、內部網路</td>
      </tr>
      <tr>
          <td>FTPS</td>
          <td>FTP + TLS 加密</td>
          <td>支援 SSL 的主機</td>
      </tr>
      <tr>
          <td>SFTP</td>
          <td>走 SSH 通道（完全不同協定）</td>
          <td>有 SSH 存取的伺服器</td>
      </tr>
  </tbody>
</table>
<p>多數 FTP client（FileZilla、WinSCP）同時支援三種協定。如果伺服器有 SSH，用 SFTP 比 FTP 安全且功能更多。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>FTP 操作的三個限制在接手維運時要意識到：第一，非原子操作——檔案逐一上傳，上傳過程中伺服器上同時存在新舊版本的混合狀態。第二，不支援指令執行——只能傳檔案、不能跑腳本或重啟服務。第三，沒有版本控制——上傳覆蓋就是覆蓋，沒有 diff、沒有 rollback。</p>
<h2 id="設計責任">設計責任</h2>
<p>用 FTP 部署時要建立的紀律：本地先 Git commit 再上傳（Git 提供版本控制、FTP 只負責傳輸）；上傳前用目錄比較確認差異；關鍵檔案（<code>index.php</code>、<code>.htaccess</code>）上傳前先從 server 下載一份備份。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ssh/" data-link-title="SSH" data-link-desc="Secure Shell — 加密的遠端 shell 連線，有 SSH 等於有 CLI 工具鏈，沒有就只能靠 FTP 和 web 面板">SSH</a> — 有 SSH 時用 SFTP 或 SCP 替代 FTP</li>
<li><a href="/blog/infra/knowledge-cards/filezilla/" data-link-title="FileZilla" data-link-desc="跨平台的 FTP/SFTP client，提供目錄同步瀏覽和檔案比較功能">FileZilla</a> — 最常用的 FTP client</li>
</ul>
]]></content:encoded></item><item><title>cron</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/cron/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/cron/</guid><description>&lt;p>cron 是 Unix/Linux 系統內建的排程工作管理器，按預定的時間表自動執行指令。一個 cron job 定義「什麼時間跑什麼指令」，系統背景的 cron daemon 負責到時間就執行。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>cron 在接手維運時是容易被忽略的隱藏工作——它不像 web 服務有明顯的入口，但可能負責資料庫備份、快取清除、報表產出、日誌清理等關鍵任務。漏掉一個 cron job 可能讓備份停止、快取永不過期、報表不再更新，而且不會立刻有人發現。&lt;/p>
&lt;h2 id="crontab-格式">crontab 格式&lt;/h2>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl"># 分 時 日 月 週 指令
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">0 3 * * * /usr/bin/php /var/www/backup.php
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">*/5 * * * * /usr/bin/curl -s https://example.com/cron/heartbeat
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">0 0 1 * * /usr/bin/find /tmp -mtime +7 -delete&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>五個時間欄位依序是分鐘（0-59）、小時（0-23）、日（1-31）、月（1-12）、星期幾（0-7，0 和 7 都是星期日）。&lt;code>*&lt;/code> 代表「每一個」，&lt;code>*/5&lt;/code> 代表「每 5 個」。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>接手維運時盤點 cron job：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 當前使用者的 crontab&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">crontab -l
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="c1"># 所有使用者的 crontab（需要 root）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="k">for&lt;/span> user in &lt;span class="k">$(&lt;/span>cut -f1 -d: /etc/passwd&lt;span class="k">)&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> crontab -u &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$user&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> -l 2&amp;gt;/dev/null &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;=== &lt;/span>&lt;span class="nv">$user&lt;/span>&lt;span class="s2"> ===&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="k">done&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="c1"># 系統級 cron&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">cat /etc/crontab
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">ls /etc/cron.d/&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>沒有 SSH 時（cPanel 環境），在 cPanel 的「Cron 工作」頁面查看和匯出。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>cron job 要決定：排程頻率、執行失敗時的通知方式（cron 預設把輸出寄 email，但 email 常沒配好）、日誌記錄（指令的 stdout/stderr 導到 log 檔）。遷移或升級時，cron job 要隨著遷移——忘了搬等於停掉排程但沒人知道。&lt;/p>
&lt;p>雲端替代品：AWS CloudWatch Events / EventBridge、GCP Cloud Scheduler、Azure Logic Apps。這些服務提供 web UI 管理、失敗通知、執行歷史，但需要額外設定。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ssh/" data-link-title="SSH" data-link-desc="Secure Shell — 加密的遠端 shell 連線，有 SSH 等於有 CLI 工具鏈，沒有就只能靠 FTP 和 web 面板">SSH&lt;/a> — 盤點和管理 cron 需要 SSH 存取&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>cron 是 Unix/Linux 系統內建的排程工作管理器，按預定的時間表自動執行指令。一個 cron job 定義「什麼時間跑什麼指令」，系統背景的 cron daemon 負責到時間就執行。</p>
<h2 id="概念位置">概念位置</h2>
<p>cron 在接手維運時是容易被忽略的隱藏工作——它不像 web 服務有明顯的入口，但可能負責資料庫備份、快取清除、報表產出、日誌清理等關鍵任務。漏掉一個 cron job 可能讓備份停止、快取永不過期、報表不再更新，而且不會立刻有人發現。</p>
<h2 id="crontab-格式">crontab 格式</h2>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"># 分 時 日 月 週  指令
</span></span><span class="line"><span class="ln">2</span><span class="cl">0  3  *  *  *    /usr/bin/php /var/www/backup.php
</span></span><span class="line"><span class="ln">3</span><span class="cl">*/5 * *  *  *    /usr/bin/curl -s https://example.com/cron/heartbeat
</span></span><span class="line"><span class="ln">4</span><span class="cl">0  0  1  *  *    /usr/bin/find /tmp -mtime +7 -delete</span></span></code></pre></div><p>五個時間欄位依序是分鐘（0-59）、小時（0-23）、日（1-31）、月（1-12）、星期幾（0-7，0 和 7 都是星期日）。<code>*</code> 代表「每一個」，<code>*/5</code> 代表「每 5 個」。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>接手維運時盤點 cron job：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 當前使用者的 crontab</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">crontab -l
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 所有使用者的 crontab（需要 root）</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">for</span> user in <span class="k">$(</span>cut -f1 -d: /etc/passwd<span class="k">)</span><span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">  crontab -u <span class="s2">&#34;</span><span class="nv">$user</span><span class="s2">&#34;</span> -l 2&gt;/dev/null <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;=== </span><span class="nv">$user</span><span class="s2"> ===&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">done</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 系統級 cron</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">cat /etc/crontab
</span></span><span class="line"><span class="ln">11</span><span class="cl">ls /etc/cron.d/</span></span></code></pre></div><p>沒有 SSH 時（cPanel 環境），在 cPanel 的「Cron 工作」頁面查看和匯出。</p>
<h2 id="設計責任">設計責任</h2>
<p>cron job 要決定：排程頻率、執行失敗時的通知方式（cron 預設把輸出寄 email，但 email 常沒配好）、日誌記錄（指令的 stdout/stderr 導到 log 檔）。遷移或升級時，cron job 要隨著遷移——忘了搬等於停掉排程但沒人知道。</p>
<p>雲端替代品：AWS CloudWatch Events / EventBridge、GCP Cloud Scheduler、Azure Logic Apps。這些服務提供 web UI 管理、失敗通知、執行歷史，但需要額外設定。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ssh/" data-link-title="SSH" data-link-desc="Secure Shell — 加密的遠端 shell 連線，有 SSH 等於有 CLI 工具鏈，沒有就只能靠 FTP 和 web 面板">SSH</a> — 盤點和管理 cron 需要 SSH 存取</li>
</ul>
]]></content:encoded></item><item><title>nginx</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/nginx/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/nginx/</guid><description>&lt;p>nginx 是高效能的 Web Server 和 Reverse Proxy，以非同步事件驅動架構處理大量並發連線。它在全球 web server 市場佔有率與 Apache 並列前二，新部署的伺服器多數選 nginx。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>nginx 在 infra 裡常見的角色有三種：作為 reverse proxy 把請求轉給後端應用（Node.js、PHP-FPM、Python WSGI）、作為靜態檔案伺服器、作為 TLS 終結點處理 HTTPS。ALB 在雲端環境承擔了部分 nginx 的職責（負載平衡、TLS 終結），但 VPS 環境裡 nginx 仍然是標準選擇。&lt;/p>
&lt;h2 id="跟-apache-的關鍵差別">跟 Apache 的關鍵差別&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>面向&lt;/th>
 &lt;th>nginx&lt;/th>
 &lt;th>Apache&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>設定模式&lt;/td>
 &lt;td>集中式（&lt;code>/etc/nginx/&lt;/code> 下的設定檔）&lt;/td>
 &lt;td>支援 .htaccess 分散式設定&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>並發模型&lt;/td>
 &lt;td>事件驅動、非阻塞&lt;/td>
 &lt;td>預設 prefork（每個請求一個 process）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>PHP 整合&lt;/td>
 &lt;td>透過 FastCGI（PHP-FPM）&lt;/td>
 &lt;td>mod_php（直接嵌入）或 FastCGI&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>URL rewrite&lt;/td>
 &lt;td>&lt;code>location&lt;/code> + &lt;code>rewrite&lt;/code> 區塊&lt;/td>
 &lt;td>&lt;code>.htaccess&lt;/code> 的 &lt;code>RewriteRule&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>OS 升級或平台遷移時，如果從 Apache 換成 nginx，所有 &lt;code>.htaccess&lt;/code> 規則要手動轉成 nginx 設定：URL rewrite、目錄保護、PHP 設定覆寫、安全標頭。nginx 沒有 &lt;code>.htaccess&lt;/code> 的等價物——所有設定都在集中的設定檔裡，需要 reload nginx 才能生效（Apache 的 &lt;code>.htaccess&lt;/code> 每次請求都重新讀取）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>nginx 設定要決定：server block（類似 Apache 的 VirtualHost）怎麼組織、upstream 指向哪個 app server、靜態檔案的 root 路徑、TLS 憑證掛在哪裡、access log 和 error log 的路徑。設定改完跑 &lt;code>nginx -t&lt;/code> 驗證語法後再 &lt;code>nginx -s reload&lt;/code>。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/htaccess/" data-link-title=".htaccess" data-link-desc="Apache Web Server 的目錄層級設定檔，控制 URL rewrite、存取權限、PHP 設定覆寫與安全標頭">.htaccess&lt;/a> — Apache 的分散設定，遷移到 nginx 時需要轉換&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a> — 雲端環境裡承擔部分 nginx 職責&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>nginx 是高效能的 Web Server 和 Reverse Proxy，以非同步事件驅動架構處理大量並發連線。它在全球 web server 市場佔有率與 Apache 並列前二，新部署的伺服器多數選 nginx。</p>
<h2 id="概念位置">概念位置</h2>
<p>nginx 在 infra 裡常見的角色有三種：作為 reverse proxy 把請求轉給後端應用（Node.js、PHP-FPM、Python WSGI）、作為靜態檔案伺服器、作為 TLS 終結點處理 HTTPS。ALB 在雲端環境承擔了部分 nginx 的職責（負載平衡、TLS 終結），但 VPS 環境裡 nginx 仍然是標準選擇。</p>
<h2 id="跟-apache-的關鍵差別">跟 Apache 的關鍵差別</h2>
<table>
  <thead>
      <tr>
          <th>面向</th>
          <th>nginx</th>
          <th>Apache</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>設定模式</td>
          <td>集中式（<code>/etc/nginx/</code> 下的設定檔）</td>
          <td>支援 .htaccess 分散式設定</td>
      </tr>
      <tr>
          <td>並發模型</td>
          <td>事件驅動、非阻塞</td>
          <td>預設 prefork（每個請求一個 process）</td>
      </tr>
      <tr>
          <td>PHP 整合</td>
          <td>透過 FastCGI（PHP-FPM）</td>
          <td>mod_php（直接嵌入）或 FastCGI</td>
      </tr>
      <tr>
          <td>URL rewrite</td>
          <td><code>location</code> + <code>rewrite</code> 區塊</td>
          <td><code>.htaccess</code> 的 <code>RewriteRule</code></td>
      </tr>
  </tbody>
</table>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>OS 升級或平台遷移時，如果從 Apache 換成 nginx，所有 <code>.htaccess</code> 規則要手動轉成 nginx 設定：URL rewrite、目錄保護、PHP 設定覆寫、安全標頭。nginx 沒有 <code>.htaccess</code> 的等價物——所有設定都在集中的設定檔裡，需要 reload nginx 才能生效（Apache 的 <code>.htaccess</code> 每次請求都重新讀取）。</p>
<h2 id="設計責任">設計責任</h2>
<p>nginx 設定要決定：server block（類似 Apache 的 VirtualHost）怎麼組織、upstream 指向哪個 app server、靜態檔案的 root 路徑、TLS 憑證掛在哪裡、access log 和 error log 的路徑。設定改完跑 <code>nginx -t</code> 驗證語法後再 <code>nginx -s reload</code>。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/htaccess/" data-link-title=".htaccess" data-link-desc="Apache Web Server 的目錄層級設定檔，控制 URL rewrite、存取權限、PHP 設定覆寫與安全標頭">.htaccess</a> — Apache 的分散設定，遷移到 nginx 時需要轉換</li>
<li><a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a> — 雲端環境裡承擔部分 nginx 職責</li>
</ul>
]]></content:encoded></item><item><title>MySQL</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/mysql/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/mysql/</guid><description>&lt;p>MySQL 是最廣泛使用的開源關聯式資料庫，多數 PHP 應用、WordPress、以及大量 web 服務的資料層都跑在 MySQL 上。MariaDB 是 MySQL 被 Oracle 收購後社群分支出來的相容實作，多數 Linux 發行版已經把預設的 mysql 套件指向 MariaDB。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>MySQL 在 infra 裡是典型的 stateful 資源——資料不可重建、備份和刪除保護是 day-1 需求。接手維運時，MySQL 的版本、備份設定、認證方式是第一批要確認的項目。雲端環境裡 MySQL 常以 RDS 形式運行（受管服務、代管備份與 failover）。&lt;/p>
&lt;h2 id="大版本升級的關鍵差異">大版本升級的關鍵差異&lt;/h2>
&lt;p>MySQL 5.7 → 8.0 的 breaking change 在接手和升級情境裡經常遇到：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>變更項&lt;/th>
 &lt;th>5.7 行為&lt;/th>
 &lt;th>8.0 行為&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>預設認證方式&lt;/td>
 &lt;td>&lt;code>mysql_native_password&lt;/code>&lt;/td>
 &lt;td>&lt;code>caching_sha2_password&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>GROUP BY&lt;/code> 隱式排序&lt;/td>
 &lt;td>有（按 group 欄位排）&lt;/td>
 &lt;td>無（需要明確 &lt;code>ORDER BY&lt;/code>）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>預設字元集&lt;/td>
 &lt;td>&lt;code>utf8&lt;/code>（3 byte）&lt;/td>
 &lt;td>&lt;code>utf8mb4&lt;/code>（4 byte、支援 emoji）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>GRANT&lt;/code> 同時建使用者&lt;/td>
 &lt;td>允許&lt;/td>
 &lt;td>必須先 &lt;code>CREATE USER&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>接手維運時的確認清單：&lt;code>SELECT VERSION();&lt;/code> 查版本、&lt;code>SHOW DATABASES;&lt;/code> 看有哪些資料庫、&lt;code>SHOW VARIABLES LIKE 'character_set%';&lt;/code> 確認字元集、&lt;code>SHOW VARIABLES LIKE 'max_connections';&lt;/code> 看連線上限。&lt;/p>
&lt;h2 id="cli-工具">CLI 工具&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>工具&lt;/th>
 &lt;th>功能&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>mysql&lt;/code>&lt;/td>
 &lt;td>互動式 SQL 查詢&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>mysqldump&lt;/code>&lt;/td>
 &lt;td>匯出資料庫為 SQL 文字檔&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>mysqlcheck&lt;/code>&lt;/td>
 &lt;td>檢查、修復、優化資料表&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>mysqlimport&lt;/code>&lt;/td>
 &lt;td>匯入 CSV / TSV 資料&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;code>mysqldump&lt;/code> 是備份的核心工具——一行指令把整個資料庫匯出成可還原的 SQL。phpMyAdmin 的匯出功能底層也是類似的邏輯，但受 web server timeout 限制，大資料庫更適合用 CLI。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>MySQL 的 infra 設計要決定：備份頻率和保留天數（RDS 預設 7 天自動備份）、是否開 multi-AZ（failover 保護）、連線池設定（RDS Proxy 或應用層 pool）、慢查詢日誌是否開啟。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/rds/" data-link-title="RDS" data-link-desc="AWS 的受管關聯式資料庫服務，代管備份、更新與 failover，讓使用者專注在 schema 和查詢">RDS&lt;/a> — AWS 的受管 MySQL 服務&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin&lt;/a> — Web 介面的 MySQL 管理工具&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>MySQL 是最廣泛使用的開源關聯式資料庫，多數 PHP 應用、WordPress、以及大量 web 服務的資料層都跑在 MySQL 上。MariaDB 是 MySQL 被 Oracle 收購後社群分支出來的相容實作，多數 Linux 發行版已經把預設的 mysql 套件指向 MariaDB。</p>
<h2 id="概念位置">概念位置</h2>
<p>MySQL 在 infra 裡是典型的 stateful 資源——資料不可重建、備份和刪除保護是 day-1 需求。接手維運時，MySQL 的版本、備份設定、認證方式是第一批要確認的項目。雲端環境裡 MySQL 常以 RDS 形式運行（受管服務、代管備份與 failover）。</p>
<h2 id="大版本升級的關鍵差異">大版本升級的關鍵差異</h2>
<p>MySQL 5.7 → 8.0 的 breaking change 在接手和升級情境裡經常遇到：</p>
<table>
  <thead>
      <tr>
          <th>變更項</th>
          <th>5.7 行為</th>
          <th>8.0 行為</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>預設認證方式</td>
          <td><code>mysql_native_password</code></td>
          <td><code>caching_sha2_password</code></td>
      </tr>
      <tr>
          <td><code>GROUP BY</code> 隱式排序</td>
          <td>有（按 group 欄位排）</td>
          <td>無（需要明確 <code>ORDER BY</code>）</td>
      </tr>
      <tr>
          <td>預設字元集</td>
          <td><code>utf8</code>（3 byte）</td>
          <td><code>utf8mb4</code>（4 byte、支援 emoji）</td>
      </tr>
      <tr>
          <td><code>GRANT</code> 同時建使用者</td>
          <td>允許</td>
          <td>必須先 <code>CREATE USER</code></td>
      </tr>
  </tbody>
</table>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>接手維運時的確認清單：<code>SELECT VERSION();</code> 查版本、<code>SHOW DATABASES;</code> 看有哪些資料庫、<code>SHOW VARIABLES LIKE 'character_set%';</code> 確認字元集、<code>SHOW VARIABLES LIKE 'max_connections';</code> 看連線上限。</p>
<h2 id="cli-工具">CLI 工具</h2>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>功能</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>mysql</code></td>
          <td>互動式 SQL 查詢</td>
      </tr>
      <tr>
          <td><code>mysqldump</code></td>
          <td>匯出資料庫為 SQL 文字檔</td>
      </tr>
      <tr>
          <td><code>mysqlcheck</code></td>
          <td>檢查、修復、優化資料表</td>
      </tr>
      <tr>
          <td><code>mysqlimport</code></td>
          <td>匯入 CSV / TSV 資料</td>
      </tr>
  </tbody>
</table>
<p><code>mysqldump</code> 是備份的核心工具——一行指令把整個資料庫匯出成可還原的 SQL。phpMyAdmin 的匯出功能底層也是類似的邏輯，但受 web server timeout 限制，大資料庫更適合用 CLI。</p>
<h2 id="設計責任">設計責任</h2>
<p>MySQL 的 infra 設計要決定：備份頻率和保留天數（RDS 預設 7 天自動備份）、是否開 multi-AZ（failover 保護）、連線池設定（RDS Proxy 或應用層 pool）、慢查詢日誌是否開啟。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/rds/" data-link-title="RDS" data-link-desc="AWS 的受管關聯式資料庫服務，代管備份、更新與 failover，讓使用者專注在 schema 和查詢">RDS</a> — AWS 的受管 MySQL 服務</li>
<li><a href="/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin</a> — Web 介面的 MySQL 管理工具</li>
</ul>
]]></content:encoded></item><item><title>RDS</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/rds/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/rds/</guid><description>&lt;p>RDS（Relational Database Service）是 AWS 提供的受管關聯式資料庫服務。它在 EC2 instance 上跑資料庫引擎（MySQL、PostgreSQL、MariaDB、Oracle、SQL Server），但把作業系統更新、自動備份、跨可用區 failover、磁碟擴容這些運維工作交給 AWS 代管。使用者操作的是資料庫層級的設定（schema、query、parameter group），不需要 SSH 進機器管 OS。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>RDS 是 infra 系列中 stateful 資源的代表。它持有不可重建的資料，所以它的 IaC 描述、備份策略、刪除保護、變更審查都比 stateless 資源（如 EC2 web server）嚴格。模組五（核心服務）和接手維運模組的資料庫相關段落都以 RDS 為主要範例。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 RDS 的情境包括：接手一個已經在跑的 production 資料庫、評估要不要從自建 MySQL 遷移到 RDS、設定資料庫的備份和高可用、或在 IaC 裡描述資料庫資源。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 RDS 時要決定的關鍵設定：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>設定&lt;/th>
 &lt;th>決定什麼&lt;/th>
 &lt;th>影響&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>instance class&lt;/td>
 &lt;td>CPU / 記憶體規格&lt;/td>
 &lt;td>效能與成本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>multi-AZ&lt;/td>
 &lt;td>是否跨可用區部署 standby&lt;/td>
 &lt;td>可用性（failover 分鐘級）vs 成本（約 2 倍）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>backup retention&lt;/td>
 &lt;td>自動備份保留天數（1-35）&lt;/td>
 &lt;td>可回溯的時間窗口&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>deletion protection&lt;/td>
 &lt;td>是否允許刪除&lt;/td>
 &lt;td>防誤刪（production 必開）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>parameter group&lt;/td>
 &lt;td>資料庫引擎參數（max_connections 等）&lt;/td>
 &lt;td>效能調校&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>engine version&lt;/td>
 &lt;td>資料庫版本&lt;/td>
 &lt;td>功能與相容性&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>跟自建 MySQL on EC2 的取捨：RDS 省去 OS 層運維，但 parameter group 和 option group 的可調整範圍比直接操作 my.cnf 窄。需要完全控制 OS 層（如自訂 plugin、特殊檔案系統）時，自建較合理。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/mysql/" data-link-title="MySQL" data-link-desc="最廣泛使用的開源關聯式資料庫。MariaDB 是其社群分支。大版本升級（5.7→8.0）有認證方式和查詢行為的 breaking change">MySQL&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/deletion-protection/" data-link-title="Deletion Protection" data-link-desc="雲端平台提供的防誤刪機制，開啟後刪除操作需要先顯式關閉保護才能執行">Deletion Protection&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>RDS（Relational Database Service）是 AWS 提供的受管關聯式資料庫服務。它在 EC2 instance 上跑資料庫引擎（MySQL、PostgreSQL、MariaDB、Oracle、SQL Server），但把作業系統更新、自動備份、跨可用區 failover、磁碟擴容這些運維工作交給 AWS 代管。使用者操作的是資料庫層級的設定（schema、query、parameter group），不需要 SSH 進機器管 OS。</p>
<h2 id="概念位置">概念位置</h2>
<p>RDS 是 infra 系列中 stateful 資源的代表。它持有不可重建的資料，所以它的 IaC 描述、備份策略、刪除保護、變更審查都比 stateless 資源（如 EC2 web server）嚴格。模組五（核心服務）和接手維運模組的資料庫相關段落都以 RDS 為主要範例。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 RDS 的情境包括：接手一個已經在跑的 production 資料庫、評估要不要從自建 MySQL 遷移到 RDS、設定資料庫的備份和高可用、或在 IaC 裡描述資料庫資源。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 RDS 時要決定的關鍵設定：</p>
<table>
  <thead>
      <tr>
          <th>設定</th>
          <th>決定什麼</th>
          <th>影響</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>instance class</td>
          <td>CPU / 記憶體規格</td>
          <td>效能與成本</td>
      </tr>
      <tr>
          <td>multi-AZ</td>
          <td>是否跨可用區部署 standby</td>
          <td>可用性（failover 分鐘級）vs 成本（約 2 倍）</td>
      </tr>
      <tr>
          <td>backup retention</td>
          <td>自動備份保留天數（1-35）</td>
          <td>可回溯的時間窗口</td>
      </tr>
      <tr>
          <td>deletion protection</td>
          <td>是否允許刪除</td>
          <td>防誤刪（production 必開）</td>
      </tr>
      <tr>
          <td>parameter group</td>
          <td>資料庫引擎參數（max_connections 等）</td>
          <td>效能調校</td>
      </tr>
      <tr>
          <td>engine version</td>
          <td>資料庫版本</td>
          <td>功能與相容性</td>
      </tr>
  </tbody>
</table>
<p>跟自建 MySQL on EC2 的取捨：RDS 省去 OS 層運維，但 parameter group 和 option group 的可調整範圍比直接操作 my.cnf 窄。需要完全控制 OS 層（如自訂 plugin、特殊檔案系統）時，自建較合理。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/mysql/" data-link-title="MySQL" data-link-desc="最廣泛使用的開源關聯式資料庫。MariaDB 是其社群分支。大版本升級（5.7→8.0）有認證方式和查詢行為的 breaking change">MySQL</a></li>
<li><a href="/blog/infra/knowledge-cards/deletion-protection/" data-link-title="Deletion Protection" data-link-desc="雲端平台提供的防誤刪機制，開啟後刪除操作需要先顯式關閉保護才能執行">Deletion Protection</a></li>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a></li>
</ul>
]]></content:encoded></item><item><title>S3</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/s3/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/s3/</guid><description>&lt;p>S3（Simple Storage Service）是 AWS 的物件儲存服務。每個檔案（object）放在一個 bucket 裡、用 key（路徑）定址。S3 的持久性設計為 99.999999999%（11 個 9），資料自動跨多個可用區複製，不需要手動備份 S3 本身——要保護的是「物件被覆寫或刪除」的風險，而非「S3 服務掛掉」的風險。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>S3 在 infra 系列裡有三個角色：Terraform state 的存放處（remote state backend）、應用程式的靜態檔案儲存（上傳內容、備份歸檔）、以及 log 的長期保存目的地。模組一（state backend）、模組五（storage）、模組八（治理）都涉及 S3。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 S3 的情境包括：設定 Terraform 的 remote state backend、管理使用者上傳的檔案、設計備份歸檔策略、或評估儲存成本。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 S3 時要決定的關鍵設定：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>設定&lt;/th>
 &lt;th>決定什麼&lt;/th>
 &lt;th>影響&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>versioning&lt;/td>
 &lt;td>是否保留物件的歷史版本&lt;/td>
 &lt;td>覆寫或刪除後能回溯（state bucket 必開）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>encryption&lt;/td>
 &lt;td>靜態加密方式（SSE-S3 / SSE-KMS）&lt;/td>
 &lt;td>合規與金鑰管理&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>public access block&lt;/td>
 &lt;td>是否封鎖公開存取&lt;/td>
 &lt;td>安全（預設全封鎖）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>lifecycle rules&lt;/td>
 &lt;td>自動移到低成本儲存類或過期刪除&lt;/td>
 &lt;td>成本控制（如 30 天後移到 Glacier）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>bucket policy&lt;/td>
 &lt;td>跨帳號或跨服務的存取規則&lt;/td>
 &lt;td>權限邊界&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>versioning 開啟後，刪除物件只是加一個 delete marker、實際資料還在。要真正刪除需要刪除 delete marker 和所有歷史版本。這是保護 state 檔的關鍵機制——誤寫 state 後可以回捲到上一個版本。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/remote-state-backend/" data-link-title="Remote State Backend" data-link-desc="把 Terraform state 從本地搬到團隊共享儲存的機制，同時滿足持久保存、並行鎖與敏感值保護">Remote State Backend&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/deletion-protection/" data-link-title="Deletion Protection" data-link-desc="雲端平台提供的防誤刪機制，開啟後刪除操作需要先顯式關閉保護才能執行">Deletion Protection&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>S3（Simple Storage Service）是 AWS 的物件儲存服務。每個檔案（object）放在一個 bucket 裡、用 key（路徑）定址。S3 的持久性設計為 99.999999999%（11 個 9），資料自動跨多個可用區複製，不需要手動備份 S3 本身——要保護的是「物件被覆寫或刪除」的風險，而非「S3 服務掛掉」的風險。</p>
<h2 id="概念位置">概念位置</h2>
<p>S3 在 infra 系列裡有三個角色：Terraform state 的存放處（remote state backend）、應用程式的靜態檔案儲存（上傳內容、備份歸檔）、以及 log 的長期保存目的地。模組一（state backend）、模組五（storage）、模組八（治理）都涉及 S3。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 S3 的情境包括：設定 Terraform 的 remote state backend、管理使用者上傳的檔案、設計備份歸檔策略、或評估儲存成本。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 S3 時要決定的關鍵設定：</p>
<table>
  <thead>
      <tr>
          <th>設定</th>
          <th>決定什麼</th>
          <th>影響</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>versioning</td>
          <td>是否保留物件的歷史版本</td>
          <td>覆寫或刪除後能回溯（state bucket 必開）</td>
      </tr>
      <tr>
          <td>encryption</td>
          <td>靜態加密方式（SSE-S3 / SSE-KMS）</td>
          <td>合規與金鑰管理</td>
      </tr>
      <tr>
          <td>public access block</td>
          <td>是否封鎖公開存取</td>
          <td>安全（預設全封鎖）</td>
      </tr>
      <tr>
          <td>lifecycle rules</td>
          <td>自動移到低成本儲存類或過期刪除</td>
          <td>成本控制（如 30 天後移到 Glacier）</td>
      </tr>
      <tr>
          <td>bucket policy</td>
          <td>跨帳號或跨服務的存取規則</td>
          <td>權限邊界</td>
      </tr>
  </tbody>
</table>
<p>versioning 開啟後，刪除物件只是加一個 delete marker、實際資料還在。要真正刪除需要刪除 delete marker 和所有歷史版本。這是保護 state 檔的關鍵機制——誤寫 state 後可以回捲到上一個版本。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/remote-state-backend/" data-link-title="Remote State Backend" data-link-desc="把 Terraform state 從本地搬到團隊共享儲存的機制，同時滿足持久保存、並行鎖與敏感值保護">Remote State Backend</a></li>
<li><a href="/blog/infra/knowledge-cards/deletion-protection/" data-link-title="Deletion Protection" data-link-desc="雲端平台提供的防誤刪機制，開啟後刪除操作需要先顯式關閉保護才能執行">Deletion Protection</a></li>
</ul>
]]></content:encoded></item><item><title>EC2</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ec2/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ec2/</guid><description>&lt;p>EC2（Elastic Compute Cloud）是 AWS 提供的虛擬機器服務。每一台 EC2 instance 是一台完整的虛擬伺服器——有自己的 OS、CPU、記憶體、磁碟和網路介面。使用者可以 SSH 進去、安裝軟體、跑應用程式，跟操作一台實體伺服器的體驗相似。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>EC2 是 infra 系列中「運算」面向的基礎單位。容器服務（ECS、EKS）底層也跑在 EC2 上（除非用 Fargate）。模組五（核心服務）的運算段落、接手維運（雲端篇）的 VM 快照、升級模組的 OS 遷移都以 EC2 為操作對象。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 EC2 的情境包括：接手一個跑在 VM 上的應用程式、評估容器化 vs VM 部署、設定 auto-scaling、或建立 AMI 快照作為備份。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>一台 EC2 instance 由五個組件構成：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>組件&lt;/th>
 &lt;th>角色&lt;/th>
 &lt;th>選型判準&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>AMI&lt;/td>
 &lt;td>作業系統映像（Ubuntu、Amazon Linux 等）&lt;/td>
 &lt;td>OS 偏好、軟體預裝需求&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Instance type&lt;/td>
 &lt;td>CPU / 記憶體規格（t3.micro、m6i.large 等）&lt;/td>
 &lt;td>工作負載的 CPU 和記憶體需求&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>EBS&lt;/td>
 &lt;td>持久化磁碟&lt;/td>
 &lt;td>容量、IOPS、是否需要加密&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Security group&lt;/td>
 &lt;td>網路防火牆規則&lt;/td>
 &lt;td>哪些 port 開放、來源限制&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>IAM role&lt;/td>
 &lt;td>instance 的雲端權限&lt;/td>
 &lt;td>需要存取哪些 AWS 服務&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>跟容器（ECS / EKS）的差別：EC2 管整台 VM（含 OS 更新、安全性修補、磁碟管理），容器只管應用程式及其依賴。EC2 的運維負擔較高、但控制粒度也較高。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ami/" data-link-title="AMI" data-link-desc="EC2 instance 的作業系統映像快照，包含 OS、軟體、設定與磁碟內容，從 AMI 開出的 instance 跟原始狀態一樣">AMI&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>EC2（Elastic Compute Cloud）是 AWS 提供的虛擬機器服務。每一台 EC2 instance 是一台完整的虛擬伺服器——有自己的 OS、CPU、記憶體、磁碟和網路介面。使用者可以 SSH 進去、安裝軟體、跑應用程式，跟操作一台實體伺服器的體驗相似。</p>
<h2 id="概念位置">概念位置</h2>
<p>EC2 是 infra 系列中「運算」面向的基礎單位。容器服務（ECS、EKS）底層也跑在 EC2 上（除非用 Fargate）。模組五（核心服務）的運算段落、接手維運（雲端篇）的 VM 快照、升級模組的 OS 遷移都以 EC2 為操作對象。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 EC2 的情境包括：接手一個跑在 VM 上的應用程式、評估容器化 vs VM 部署、設定 auto-scaling、或建立 AMI 快照作為備份。</p>
<h2 id="設計責任">設計責任</h2>
<p>一台 EC2 instance 由五個組件構成：</p>
<table>
  <thead>
      <tr>
          <th>組件</th>
          <th>角色</th>
          <th>選型判準</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>AMI</td>
          <td>作業系統映像（Ubuntu、Amazon Linux 等）</td>
          <td>OS 偏好、軟體預裝需求</td>
      </tr>
      <tr>
          <td>Instance type</td>
          <td>CPU / 記憶體規格（t3.micro、m6i.large 等）</td>
          <td>工作負載的 CPU 和記憶體需求</td>
      </tr>
      <tr>
          <td>EBS</td>
          <td>持久化磁碟</td>
          <td>容量、IOPS、是否需要加密</td>
      </tr>
      <tr>
          <td>Security group</td>
          <td>網路防火牆規則</td>
          <td>哪些 port 開放、來源限制</td>
      </tr>
      <tr>
          <td>IAM role</td>
          <td>instance 的雲端權限</td>
          <td>需要存取哪些 AWS 服務</td>
      </tr>
  </tbody>
</table>
<p>跟容器（ECS / EKS）的差別：EC2 管整台 VM（含 OS 更新、安全性修補、磁碟管理），容器只管應用程式及其依賴。EC2 的運維負擔較高、但控制粒度也較高。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ami/" data-link-title="AMI" data-link-desc="EC2 instance 的作業系統映像快照，包含 OS、軟體、設定與磁碟內容，從 AMI 開出的 instance 跟原始狀態一樣">AMI</a></li>
<li><a href="/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS</a></li>
<li><a href="/blog/infra/knowledge-cards/subnet/" data-link-title="Subnet（子網路）" data-link-desc="VPC 內按可用區與暴露程度切出的子網段，決定資源有沒有一條通往網際網路的路徑">Subnet</a></li>
<li><a href="/blog/infra/knowledge-cards/security-group/" data-link-title="Security Group" data-link-desc="掛在資源網卡層級的有狀態防火牆，逐埠決定哪些來源能連進這個資源">Security Group</a></li>
</ul>
]]></content:encoded></item><item><title>EBS</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ebs/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ebs/</guid><description>&lt;p>EBS（Elastic Block Store）是 AWS 提供的區塊儲存服務——可以把它理解為掛在 EC2 instance 上的虛擬硬碟。EBS volume 跟 EC2 instance 的生命週期獨立：instance 停止或終止時，EBS volume 上的資料不會消失（除非明確設定 &lt;code>DeleteOnTermination&lt;/code>）。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>EBS 是 infra 系列中儲存面向的底層組件。RDS 的資料實際存在 EBS 上（由 AWS 代管）、EC2 的根磁碟和附加磁碟都是 EBS volume。接手維運時對 VM 做快照（AMI），背後就是在對 EBS volume 做 snapshot。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 EBS 的情境包括：EC2 instance 的磁碟快滿了需要擴容、要對 VM 做快照備份、評估磁碟效能（IOPS）是否足夠、或清理不再掛載的孤立 volume（殭屍 volume 持續計費）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>設定&lt;/th>
 &lt;th>決定什麼&lt;/th>
 &lt;th>影響&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Volume type&lt;/td>
 &lt;td>gp3（通用）/ io2（高 IOPS）/ st1（高吞吐）&lt;/td>
 &lt;td>效能與成本&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Size&lt;/td>
 &lt;td>磁碟容量（GB）&lt;/td>
 &lt;td>線上擴容可行、但縮小不行&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Encryption&lt;/td>
 &lt;td>是否加密&lt;/td>
 &lt;td>合規（建立後不可更改，要加密只能建新的複製過去）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Snapshot&lt;/td>
 &lt;td>快照備份&lt;/td>
 &lt;td>EBS snapshot 是增量的（只存變更的區塊）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>DeleteOnTermination&lt;/td>
 &lt;td>instance 終止時是否跟著刪除&lt;/td>
 &lt;td>根磁碟預設 true、附加磁碟預設 false&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>跟 instance store 的差別：instance store 是 EC2 實體主機上的臨時磁碟，效能高但 instance 停止資料就消失。EBS 是持久化儲存，instance 停止資料仍在。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ec2/" data-link-title="EC2" data-link-desc="AWS 的虛擬機器服務，提供可隨時啟停的運算實例，組成包含 AMI、instance type、EBS、security group 與 IAM role">EC2&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/deletion-protection/" data-link-title="Deletion Protection" data-link-desc="雲端平台提供的防誤刪機制，開啟後刪除操作需要先顯式關閉保護才能執行">Deletion Protection&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>EBS（Elastic Block Store）是 AWS 提供的區塊儲存服務——可以把它理解為掛在 EC2 instance 上的虛擬硬碟。EBS volume 跟 EC2 instance 的生命週期獨立：instance 停止或終止時，EBS volume 上的資料不會消失（除非明確設定 <code>DeleteOnTermination</code>）。</p>
<h2 id="概念位置">概念位置</h2>
<p>EBS 是 infra 系列中儲存面向的底層組件。RDS 的資料實際存在 EBS 上（由 AWS 代管）、EC2 的根磁碟和附加磁碟都是 EBS volume。接手維運時對 VM 做快照（AMI），背後就是在對 EBS volume 做 snapshot。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 EBS 的情境包括：EC2 instance 的磁碟快滿了需要擴容、要對 VM 做快照備份、評估磁碟效能（IOPS）是否足夠、或清理不再掛載的孤立 volume（殭屍 volume 持續計費）。</p>
<h2 id="設計責任">設計責任</h2>
<table>
  <thead>
      <tr>
          <th>設定</th>
          <th>決定什麼</th>
          <th>影響</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Volume type</td>
          <td>gp3（通用）/ io2（高 IOPS）/ st1（高吞吐）</td>
          <td>效能與成本</td>
      </tr>
      <tr>
          <td>Size</td>
          <td>磁碟容量（GB）</td>
          <td>線上擴容可行、但縮小不行</td>
      </tr>
      <tr>
          <td>Encryption</td>
          <td>是否加密</td>
          <td>合規（建立後不可更改，要加密只能建新的複製過去）</td>
      </tr>
      <tr>
          <td>Snapshot</td>
          <td>快照備份</td>
          <td>EBS snapshot 是增量的（只存變更的區塊）</td>
      </tr>
      <tr>
          <td>DeleteOnTermination</td>
          <td>instance 終止時是否跟著刪除</td>
          <td>根磁碟預設 true、附加磁碟預設 false</td>
      </tr>
  </tbody>
</table>
<p>跟 instance store 的差別：instance store 是 EC2 實體主機上的臨時磁碟，效能高但 instance 停止資料就消失。EBS 是持久化儲存，instance 停止資料仍在。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ec2/" data-link-title="EC2" data-link-desc="AWS 的虛擬機器服務，提供可隨時啟停的運算實例，組成包含 AMI、instance type、EBS、security group 與 IAM role">EC2</a></li>
<li><a href="/blog/infra/knowledge-cards/deletion-protection/" data-link-title="Deletion Protection" data-link-desc="雲端平台提供的防誤刪機制，開啟後刪除操作需要先顯式關閉保護才能執行">Deletion Protection</a></li>
</ul>
]]></content:encoded></item><item><title>HCL</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/hcl/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/hcl/</guid><description>&lt;p>HCL（HashiCorp Configuration Language）是 Terraform 和 OpenTofu 使用的設定語言。它用宣告式的 resource block 描述「環境應該長什麼樣」，由工具負責比對現況與描述、算出差異再套用。寫 HCL 的人描述目標狀態，不描述達到目標的步驟。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>HCL 是 infra 系列中 IaC 程式碼的語言層。IaC 卡講的是「用程式碼管理基礎設施」的概念，HCL 是這個概念落地時最常用的語言。模組一到八的所有 HCL 範例都用這個語言寫成。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 HCL 的情境包括：第一次打開一份 &lt;code>.tf&lt;/code> 檔案、要讀懂 Terraform 的 plan 輸出、要修改或新增一個 resource 定義、或要 review 別人的 infra PR。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>HCL 的基本結構：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket&amp;#34; &amp;#34;example&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="n"> bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-bucket&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="n"> tags&lt;/span> &lt;span class="o">=&lt;/span>&lt;span class="n"> { env&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;prod&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">}&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;code>resource&lt;/code>：宣告一個雲端資源&lt;/li>
&lt;li>&lt;code>&amp;quot;aws_s3_bucket&amp;quot;&lt;/code>：資源類型（由 provider 決定）&lt;/li>
&lt;li>&lt;code>&amp;quot;example&amp;quot;&lt;/code>：這個資源在程式碼裡的名稱（用來引用）&lt;/li>
&lt;li>&lt;code>{}&lt;/code>：這個資源的屬性&lt;/li>
&lt;/ul>
&lt;p>跟其他格式的差別：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>格式&lt;/th>
 &lt;th>特性&lt;/th>
 &lt;th>適合場景&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>JSON / YAML&lt;/td>
 &lt;td>純資料格式、沒有邏輯&lt;/td>
 &lt;td>設定值、資料交換&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>HCL&lt;/td>
 &lt;td>支援變數、函式、條件、迴圈&lt;/td>
 &lt;td>基礎設施描述&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>TypeScript / Python&lt;/td>
 &lt;td>通用程式語言、完整邏輯&lt;/td>
 &lt;td>複雜的 infra 抽象（CDK / Pulumi）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>HCL 的定位在 JSON 和通用語言之間——比 JSON 有表達力（能做迴圈和條件）、比通用語言好 review（diff 直觀、不需要在腦中「執行」程式碼才知道結果）。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>HCL（HashiCorp Configuration Language）是 Terraform 和 OpenTofu 使用的設定語言。它用宣告式的 resource block 描述「環境應該長什麼樣」，由工具負責比對現況與描述、算出差異再套用。寫 HCL 的人描述目標狀態，不描述達到目標的步驟。</p>
<h2 id="概念位置">概念位置</h2>
<p>HCL 是 infra 系列中 IaC 程式碼的語言層。IaC 卡講的是「用程式碼管理基礎設施」的概念，HCL 是這個概念落地時最常用的語言。模組一到八的所有 HCL 範例都用這個語言寫成。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 HCL 的情境包括：第一次打開一份 <code>.tf</code> 檔案、要讀懂 Terraform 的 plan 輸出、要修改或新增一個 resource 定義、或要 review 別人的 infra PR。</p>
<h2 id="設計責任">設計責任</h2>
<p>HCL 的基本結構：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-hcl" data-lang="hcl"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">resource</span> <span class="s2">&#34;aws_s3_bucket&#34; &#34;example&#34;</span> {
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">  bucket</span> <span class="o">=</span> <span class="s2">&#34;my-bucket&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="n">  tags</span>   <span class="o">=</span><span class="n"> { env</span> <span class="o">=</span> <span class="s2">&#34;prod&#34;</span> }
</span></span><span class="line"><span class="ln">4</span><span class="cl">}</span></span></code></pre></div><ul>
<li><code>resource</code>：宣告一個雲端資源</li>
<li><code>&quot;aws_s3_bucket&quot;</code>：資源類型（由 provider 決定）</li>
<li><code>&quot;example&quot;</code>：這個資源在程式碼裡的名稱（用來引用）</li>
<li><code>{}</code>：這個資源的屬性</li>
</ul>
<p>跟其他格式的差別：</p>
<table>
  <thead>
      <tr>
          <th>格式</th>
          <th>特性</th>
          <th>適合場景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>JSON / YAML</td>
          <td>純資料格式、沒有邏輯</td>
          <td>設定值、資料交換</td>
      </tr>
      <tr>
          <td>HCL</td>
          <td>支援變數、函式、條件、迴圈</td>
          <td>基礎設施描述</td>
      </tr>
      <tr>
          <td>TypeScript / Python</td>
          <td>通用程式語言、完整邏輯</td>
          <td>複雜的 infra 抽象（CDK / Pulumi）</td>
      </tr>
  </tbody>
</table>
<p>HCL 的定位在 JSON 和通用語言之間——比 JSON 有表達力（能做迴圈和條件）、比通用語言好 review（diff 直觀、不需要在腦中「執行」程式碼才知道結果）。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a></li>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a></li>
</ul>
]]></content:encoded></item><item><title>terraform plan / apply</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/terraform-plan-apply/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/terraform-plan-apply/</guid><description>&lt;p>&lt;code>terraform plan&lt;/code> 和 &lt;code>terraform apply&lt;/code> 是 Terraform 操作基礎設施的兩個核心指令。plan 比對三方（state 檔、雲端現況、HCL 描述）產出差異報告，告訴使用者「如果 apply 會發生什麼」，但不做任何改動。apply 執行 plan 算出的差異，在雲端建立、修改或刪除資源。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>plan/apply 的分離是 IaC 可審查性的基礎。模組七（PR 流程）的核心機制就是「PR 觸發 plan → plan 結果貼回 PR → reviewer 看 plan 再決定要不要 apply」。這個「先看再動」的流程跟手動操作（直接在 Console 改）的根本差別。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 plan/apply 的情境包括：第一次跑 Terraform、review 別人的 infra PR（看 plan 輸出）、排查 drift（plan 在沒有 code 變更的情況下顯示差異）、或決定一次 apply 是否安全。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>plan 輸出的三種動作標記：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>標記&lt;/th>
 &lt;th>意義&lt;/th>
 &lt;th>風險&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>+&lt;/code>&lt;/td>
 &lt;td>新增資源&lt;/td>
 &lt;td>低（新建不影響現有）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>~&lt;/code>&lt;/td>
 &lt;td>修改資源（in-place update）&lt;/td>
 &lt;td>中（看改什麼，改 tag 低風險、改 instance type 可能重啟）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>-/+&lt;/code>&lt;/td>
 &lt;td>先刪後建（forces replacement）&lt;/td>
 &lt;td>高（stateful 資源如 RDS 代表資料遺失）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>-&lt;/code>&lt;/td>
 &lt;td>刪除資源&lt;/td>
 &lt;td>高（不可逆）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>review plan 時最需要警惕的是 &lt;code>-/+&lt;/code>（forces replacement）——看起來只是改一個屬性，但某些屬性的修改會觸發資源重建（例如 RDS 的 &lt;code>identifier&lt;/code> 改名）。&lt;/p>
&lt;p>plan 與 apply 之間可能有時間差。如果 plan 之後、apply 之前有人手動改了雲端資源，apply 時的實際行為可能跟 plan 預期的不同。多數團隊在 apply 階段會重跑一次 plan 並要求結果一致。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p><code>terraform plan</code> 和 <code>terraform apply</code> 是 Terraform 操作基礎設施的兩個核心指令。plan 比對三方（state 檔、雲端現況、HCL 描述）產出差異報告，告訴使用者「如果 apply 會發生什麼」，但不做任何改動。apply 執行 plan 算出的差異，在雲端建立、修改或刪除資源。</p>
<h2 id="概念位置">概念位置</h2>
<p>plan/apply 的分離是 IaC 可審查性的基礎。模組七（PR 流程）的核心機制就是「PR 觸發 plan → plan 結果貼回 PR → reviewer 看 plan 再決定要不要 apply」。這個「先看再動」的流程跟手動操作（直接在 Console 改）的根本差別。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 plan/apply 的情境包括：第一次跑 Terraform、review 別人的 infra PR（看 plan 輸出）、排查 drift（plan 在沒有 code 變更的情況下顯示差異）、或決定一次 apply 是否安全。</p>
<h2 id="設計責任">設計責任</h2>
<p>plan 輸出的三種動作標記：</p>
<table>
  <thead>
      <tr>
          <th>標記</th>
          <th>意義</th>
          <th>風險</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>+</code></td>
          <td>新增資源</td>
          <td>低（新建不影響現有）</td>
      </tr>
      <tr>
          <td><code>~</code></td>
          <td>修改資源（in-place update）</td>
          <td>中（看改什麼，改 tag 低風險、改 instance type 可能重啟）</td>
      </tr>
      <tr>
          <td><code>-/+</code></td>
          <td>先刪後建（forces replacement）</td>
          <td>高（stateful 資源如 RDS 代表資料遺失）</td>
      </tr>
      <tr>
          <td><code>-</code></td>
          <td>刪除資源</td>
          <td>高（不可逆）</td>
      </tr>
  </tbody>
</table>
<p>review plan 時最需要警惕的是 <code>-/+</code>（forces replacement）——看起來只是改一個屬性，但某些屬性的修改會觸發資源重建（例如 RDS 的 <code>identifier</code> 改名）。</p>
<p>plan 與 apply 之間可能有時間差。如果 plan 之後、apply 之前有人手動改了雲端資源，apply 時的實際行為可能跟 plan 預期的不同。多數團隊在 apply 階段會重跑一次 plan 並要求結果一致。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/state/" data-link-title="State（IaC 狀態檔）" data-link-desc="IaC 工具用來記錄每個納管資源在雲端真實樣貌的快照，是比對差異與排定操作順序的依據">State</a></li>
<li><a href="/blog/infra/knowledge-cards/drift/" data-link-title="Drift（設定漂移）" data-link-desc="IaC 的 state 與雲端實際狀態之間的不一致，通常因為有人繞過 IaC 直接在 Console 改設定">Drift</a></li>
<li><a href="/blog/infra/knowledge-cards/iac/" data-link-title="Infrastructure as Code (IaC)" data-link-desc="用程式碼描述基礎設施的最終狀態，由工具負責收斂現實與描述的差異">IaC</a></li>
</ul>
]]></content:encoded></item><item><title>AMI</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/ami/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/ami/</guid><description>&lt;p>AMI（Amazon Machine Image）是 EC2 instance 的完整映像快照。它包含作業系統、已安裝的軟體、設定檔、磁碟內容——從一個 AMI 啟動新的 instance，得到的是跟拍照時完全一樣的環境。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>AMI 在 infra 系列裡有兩個角色。第一個是接手維運時的保險——對 VM 建一個 AMI 等於把整台機器拍下來，做任何改動前都有一個可回退的基線。第二個是環境標準化——把裝好軟體的 instance 做成 AMI（golden image），之後開新機器都從這個 AMI 啟動，確保每台機器的基線一致。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>需要理解 AMI 的情境包括：接手一台不確定裡面裝了什麼的 EC2（先拍 AMI 再動）、要在另一個 region 或帳號複製一台同樣的機器、OS 升級時要保留舊環境作為 rollback、或設計 auto-scaling 的 launch template（需要指定 AMI）。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>操作&lt;/th>
 &lt;th>用途&lt;/th>
 &lt;th>注意事項&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>建立 AMI&lt;/td>
 &lt;td>對現有 instance 拍照&lt;/td>
 &lt;td>&lt;code>--no-reboot&lt;/code> 避免服務中斷，但檔案系統一致性略低&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>從 AMI 啟動 instance&lt;/td>
 &lt;td>複製環境&lt;/td>
 &lt;td>新 instance 有新的 IP、hostname、instance ID&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>跨 region 複製 AMI&lt;/td>
 &lt;td>災難復原或多 region 部署&lt;/td>
 &lt;td>複製是非同步的、完成後才能在目標 region 使用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>共享 AMI&lt;/td>
 &lt;td>跨帳號使用同一個映像&lt;/td>
 &lt;td>需要設定 AMI 的 launch permission&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>AMI 包含 EBS snapshot——AMI 的儲存成本就是底層 EBS snapshot 的成本（按儲存量計費）。不再使用的 AMI 要記得 deregister 並刪除對應的 snapshot，否則持續計費。&lt;/p>
&lt;p>跟 container image 的差別：AMI 是整台 VM 的映像（含 OS、kernel、系統套件），container image 只包含應用程式和它的依賴（共用 host OS 的 kernel）。AMI 以 GB 計（通常 8-50 GB），container image 以 MB 計（通常 50-500 MB）。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ec2/" data-link-title="EC2" data-link-desc="AWS 的虛擬機器服務，提供可隨時啟停的運算實例，組成包含 AMI、instance type、EBS、security group 與 IAM role">EC2&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ebs/" data-link-title="EBS" data-link-desc="掛在 EC2 instance 上的持久化區塊儲存（虛擬磁碟），支援 snapshot 快照備份，跟 instance 獨立生命週期">EBS&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>AMI（Amazon Machine Image）是 EC2 instance 的完整映像快照。它包含作業系統、已安裝的軟體、設定檔、磁碟內容——從一個 AMI 啟動新的 instance，得到的是跟拍照時完全一樣的環境。</p>
<h2 id="概念位置">概念位置</h2>
<p>AMI 在 infra 系列裡有兩個角色。第一個是接手維運時的保險——對 VM 建一個 AMI 等於把整台機器拍下來，做任何改動前都有一個可回退的基線。第二個是環境標準化——把裝好軟體的 instance 做成 AMI（golden image），之後開新機器都從這個 AMI 啟動，確保每台機器的基線一致。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>需要理解 AMI 的情境包括：接手一台不確定裡面裝了什麼的 EC2（先拍 AMI 再動）、要在另一個 region 或帳號複製一台同樣的機器、OS 升級時要保留舊環境作為 rollback、或設計 auto-scaling 的 launch template（需要指定 AMI）。</p>
<h2 id="設計責任">設計責任</h2>
<table>
  <thead>
      <tr>
          <th>操作</th>
          <th>用途</th>
          <th>注意事項</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>建立 AMI</td>
          <td>對現有 instance 拍照</td>
          <td><code>--no-reboot</code> 避免服務中斷，但檔案系統一致性略低</td>
      </tr>
      <tr>
          <td>從 AMI 啟動 instance</td>
          <td>複製環境</td>
          <td>新 instance 有新的 IP、hostname、instance ID</td>
      </tr>
      <tr>
          <td>跨 region 複製 AMI</td>
          <td>災難復原或多 region 部署</td>
          <td>複製是非同步的、完成後才能在目標 region 使用</td>
      </tr>
      <tr>
          <td>共享 AMI</td>
          <td>跨帳號使用同一個映像</td>
          <td>需要設定 AMI 的 launch permission</td>
      </tr>
  </tbody>
</table>
<p>AMI 包含 EBS snapshot——AMI 的儲存成本就是底層 EBS snapshot 的成本（按儲存量計費）。不再使用的 AMI 要記得 deregister 並刪除對應的 snapshot，否則持續計費。</p>
<p>跟 container image 的差別：AMI 是整台 VM 的映像（含 OS、kernel、系統套件），container image 只包含應用程式和它的依賴（共用 host OS 的 kernel）。AMI 以 GB 計（通常 8-50 GB），container image 以 MB 計（通常 50-500 MB）。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ec2/" data-link-title="EC2" data-link-desc="AWS 的虛擬機器服務，提供可隨時啟停的運算實例，組成包含 AMI、instance type、EBS、security group 與 IAM role">EC2</a></li>
<li><a href="/blog/infra/knowledge-cards/ebs/" data-link-title="EBS" data-link-desc="掛在 EC2 instance 上的持久化區塊儲存（虛擬磁碟），支援 snapshot 快照備份，跟 instance 獨立生命週期">EBS</a></li>
</ul>
]]></content:encoded></item><item><title>Composer</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/composer/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/composer/</guid><description>&lt;p>Composer 是 PHP 的套件管理工具，角色等同於 Node.js 的 npm、Python 的 pip、Go 的 go mod。它負責宣告專案需要哪些第三方套件、鎖定每個套件的確切版本、以及把套件安裝到專案目錄裡。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>接手 PHP 專案時，Composer 是判斷「專案依賴了什麼、版本有沒有已知漏洞」的入口。專案根目錄通常有三個 Composer 相關的檔案：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>檔案&lt;/th>
 &lt;th>角色&lt;/th>
 &lt;th>進 Git？&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>composer.json&lt;/code>&lt;/td>
 &lt;td>宣告依賴（套件名稱 + 版本範圍）&lt;/td>
 &lt;td>是&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>composer.lock&lt;/code>&lt;/td>
 &lt;td>鎖定確切版本（含所有 transitive 依賴）&lt;/td>
 &lt;td>是&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>vendor/&lt;/code>&lt;/td>
 &lt;td>安裝的套件目錄&lt;/td>
 &lt;td>否（.gitignore 排除、由 &lt;code>composer install&lt;/code> 重建）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>接手專案時如果根目錄有 &lt;code>composer.json&lt;/code> 但沒有 &lt;code>vendor/&lt;/code>，代表需要先跑 &lt;code>composer install&lt;/code> 才能讓專案運作。如果連 &lt;code>composer.lock&lt;/code> 都沒有，代表套件版本沒有鎖定——每次安裝可能拿到不同版本。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>兩個常用指令的差別：&lt;/p>
&lt;ul>
&lt;li>&lt;code>composer install&lt;/code>：按 &lt;code>composer.lock&lt;/code> 安裝確切版本。用於部署和接手——確保每台機器安裝的版本一致。&lt;/li>
&lt;li>&lt;code>composer update&lt;/code>：重新解析 &lt;code>composer.json&lt;/code> 的版本範圍、更新到最新的符合版本、改寫 &lt;code>composer.lock&lt;/code>。用於主動升級依賴。&lt;/li>
&lt;/ul>
&lt;p>接手時的關鍵操作：&lt;/p>
&lt;ul>
&lt;li>&lt;code>composer audit&lt;/code>：掃描已安裝套件的已知安全漏洞&lt;/li>
&lt;li>&lt;code>composer outdated&lt;/code>：列出可更新的套件及其最新版本&lt;/li>
&lt;/ul>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/dotenv/" data-link-title=".env" data-link-desc="存放環境變數的純文字檔案，把機密值從程式碼分離出來">.env&lt;/a>：Composer 管套件、.env 管設定值，兩者都是 PHP 專案的基礎設施&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/php-ini/" data-link-title="php.ini / .user.ini" data-link-desc="PHP 的執行期設定檔，控制記憶體上限、上傳大小、錯誤報告等 runtime 行為">php.ini / .user.ini&lt;/a>：Composer 需要 PHP CLI 執行，php.ini 的 memory_limit 和 max_execution_time 會影響 Composer 能不能跑完&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Composer 是 PHP 的套件管理工具，角色等同於 Node.js 的 npm、Python 的 pip、Go 的 go mod。它負責宣告專案需要哪些第三方套件、鎖定每個套件的確切版本、以及把套件安裝到專案目錄裡。</p>
<h2 id="概念位置">概念位置</h2>
<p>接手 PHP 專案時，Composer 是判斷「專案依賴了什麼、版本有沒有已知漏洞」的入口。專案根目錄通常有三個 Composer 相關的檔案：</p>
<table>
  <thead>
      <tr>
          <th>檔案</th>
          <th>角色</th>
          <th>進 Git？</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>composer.json</code></td>
          <td>宣告依賴（套件名稱 + 版本範圍）</td>
          <td>是</td>
      </tr>
      <tr>
          <td><code>composer.lock</code></td>
          <td>鎖定確切版本（含所有 transitive 依賴）</td>
          <td>是</td>
      </tr>
      <tr>
          <td><code>vendor/</code></td>
          <td>安裝的套件目錄</td>
          <td>否（.gitignore 排除、由 <code>composer install</code> 重建）</td>
      </tr>
  </tbody>
</table>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>接手專案時如果根目錄有 <code>composer.json</code> 但沒有 <code>vendor/</code>，代表需要先跑 <code>composer install</code> 才能讓專案運作。如果連 <code>composer.lock</code> 都沒有，代表套件版本沒有鎖定——每次安裝可能拿到不同版本。</p>
<h2 id="設計責任">設計責任</h2>
<p>兩個常用指令的差別：</p>
<ul>
<li><code>composer install</code>：按 <code>composer.lock</code> 安裝確切版本。用於部署和接手——確保每台機器安裝的版本一致。</li>
<li><code>composer update</code>：重新解析 <code>composer.json</code> 的版本範圍、更新到最新的符合版本、改寫 <code>composer.lock</code>。用於主動升級依賴。</li>
</ul>
<p>接手時的關鍵操作：</p>
<ul>
<li><code>composer audit</code>：掃描已安裝套件的已知安全漏洞</li>
<li><code>composer outdated</code>：列出可更新的套件及其最新版本</li>
</ul>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/dotenv/" data-link-title=".env" data-link-desc="存放環境變數的純文字檔案，把機密值從程式碼分離出來">.env</a>：Composer 管套件、.env 管設定值，兩者都是 PHP 專案的基礎設施</li>
<li><a href="/blog/infra/knowledge-cards/php-ini/" data-link-title="php.ini / .user.ini" data-link-desc="PHP 的執行期設定檔，控制記憶體上限、上傳大小、錯誤報告等 runtime 行為">php.ini / .user.ini</a>：Composer 需要 PHP CLI 執行，php.ini 的 memory_limit 和 max_execution_time 會影響 Composer 能不能跑完</li>
</ul>
]]></content:encoded></item><item><title>mysqldump</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/mysqldump/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/mysqldump/</guid><description>&lt;p>mysqldump 是 MySQL 和 MariaDB 內建的命令列備份工具，把整個資料庫（或指定的表）匯出成一份包含 CREATE TABLE 和 INSERT 語句的 SQL 純文字檔。還原時把這份檔案餵給 &lt;code>mysql&lt;/code> client 就能重建資料。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>mysqldump 是有 SSH 存取（或 remote MySQL 存取）時的主要備份手段。比 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin&lt;/a> 的匯出更可靠——不受 web server 的 timeout 和記憶體限制影響，可以處理數 GB 的資料庫。沒有 SSH 的環境只能退回 phpMyAdmin 匯出。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>接手時如果 server 上有 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/cron/" data-link-title="cron" data-link-desc="Unix/Linux 的排程工作系統，按時間表自動執行指令。接手維運時要盤點所有 cron job">cron&lt;/a> job 在跑 mysqldump，代表前任有做自動備份——確認輸出的 dump 檔案存在哪、保留幾天、有沒有被驗證過能還原。如果沒有任何 mysqldump cron，代表備份可能只靠 phpMyAdmin 手動匯出或完全沒做。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>常用的 flag 組合：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">mysqldump -u user -p &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="se">&lt;/span> --single-transaction &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="se">&lt;/span> --routines &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="se">&lt;/span> --triggers &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="se">&lt;/span> dbname &amp;gt; dump-&lt;span class="k">$(&lt;/span>date +%Y%m%d&lt;span class="k">)&lt;/span>.sql&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>Flag&lt;/th>
 &lt;th>作用&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>--single-transaction&lt;/code>&lt;/td>
 &lt;td>InnoDB 表不鎖表匯出（用一致性快照），生產備份必備&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>--routines&lt;/code>&lt;/td>
 &lt;td>含 stored procedure 和 function&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>--triggers&lt;/code>&lt;/td>
 &lt;td>含 trigger&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>--quick&lt;/code>&lt;/td>
 &lt;td>逐行讀取、不把整個表載入記憶體，大表必備&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>還原指令：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">mysql -u user -p dbname &amp;lt; dump-20260626.sql&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>mysqldump 產出的是邏輯備份（SQL 語句），還原速度取決於資料量——幾百 MB 以內分鐘級，數 GB 可能要半小時以上。需要更快的備份/還原（物理備份），要用 Percona XtraBackup 或 MySQL Enterprise Backup。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin&lt;/a>：無 SSH 時的替代備份手段&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/cron/" data-link-title="cron" data-link-desc="Unix/Linux 的排程工作系統，按時間表自動執行指令。接手維運時要盤點所有 cron job">cron&lt;/a>：搭配 cron 做定期自動備份&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>mysqldump 是 MySQL 和 MariaDB 內建的命令列備份工具，把整個資料庫（或指定的表）匯出成一份包含 CREATE TABLE 和 INSERT 語句的 SQL 純文字檔。還原時把這份檔案餵給 <code>mysql</code> client 就能重建資料。</p>
<h2 id="概念位置">概念位置</h2>
<p>mysqldump 是有 SSH 存取（或 remote MySQL 存取）時的主要備份手段。比 <a href="/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin</a> 的匯出更可靠——不受 web server 的 timeout 和記憶體限制影響，可以處理數 GB 的資料庫。沒有 SSH 的環境只能退回 phpMyAdmin 匯出。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>接手時如果 server 上有 <a href="/blog/infra/knowledge-cards/cron/" data-link-title="cron" data-link-desc="Unix/Linux 的排程工作系統，按時間表自動執行指令。接手維運時要盤點所有 cron job">cron</a> job 在跑 mysqldump，代表前任有做自動備份——確認輸出的 dump 檔案存在哪、保留幾天、有沒有被驗證過能還原。如果沒有任何 mysqldump cron，代表備份可能只靠 phpMyAdmin 手動匯出或完全沒做。</p>
<h2 id="設計責任">設計責任</h2>
<p>常用的 flag 組合：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mysqldump -u user -p <span class="se">\
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="se"></span>  --single-transaction <span class="se">\
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="se"></span>  --routines <span class="se">\
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="se"></span>  --triggers <span class="se">\
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="se"></span>  dbname &gt; dump-<span class="k">$(</span>date +%Y%m%d<span class="k">)</span>.sql</span></span></code></pre></div><table>
  <thead>
      <tr>
          <th>Flag</th>
          <th>作用</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>--single-transaction</code></td>
          <td>InnoDB 表不鎖表匯出（用一致性快照），生產備份必備</td>
      </tr>
      <tr>
          <td><code>--routines</code></td>
          <td>含 stored procedure 和 function</td>
      </tr>
      <tr>
          <td><code>--triggers</code></td>
          <td>含 trigger</td>
      </tr>
      <tr>
          <td><code>--quick</code></td>
          <td>逐行讀取、不把整個表載入記憶體，大表必備</td>
      </tr>
  </tbody>
</table>
<p>還原指令：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">mysql -u user -p dbname &lt; dump-20260626.sql</span></span></code></pre></div><p>mysqldump 產出的是邏輯備份（SQL 語句），還原速度取決於資料量——幾百 MB 以內分鐘級，數 GB 可能要半小時以上。需要更快的備份/還原（物理備份），要用 Percona XtraBackup 或 MySQL Enterprise Backup。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin</a>：無 SSH 時的替代備份手段</li>
<li><a href="/blog/infra/knowledge-cards/cron/" data-link-title="cron" data-link-desc="Unix/Linux 的排程工作系統，按時間表自動執行指令。接手維運時要盤點所有 cron job">cron</a>：搭配 cron 做定期自動備份</li>
</ul>
]]></content:encoded></item><item><title>Reverse Proxy</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/reverse-proxy/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/reverse-proxy/</guid><description>&lt;p>Reverse proxy 是一個坐在後端服務前面、代替它接收外部請求的中介層。外部 client 連的是 reverse proxy 的位址，reverse proxy 根據規則把請求轉發到實際處理的內部服務，再把回應傳回給 client。Client 不知道（也不需要知道）後面有幾台服務、跑在哪裡。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>nginx 和 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a> 都扮演 reverse proxy 角色。差別在層級：nginx 通常部署在應用層（跟應用伺服器同一台或同一個 VPC 內），ALB 是雲端平台提供的受管服務。兩者的核心功能相同——接收外部流量、轉發到後端、回傳結果。&lt;/p>
&lt;p>跟 forward proxy 的方向相反：forward proxy 代替 client 發送請求（client 在內網、proxy 幫它出去）；reverse proxy 代替 server 接收請求（server 在內網、proxy 幫它面對外部）。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>接手時如果 server 上跑著 nginx 但應用程式用的是 PHP-FPM 或 Node.js，nginx 多半扮演 reverse proxy——它接 HTTP/HTTPS 請求、轉發給後端的 application server。設定檔裡的 &lt;code>proxy_pass&lt;/code>（nginx）或 &lt;code>ProxyPass&lt;/code>（Apache）就是 reverse proxy 的轉發規則。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>reverse proxy 常承擔的功能：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>功能&lt;/th>
 &lt;th>說明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>TLS 終結&lt;/td>
 &lt;td>HTTPS 的加解密在 proxy 層處理，後端服務只收 HTTP&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>負載平衡&lt;/td>
 &lt;td>把請求分配到多台後端（round-robin、least-connection）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>路由分流&lt;/td>
 &lt;td>依 URL path 導到不同後端服務（/api → backend、/ → frontend）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>靜態檔案快取&lt;/td>
 &lt;td>圖片、CSS、JS 由 proxy 直接回應、不轉發到後端&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>安全過濾&lt;/td>
 &lt;td>擋掉異常請求、限制請求速率、加安全標頭&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB&lt;/a>：雲端的受管 reverse proxy + 負載平衡器&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/nginx/" data-link-title="nginx" data-link-desc="高效能 Web Server 與 Reverse Proxy，以集中設定檔取代 Apache 的 .htaccess 分散設定">nginx&lt;/a>：最常見的 reverse proxy 軟體&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Reverse proxy 是一個坐在後端服務前面、代替它接收外部請求的中介層。外部 client 連的是 reverse proxy 的位址，reverse proxy 根據規則把請求轉發到實際處理的內部服務，再把回應傳回給 client。Client 不知道（也不需要知道）後面有幾台服務、跑在哪裡。</p>
<h2 id="概念位置">概念位置</h2>
<p>nginx 和 <a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a> 都扮演 reverse proxy 角色。差別在層級：nginx 通常部署在應用層（跟應用伺服器同一台或同一個 VPC 內），ALB 是雲端平台提供的受管服務。兩者的核心功能相同——接收外部流量、轉發到後端、回傳結果。</p>
<p>跟 forward proxy 的方向相反：forward proxy 代替 client 發送請求（client 在內網、proxy 幫它出去）；reverse proxy 代替 server 接收請求（server 在內網、proxy 幫它面對外部）。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>接手時如果 server 上跑著 nginx 但應用程式用的是 PHP-FPM 或 Node.js，nginx 多半扮演 reverse proxy——它接 HTTP/HTTPS 請求、轉發給後端的 application server。設定檔裡的 <code>proxy_pass</code>（nginx）或 <code>ProxyPass</code>（Apache）就是 reverse proxy 的轉發規則。</p>
<h2 id="設計責任">設計責任</h2>
<p>reverse proxy 常承擔的功能：</p>
<table>
  <thead>
      <tr>
          <th>功能</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TLS 終結</td>
          <td>HTTPS 的加解密在 proxy 層處理，後端服務只收 HTTP</td>
      </tr>
      <tr>
          <td>負載平衡</td>
          <td>把請求分配到多台後端（round-robin、least-connection）</td>
      </tr>
      <tr>
          <td>路由分流</td>
          <td>依 URL path 導到不同後端服務（/api → backend、/ → frontend）</td>
      </tr>
      <tr>
          <td>靜態檔案快取</td>
          <td>圖片、CSS、JS 由 proxy 直接回應、不轉發到後端</td>
      </tr>
      <tr>
          <td>安全過濾</td>
          <td>擋掉異常請求、限制請求速率、加安全標頭</td>
      </tr>
  </tbody>
</table>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/alb/" data-link-title="ALB" data-link-desc="Application Load Balancer — 流量進入系統的第一站，負責 listener 路由、健康檢查與 TLS 終結">ALB</a>：雲端的受管 reverse proxy + 負載平衡器</li>
<li><a href="/blog/infra/knowledge-cards/nginx/" data-link-title="nginx" data-link-desc="高效能 Web Server 與 Reverse Proxy，以集中設定檔取代 Apache 的 .htaccess 分散設定">nginx</a>：最常見的 reverse proxy 軟體</li>
</ul>
]]></content:encoded></item><item><title>Database Migration</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/database-migration/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/database-migration/</guid><description>&lt;p>Database migration 是用版本化的腳本管理資料庫 schema 變更的做法。每次 schema 變更（加欄位、改索引、拆表、改資料型別）寫成一份獨立的 migration 檔案，按順序套用。這讓 schema 的演進跟程式碼一樣有版本歷史、可追蹤、可在新環境重現。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>migration 解決的問題是「資料庫的 schema 怎麼從 A 狀態安全地變成 B 狀態」。沒有 migration 時，schema 變更靠在 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin&lt;/a> 或 CLI 手動執行 SQL，改了什麼只存在操作者的記憶裡。有 migration 時，每次變更都是 repo 裡的一份檔案，跟程式碼一起 commit、一起 review。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>接手專案時，如果 repo 裡有 &lt;code>migrations/&lt;/code> 目錄（或框架特定的路徑如 Laravel 的 &lt;code>database/migrations/&lt;/code>、Rails 的 &lt;code>db/migrate/&lt;/code>），代表專案使用 migration。如果 repo 裡只有一份 &lt;code>schema.sql&lt;/code> 或完全沒有 schema 相關檔案，代表 schema 變更是手動的——這時候建立 migration 紀律是接手後的優先事項之一。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>每份 migration 檔案包含兩個方向：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>UP&lt;/strong>（套用）：執行 schema 變更的 SQL&lt;/li>
&lt;li>&lt;strong>DOWN&lt;/strong>（回退）：撤銷這次變更的 SQL（不是所有變更都能完美回退，如刪除欄位後資料就沒了）&lt;/li>
&lt;/ul>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- migrations/2026-06-26-001-add-users-email-verified.sql
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- UP
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">ALTER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">TABLE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ADD&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLUMN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">email_verified&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">BOOLEAN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DEFAULT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FALSE&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- DOWN
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">ALTER&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">TABLE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">users&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">DROP&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">COLUMN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">email_verified&lt;/span>&lt;span class="p">;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>常用的 migration 工具：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>工具&lt;/th>
 &lt;th>語言 / 框架&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Laravel Migration&lt;/td>
 &lt;td>PHP / Laravel&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Rails Migration&lt;/td>
 &lt;td>Ruby / Rails&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Flyway&lt;/td>
 &lt;td>Java / 跨語言（純 SQL）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Liquibase&lt;/td>
 &lt;td>Java / 跨語言（XML / YAML / SQL）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>golang-migrate&lt;/td>
 &lt;td>Go&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>手動 SQL 檔案&lt;/td>
 &lt;td>無框架時的最低限度方案&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>沒有框架時，用日期 + 序號命名 SQL 檔案（&lt;code>2026-06-26-001-描述.sql&lt;/code>），搭配一張 &lt;code>migration_log&lt;/code> 表記錄哪些已經套用過，就是最低限度的 migration 系統。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/rds/" data-link-title="RDS" data-link-desc="AWS 的受管關聯式資料庫服務，代管備份、更新與 failover，讓使用者專注在 schema 和查詢">RDS&lt;/a>：migration 在 production 資料庫上執行時要格外小心——大表的 ALTER TABLE 可能鎖表&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/mysqldump/" data-link-title="mysqldump" data-link-desc="MySQL / MariaDB 的 CLI 備份工具，把資料庫匯出成 SQL 語句的純文字檔">mysqldump&lt;/a>：執行 migration 前先做一次完整備份&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Database migration 是用版本化的腳本管理資料庫 schema 變更的做法。每次 schema 變更（加欄位、改索引、拆表、改資料型別）寫成一份獨立的 migration 檔案，按順序套用。這讓 schema 的演進跟程式碼一樣有版本歷史、可追蹤、可在新環境重現。</p>
<h2 id="概念位置">概念位置</h2>
<p>migration 解決的問題是「資料庫的 schema 怎麼從 A 狀態安全地變成 B 狀態」。沒有 migration 時，schema 變更靠在 <a href="/blog/infra/knowledge-cards/phpmyadmin/" data-link-title="phpMyAdmin" data-link-desc="Web 介面的 MySQL / MariaDB 管理工具，透過瀏覽器操作資料庫">phpMyAdmin</a> 或 CLI 手動執行 SQL，改了什麼只存在操作者的記憶裡。有 migration 時，每次變更都是 repo 裡的一份檔案，跟程式碼一起 commit、一起 review。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>接手專案時，如果 repo 裡有 <code>migrations/</code> 目錄（或框架特定的路徑如 Laravel 的 <code>database/migrations/</code>、Rails 的 <code>db/migrate/</code>），代表專案使用 migration。如果 repo 裡只有一份 <code>schema.sql</code> 或完全沒有 schema 相關檔案，代表 schema 變更是手動的——這時候建立 migration 紀律是接手後的優先事項之一。</p>
<h2 id="設計責任">設計責任</h2>
<p>每份 migration 檔案包含兩個方向：</p>
<ul>
<li><strong>UP</strong>（套用）：執行 schema 變更的 SQL</li>
<li><strong>DOWN</strong>（回退）：撤銷這次變更的 SQL（不是所有變更都能完美回退，如刪除欄位後資料就沒了）</li>
</ul>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">-- migrations/2026-06-26-001-add-users-email-verified.sql
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="c1">-- UP
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="k">ADD</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="n">email_verified</span><span class="w"> </span><span class="nb">BOOLEAN</span><span class="w"> </span><span class="k">DEFAULT</span><span class="w"> </span><span class="k">FALSE</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="w"></span><span class="c1">-- DOWN
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"></span><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">users</span><span class="w"> </span><span class="k">DROP</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="n">email_verified</span><span class="p">;</span></span></span></code></pre></div><p>常用的 migration 工具：</p>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>語言 / 框架</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Laravel Migration</td>
          <td>PHP / Laravel</td>
      </tr>
      <tr>
          <td>Rails Migration</td>
          <td>Ruby / Rails</td>
      </tr>
      <tr>
          <td>Flyway</td>
          <td>Java / 跨語言（純 SQL）</td>
      </tr>
      <tr>
          <td>Liquibase</td>
          <td>Java / 跨語言（XML / YAML / SQL）</td>
      </tr>
      <tr>
          <td>golang-migrate</td>
          <td>Go</td>
      </tr>
      <tr>
          <td>手動 SQL 檔案</td>
          <td>無框架時的最低限度方案</td>
      </tr>
  </tbody>
</table>
<p>沒有框架時，用日期 + 序號命名 SQL 檔案（<code>2026-06-26-001-描述.sql</code>），搭配一張 <code>migration_log</code> 表記錄哪些已經套用過，就是最低限度的 migration 系統。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/rds/" data-link-title="RDS" data-link-desc="AWS 的受管關聯式資料庫服務，代管備份、更新與 failover，讓使用者專注在 schema 和查詢">RDS</a>：migration 在 production 資料庫上執行時要格外小心——大表的 ALTER TABLE 可能鎖表</li>
<li><a href="/blog/infra/knowledge-cards/mysqldump/" data-link-title="mysqldump" data-link-desc="MySQL / MariaDB 的 CLI 備份工具，把資料庫匯出成 SQL 語句的純文字檔">mysqldump</a>：執行 migration 前先做一次完整備份</li>
</ul>
]]></content:encoded></item><item><title>Prometheus</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/prometheus/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/prometheus/</guid><description>&lt;p>Prometheus 是開源的 metrics 收集與告警系統。它用 pull 模式運作——定期從被監控的 target（應用程式、伺服器、資料庫）的 HTTP endpoint 拉取指標，存進本地的時序資料庫。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Prometheus 在 infra 監控層負責「收集與儲存指標」。它搭配 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/grafana/" data-link-title="Grafana" data-link-desc="開源的監控視覺化平台，從 Prometheus / Loki / Elasticsearch 等資料源建立 dashboard">Grafana&lt;/a> 做視覺化（Prometheus 自己的 UI 只有基礎的 query 介面）、搭配 Alertmanager 做告警路由（Prometheus 偵測異常、Alertmanager 決定通知誰）。斷網環境裡它是取代 Datadog / New Relic 的預設方案——不需要連外、self-hosted、社群龐大。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>系統需要 Prometheus 的訊號是：需要追蹤隨時間變化的數值指標（CPU 使用率、request 延遲、佇列深度、錯誤率），且這些指標要能查詢歷史趨勢和設定告警閾值。如果只需要 log（文字紀錄），Loki 或 ELK 更適合；Prometheus 處理的是結構化的數值 metrics。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 Prometheus 時要決定：scrape interval（多久拉一次、預設 15 秒）、retention（資料保留多久、預設 15 天）、哪些 target 要監控（service discovery 或靜態設定）、告警規則的閾值和評估窗口。斷網環境的額外考量是 storage capacity——所有資料留在本地磁碟、沒有 cloud auto-scale。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/grafana/" data-link-title="Grafana" data-link-desc="開源的監控視覺化平台，從 Prometheus / Loki / Elasticsearch 等資料源建立 dashboard">Grafana&lt;/a>：視覺化 Prometheus 的指標&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Prometheus 是開源的 metrics 收集與告警系統。它用 pull 模式運作——定期從被監控的 target（應用程式、伺服器、資料庫）的 HTTP endpoint 拉取指標，存進本地的時序資料庫。</p>
<h2 id="概念位置">概念位置</h2>
<p>Prometheus 在 infra 監控層負責「收集與儲存指標」。它搭配 <a href="/blog/infra/knowledge-cards/grafana/" data-link-title="Grafana" data-link-desc="開源的監控視覺化平台，從 Prometheus / Loki / Elasticsearch 等資料源建立 dashboard">Grafana</a> 做視覺化（Prometheus 自己的 UI 只有基礎的 query 介面）、搭配 Alertmanager 做告警路由（Prometheus 偵測異常、Alertmanager 決定通知誰）。斷網環境裡它是取代 Datadog / New Relic 的預設方案——不需要連外、self-hosted、社群龐大。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>系統需要 Prometheus 的訊號是：需要追蹤隨時間變化的數值指標（CPU 使用率、request 延遲、佇列深度、錯誤率），且這些指標要能查詢歷史趨勢和設定告警閾值。如果只需要 log（文字紀錄），Loki 或 ELK 更適合；Prometheus 處理的是結構化的數值 metrics。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 Prometheus 時要決定：scrape interval（多久拉一次、預設 15 秒）、retention（資料保留多久、預設 15 天）、哪些 target 要監控（service discovery 或靜態設定）、告警規則的閾值和評估窗口。斷網環境的額外考量是 storage capacity——所有資料留在本地磁碟、沒有 cloud auto-scale。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/grafana/" data-link-title="Grafana" data-link-desc="開源的監控視覺化平台，從 Prometheus / Loki / Elasticsearch 等資料源建立 dashboard">Grafana</a>：視覺化 Prometheus 的指標</li>
</ul>
]]></content:encoded></item><item><title>Grafana</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/grafana/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/grafana/</guid><description>&lt;p>Grafana 是開源的監控視覺化平台。它本身不收集或儲存資料——它連接外部資料源（&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/prometheus/" data-link-title="Prometheus" data-link-desc="開源的 metrics 收集與告警系統，用 pull 模式從 target 拉取指標，斷網環境的預設監控方案">Prometheus&lt;/a>、Loki、Elasticsearch、MySQL 等），提供查詢介面和可自訂的儀表板。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Grafana 在監控體系裡負責「讓指標和 log 變成人可以讀的畫面」。Prometheus 收集指標、Loki 收集 log、Grafana 把兩者的資料用圖表、表格、熱力圖呈現。不同角色看不同 dashboard——DevOps 看資源健康、開發者看應用指標、管理層看 SLA 達成率。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>系統需要 Grafana 的訊號是：已經有 Prometheus 或其他資料源在收集指標，但需要一個視覺化介面來建 dashboard、設告警（Grafana 也有自己的告警功能）、分享給團隊。如果只需要 CLI 查詢，PromQL 直接在 Prometheus 跑就好。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 Grafana 時要決定：dashboard 的組織（按服務、按環境、按角色）、資料源的連線設定、使用者權限（viewer / editor / admin）、告警通知管道（email / Slack / webhook）。斷網環境裡 Grafana 的 plugin 需要離線安裝（&lt;code>grafana-cli --pluginUrl&lt;/code> 指向本地檔案）。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/prometheus/" data-link-title="Prometheus" data-link-desc="開源的 metrics 收集與告警系統，用 pull 模式從 target 拉取指標，斷網環境的預設監控方案">Prometheus&lt;/a>：Grafana 最常見的 metrics 資料源&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Grafana 是開源的監控視覺化平台。它本身不收集或儲存資料——它連接外部資料源（<a href="/blog/infra/knowledge-cards/prometheus/" data-link-title="Prometheus" data-link-desc="開源的 metrics 收集與告警系統，用 pull 模式從 target 拉取指標，斷網環境的預設監控方案">Prometheus</a>、Loki、Elasticsearch、MySQL 等），提供查詢介面和可自訂的儀表板。</p>
<h2 id="概念位置">概念位置</h2>
<p>Grafana 在監控體系裡負責「讓指標和 log 變成人可以讀的畫面」。Prometheus 收集指標、Loki 收集 log、Grafana 把兩者的資料用圖表、表格、熱力圖呈現。不同角色看不同 dashboard——DevOps 看資源健康、開發者看應用指標、管理層看 SLA 達成率。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>系統需要 Grafana 的訊號是：已經有 Prometheus 或其他資料源在收集指標，但需要一個視覺化介面來建 dashboard、設告警（Grafana 也有自己的告警功能）、分享給團隊。如果只需要 CLI 查詢，PromQL 直接在 Prometheus 跑就好。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 Grafana 時要決定：dashboard 的組織（按服務、按環境、按角色）、資料源的連線設定、使用者權限（viewer / editor / admin）、告警通知管道（email / Slack / webhook）。斷網環境裡 Grafana 的 plugin 需要離線安裝（<code>grafana-cli --pluginUrl</code> 指向本地檔案）。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/prometheus/" data-link-title="Prometheus" data-link-desc="開源的 metrics 收集與告警系統，用 pull 模式從 target 拉取指標，斷網環境的預設監控方案">Prometheus</a>：Grafana 最常見的 metrics 資料源</li>
</ul>
]]></content:encoded></item><item><title>HashiCorp Vault</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/vault/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/vault/</guid><description>&lt;p>HashiCorp Vault 是機密管理系統，集中存放和控制對敏感資料（密碼、API key、TLS 私鑰、資料庫憑證）的存取。每一次讀取都有稽核紀錄、每一份機密都有存取政策、憑證可以設定自動輪替。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Vault 在 infra 裡負責「機密值的集中管理」。跟直接把密碼寫在環境變數或設定檔的差別是：Vault 提供存取控制（只有被授權的身分能讀特定 secret）、稽核軌跡（誰在什麼時候讀了什麼）、以及動態 secret（每次請求產生一組臨時憑證、用完即銷毀）。&lt;/p>
&lt;p>連網環境通常用雲端的 secret manager（AWS Secrets Manager、GCP Secret Manager）。斷網環境沒有雲端服務可用、Vault 是 self-hosted 的替代方案。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>系統需要 Vault 的訊號是：多個服務共用同一組資料庫密碼且密碼寫在設定檔裡、沒有人知道上次輪替是什麼時候、或是稽核要求「列出誰能存取哪些機密」而答不出來。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 Vault 時要決定：unseal 方式（連網用 cloud auto-unseal、斷網用 Shamir&amp;rsquo;s secret sharing——需要 N 把 key 中的 M 把才能解鎖）、storage backend（Consul、PostgreSQL、filesystem）、認證方式（人用 LDAP/OIDC、機器用 AppRole）、secret engine 的選擇（KV 存靜態值、PKI 簽發憑證、database 動態產生 DB 帳號）。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a>：Vault 的存取政策跟 IAM 的 policy 概念類似&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ssl-tls/" data-link-title="SSL / TLS" data-link-desc="加密 client 與 server 之間通訊的協定，讓 HTTPS 成為可能。TLS 是 SSL 的後繼者，但 SSL 憑證的稱呼仍廣泛使用">SSL/TLS&lt;/a>：Vault 的 PKI engine 可以當內部 CA 簽發憑證&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>HashiCorp Vault 是機密管理系統，集中存放和控制對敏感資料（密碼、API key、TLS 私鑰、資料庫憑證）的存取。每一次讀取都有稽核紀錄、每一份機密都有存取政策、憑證可以設定自動輪替。</p>
<h2 id="概念位置">概念位置</h2>
<p>Vault 在 infra 裡負責「機密值的集中管理」。跟直接把密碼寫在環境變數或設定檔的差別是：Vault 提供存取控制（只有被授權的身分能讀特定 secret）、稽核軌跡（誰在什麼時候讀了什麼）、以及動態 secret（每次請求產生一組臨時憑證、用完即銷毀）。</p>
<p>連網環境通常用雲端的 secret manager（AWS Secrets Manager、GCP Secret Manager）。斷網環境沒有雲端服務可用、Vault 是 self-hosted 的替代方案。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>系統需要 Vault 的訊號是：多個服務共用同一組資料庫密碼且密碼寫在設定檔裡、沒有人知道上次輪替是什麼時候、或是稽核要求「列出誰能存取哪些機密」而答不出來。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 Vault 時要決定：unseal 方式（連網用 cloud auto-unseal、斷網用 Shamir&rsquo;s secret sharing——需要 N 把 key 中的 M 把才能解鎖）、storage backend（Consul、PostgreSQL、filesystem）、認證方式（人用 LDAP/OIDC、機器用 AppRole）、secret engine 的選擇（KV 存靜態值、PKI 簽發憑證、database 動態產生 DB 帳號）。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a>：Vault 的存取政策跟 IAM 的 policy 概念類似</li>
<li><a href="/blog/infra/knowledge-cards/ssl-tls/" data-link-title="SSL / TLS" data-link-desc="加密 client 與 server 之間通訊的協定，讓 HTTPS 成為可能。TLS 是 SSL 的後繼者，但 SSL 憑證的稱呼仍廣泛使用">SSL/TLS</a>：Vault 的 PKI engine 可以當內部 CA 簽發憑證</li>
</ul>
]]></content:encoded></item><item><title>Harbor</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/harbor/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/harbor/</guid><description>&lt;p>Harbor 是開源的 container image registry，由 CNCF 孵化。它在 Docker Registry 的基礎上加了企業級功能：Web UI、角色型存取控制（RBAC）、映像漏洞掃描（內建 Trivy）、映像簽章驗證、以及跨 registry 的映像複製。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Harbor 在容器生態裡負責「映像的儲存、分發和安全把關」。連網環境裡這個角色通常由 Docker Hub、AWS ECR 或 GCR 擔任。斷網環境沒有公開 registry 可用、Harbor 是 self-hosted 的替代——所有 base image 和應用 image 都推進 Harbor、所有 docker pull 都從 Harbor 拉。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>系統需要 Harbor 的訊號是：團隊開始用容器部署服務、且環境無法連到公開 registry（斷網或受限網路）、或需要在 pull 時自動掃描漏洞。如果只是幾個人在開發機上用 Docker、Docker Registry（無 UI、無掃描）就夠了。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 Harbor 時要決定：project 的組織（按團隊、按環境、按產品線）、使用者認證（本地帳號 or LDAP 整合）、漏洞掃描政策（push 時自動掃、block 有 Critical CVE 的 image）、映像保留政策（保留最近 N 個 tag、自動清理舊 image）、以及 storage backend（本地磁碟或 NFS）。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS&lt;/a>：ECS task 從 registry 拉 image&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/fargate/" data-link-title="Fargate" data-link-desc="AWS ECS 的無伺服器執行模式，由 AWS 代管運算實例，不需要管 EC2 capacity 或 AMI 更新">Fargate&lt;/a>：Fargate task 同樣需要 registry&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Harbor 是開源的 container image registry，由 CNCF 孵化。它在 Docker Registry 的基礎上加了企業級功能：Web UI、角色型存取控制（RBAC）、映像漏洞掃描（內建 Trivy）、映像簽章驗證、以及跨 registry 的映像複製。</p>
<h2 id="概念位置">概念位置</h2>
<p>Harbor 在容器生態裡負責「映像的儲存、分發和安全把關」。連網環境裡這個角色通常由 Docker Hub、AWS ECR 或 GCR 擔任。斷網環境沒有公開 registry 可用、Harbor 是 self-hosted 的替代——所有 base image 和應用 image 都推進 Harbor、所有 docker pull 都從 Harbor 拉。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>系統需要 Harbor 的訊號是：團隊開始用容器部署服務、且環境無法連到公開 registry（斷網或受限網路）、或需要在 pull 時自動掃描漏洞。如果只是幾個人在開發機上用 Docker、Docker Registry（無 UI、無掃描）就夠了。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 Harbor 時要決定：project 的組織（按團隊、按環境、按產品線）、使用者認證（本地帳號 or LDAP 整合）、漏洞掃描政策（push 時自動掃、block 有 Critical CVE 的 image）、映像保留政策（保留最近 N 個 tag、自動清理舊 image）、以及 storage backend（本地磁碟或 NFS）。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS</a>：ECS task 從 registry 拉 image</li>
<li><a href="/blog/infra/knowledge-cards/fargate/" data-link-title="Fargate" data-link-desc="AWS ECS 的無伺服器執行模式，由 AWS 代管運算實例，不需要管 EC2 capacity 或 AMI 更新">Fargate</a>：Fargate task 同樣需要 registry</li>
</ul>
]]></content:encoded></item><item><title>Helm</title><link>https://tarrragon.github.io/blog/infra/knowledge-cards/helm/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/knowledge-cards/helm/</guid><description>&lt;p>Helm 是 Kubernetes 的套件管理工具。它用 chart（一組模板檔案 + 預設值）把多個 K8s 資源（Deployment、Service、ConfigMap、Ingress 等）打包成一個可安裝、可升級、可回退的單位。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Helm 在 K8s 生態裡的角色類似 apt 在 Linux、npm 在 Node.js——把「安裝一個應用」從「逐一 apply 多個 YAML」變成「一條 &lt;code>helm install&lt;/code> 指令」。chart 可以參數化（values.yaml），同一份 chart 在不同環境用不同參數部署。&lt;/p>
&lt;p>公開 chart 從 Artifact Hub 下載。斷網環境裡用 &lt;code>helm pull&lt;/code> 在外部下載 chart tarball、搬進內網、從本地檔案安裝，或用 Harbor 的 OCI chart 支援當內部 chart registry。&lt;/p>
&lt;h2 id="可觀察訊號">可觀察訊號&lt;/h2>
&lt;p>系統需要 Helm 的訊號是：用 K8s 部署的應用超過 3 個、每個應用由 5+ 個 K8s 資源組成、且需要在多個環境（dev/staging/prod）用不同參數部署同一套定義。如果只有 1-2 個簡單應用、直接 &lt;code>kubectl apply&lt;/code> 就好。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>使用 Helm 時要決定：chart 的粒度（一個 chart = 一個微服務 or 一整個平台）、values 的組織（per-environment values file）、chart 版本管理（chart version vs app version）、以及升級策略（&lt;code>helm upgrade --atomic&lt;/code> 失敗自動回退）。&lt;/p>
&lt;h2 id="鄰卡">鄰卡&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS&lt;/a>：ECS 是非 K8s 的容器編排替代&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Helm 是 Kubernetes 的套件管理工具。它用 chart（一組模板檔案 + 預設值）把多個 K8s 資源（Deployment、Service、ConfigMap、Ingress 等）打包成一個可安裝、可升級、可回退的單位。</p>
<h2 id="概念位置">概念位置</h2>
<p>Helm 在 K8s 生態裡的角色類似 apt 在 Linux、npm 在 Node.js——把「安裝一個應用」從「逐一 apply 多個 YAML」變成「一條 <code>helm install</code> 指令」。chart 可以參數化（values.yaml），同一份 chart 在不同環境用不同參數部署。</p>
<p>公開 chart 從 Artifact Hub 下載。斷網環境裡用 <code>helm pull</code> 在外部下載 chart tarball、搬進內網、從本地檔案安裝，或用 Harbor 的 OCI chart 支援當內部 chart registry。</p>
<h2 id="可觀察訊號">可觀察訊號</h2>
<p>系統需要 Helm 的訊號是：用 K8s 部署的應用超過 3 個、每個應用由 5+ 個 K8s 資源組成、且需要在多個環境（dev/staging/prod）用不同參數部署同一套定義。如果只有 1-2 個簡單應用、直接 <code>kubectl apply</code> 就好。</p>
<h2 id="設計責任">設計責任</h2>
<p>使用 Helm 時要決定：chart 的粒度（一個 chart = 一個微服務 or 一整個平台）、values 的組織（per-environment values file）、chart 版本管理（chart version vs app version）、以及升級策略（<code>helm upgrade --atomic</code> 失敗自動回退）。</p>
<h2 id="鄰卡">鄰卡</h2>
<ul>
<li><a href="/blog/infra/knowledge-cards/ecs/" data-link-title="ECS" data-link-desc="AWS Elastic Container Service — 受管的容器編排服務，用 task definition 描述容器配置、由平台負責排程與健康管理">ECS</a>：ECS 是非 K8s 的容器編排替代</li>
</ul>
]]></content:encoded></item></channel></rss>