<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Code and Me</title>
  <icon>https://blog.kyomind.tw/favicon-32x32.png</icon>
  <subtitle>Kyo 的程式與學習心得</subtitle>
  <link href="https://blog.kyomind.tw/atom.xml" rel="self"/>
  
  <link href="https://blog.kyomind.tw/"/>
  <updated>2026-08-16T05:15:16.265Z</updated>
  <id>https://blog.kyomind.tw/</id>
  
  <author>
    <name>Kyo Huang</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Hermes Agent 新手指南：從入門到進階的 10 個設定</title>
    <link href="https://blog.kyomind.tw/hermes-agent/"/>
    <id>https://blog.kyomind.tw/hermes-agent/</id>
    <published>2026-07-11T17:00:35.000Z</published>
    <updated>2026-08-16T05:15:16.265Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20260712-000922.jpg" alt="from Pixabay"><span class="cap">from Pixabay</span></p><blockquote><p><code>2026/08/02</code> 新增：OpenCode Go 方案 <a href="#%E4%BA%8C%E3%80%81OpenCode-Go-%E6%96%B9%E6%A1%88">8&#x2F;1 更新重點整理</a>。</p></blockquote><blockquote><p><code>2026/08/01</code> 更新：因應模型<strong>大幅降價</strong>，新增 <strong>GPT 5.6 Luna</strong> 模型推薦。目前在 <a href="#%E4%B8%80%E3%80%81ChatGPT%EF%BC%88Codex%EF%BC%89">ChatGPT Plus</a> 與 OpenCode Go 方案皆可使用！</p></blockquote><blockquote><p><code>2026/07/17</code> 更新：新增 <strong>Grok 4.5</strong> 模型推薦。（<a href="#%E4%BA%8C%E3%80%81OpenCode-Go-%E6%96%B9%E6%A1%88">OpenCode Go 方案</a>）</p></blockquote><p>最近 Hermes Agent 非常紅，熱度上似乎已經超越了俗稱「龍蝦」的 OpenClaw。</p><p>我自己玩了一個多月，也累積了一些心得想要與你分享。</p><p>如果你還不知道它是什麼，可以先參考 PAPAYA 的這支影片：</p><blockquote><p><a href="https://youtu.be/-EivK7vpOXY?si=sNamSkiMElvmg_7d">Hermes Agent 保姆級教學來了！最安全的 AI 私人助理造成 OpenClaw 大規模棄養潮，用過就回不去了！</a></p></blockquote><p>影片把安裝流程和許多功能講解得很清楚，我盡量不重複這些內容。</p><p>本文將整理，我玩 Hermes Agent 覺得<strong>最有用的 10 個設定</strong>，供感興趣的朋友們參考。</p><p>值得一提的是，本文並非從零開始的完整教學，它更像是我個人的實戰經驗與分享。</p><p>話不多說，讓我們一起加入「養殖業」吧！😆</p><span id="more"></span><h3 id="本文目錄"><a href="#本文目錄" class="headerlink" title="本文目錄"></a>本文目錄</h3><p>方便快速跳轉到有興趣的部分：</p><ol><li><a href="#Hermes-%E6%98%AF%E4%BB%80%E9%BA%BC">Hermes 是什麼</a></li><li><a href="#Provider-%E6%8E%A8%E8%96%A6">Provider 推薦</a></li><li><a href="#1-%E8%A8%AD%E5%AE%9A-Telegram-Gateway">設定 Telegram Gateway</a></li><li><a href="#2-%E4%BD%BF%E7%94%A8-Tavily-Web-Search">使用 Tavily Web Search</a></li><li><a href="#3-%E4%B8%8A%E8%AA%BF-Memory-%E4%B8%8A%E9%99%90">上調 Memory 上限</a></li><li><a href="#4-%E6%96%B0%E5%A2%9E%E3%80%8C%E6%A8%A1%E5%9E%8B%E5%88%A5%E5%90%8D%E3%80%8D">新增「模型別名」</a></li><li><a href="#5-%E8%AA%BF%E6%95%B4-Compression-%E9%96%80%E6%AA%BB">調整 Compression 門檻</a></li><li><a href="#6-%E7%B2%BE%E7%B0%A1%E9%A0%90%E8%A8%AD%E7%9A%84-Skills-Tools">精簡預設的 Skills &#x2F; Tools</a></li><li><a href="#7-OrbStack-Isolated-VM">OrbStack Isolated VM</a></li><li><a href="#8-%E8%AA%9E%E9%9F%B3%E8%BD%89%E6%96%87%E5%AD%97%EF%BC%9A%E6%9C%AC%E6%A9%9F%E6%88%96-Groq-Whisper">語音轉文字：本機或 Groq Whisper</a></li><li><a href="#9-%E6%8F%90%E7%A4%BA%E9%9F%B3%E6%95%88%EF%BC%9A%E4%BD%BF%E7%94%A8-Mac-iTerm2">提示音效：使用 Mac + iTerm2</a></li><li><a href="#10-GitHub-CLI%EF%BC%9A%E8%AE%80%E5%8F%96-GitHub-%E4%B8%8A%E7%9A%84%E5%85%AC%E9%96%8B%E5%85%A7%E5%AE%B9">GitHub CLI：讀取 GitHub 上的公開內容</a></li><li><a href="#%E7%B5%90%E8%AA%9E">結語</a></li></ol><hr><h2 id="Hermes-是什麼"><a href="#Hermes-是什麼" class="headerlink" title="Hermes 是什麼"></a>Hermes 是什麼</h2><p><a href="https://hermes-agent.nousresearch.com/">Hermes Agent</a> 是 <a href="https://nousresearch.com/">Nous Research</a> 推出的<strong>開源 AI 助理專案</strong>。Nous Research 是專注於開源 LLM 的 AI 研究實驗室，曾推出 Hermes 系列模型。</p><p>簡單說，Hermes Agent 是一個可以<strong>長期養成</strong>、跑在你自己機器上的 AI 助理。</p><p>它有幾個核心特色：</p><ul><li><strong>長期記憶</strong>：它會記住你的互動，累積對你的理解</li><li><strong>自我學習</strong>：每次任務完成後會回顧並優化，下次處理類似任務更熟練</li><li><strong>可以執行指令</strong>：它能操作 terminal，幫你跑指令、改檔案、安裝套件等</li></ul><p>長期記憶與自我學習，是 Hermes 與一般 coding agent——比如 Claude Code——的<strong>不同之處</strong>。</p><p>這讓 Hermes 能夠真正「成長」為你的專屬助理，而不是每次都從零開始。</p><hr><h2 id="Provider-推薦"><a href="#Provider-推薦" class="headerlink" title="Provider 推薦"></a>Provider 推薦</h2><p>和所有的 AI agent 相同，Hermes Agent 也需要接一個 LLM 作為大腦，設定上稱之為 provider。</p><p>Provider 的具體設定，影片中有教。在此推薦<strong>兩個</strong>我服役中的 provider。</p><h3 id="一、ChatGPT（Codex）"><a href="#一、ChatGPT（Codex）" class="headerlink" title="一、ChatGPT（Codex）"></a>一、ChatGPT（Codex）</h3><p>如同〈<a href="/unsubscribe-github-copilot/">我退訂了 GitHub Copilot</a>〉一文中提到的，如果只訂閱一個 AI 聊天服務，我會<a href="/unsubscribe-github-copilot/#%E6%88%91%E6%9B%B4%E6%8E%A8%E8%96%A6%E5%93%AA%E5%80%8B%EF%BC%9F">選擇 ChatGPT Plus</a>。</p><p>因為它不僅可以聊天、寫程式，還可以拿來「<a href="/unsubscribe-github-copilot/#%E9%A1%8D%E5%A4%96%E5%A5%BD%E8%99%95%EF%BC%9A%E5%8F%AF%E4%BB%A5%E9%A4%8A%E3%80%8C%E9%BE%8D%E8%9D%A6%E3%80%8D">養龍蝦</a>」。</p><p>而和龍蝦屬於「同類」的 Hermes Agent，它也完全支援——消耗的是 Codex 的 token 額度。我一開始就是使用它，作為主要 provider。</p><p>個人推薦模型：</p><ul><li><code>GPT 5.6 Sol</code>：兩個字——強大！但 token 燒比較快</li><li><code>GPT 5.6 Luna</code>：2026 年 7 月底<a href="https://www.ithome.com.tw/news/177789">大幅降價 80%</a>，競爭力巨幅增加！瞬間讓 GPT 5.4 Mini 成為時代的眼淚🥲</li></ul><p><code>5.6 Terra</code> 定位相對尷尬：難題用 Sol，日常任務用 Luna。</p><h3 id="二、OpenCode-Go-方案"><a href="#二、OpenCode-Go-方案" class="headerlink" title="二、OpenCode Go 方案"></a>二、OpenCode Go 方案</h3><blockquote><p><code>2026-08-01</code> OpenCode Go 方案<strong>更新重點整理</strong>：</p><ol><li><strong>加入了 GPT 5.6 Luna</strong>，主打一個高 CP 值！</li><li><strong>DeepSeek V4 Flash</strong> 改為 7 月 31 日推出的「<a href="https://news.cnyes.com/news/id/6555685">正式版</a>」，實力<strong>全面超越</strong>舊版的 DeepSeek V4 Pro。但目前該模型<strong>僅透過 DeepSeek 官方 API 獨家提供</strong>，所以要先在 Web UI <strong>打開</strong>「啟用部署在中國的模型」設定；<strong>可隨時關閉</strong>，關閉後無法存取新版 Flash</li></ol></blockquote><p>我平常也用 Codex 寫程式或處理專案，這樣和 Hermes Agent 共用額度，難免還是會有 <strong>token 焦慮</strong>。</p><p>後來我找到了一個便宜又大碗的替代方案——<a href="https://opencode.ai/zht/go">OpenCode Go</a>。</p><p>在此暫不詳述，只要知道它可以作為 Hermes Agent 的 provider 即可。</p><p>我現在就是以 Go 方案作為主力，而 Codex 額度僅在必要時才用。</p><p>如果你想試 OpenCode Go，可以考慮透過<a href="https://opencode.ai/go?ref=W1961YHBF2">我的推廣連結</a>訂閱，我們將各獲得 $5 美元的 Go 方案使用量額度。</p><p>推薦模型：</p><ul><li><code>DeepSeek V4 Pro</code>：我的主力模型，個人對它的評價很高</li><li><code>DeepSeek V4 Flash</code>：便宜！非常便宜XD</li><li><code>GPT 5.6 Luna</code>：理由同上，而且這裡提供的 Luna 是 Context Window 達到 <strong>1M</strong> 的完整版！（驚）</li><li><code>Grok 4.5</code>：沒錯，這裡竟然也能用 Grok！要知道 4.5 可是比 4.3 強上好一截🤩</li></ul><p>我主要使用 DeepSeek V4 系列模型，但它們有一個共同「弱點」——<strong>沒有視覺能力</strong>。</p><p>所以需要視覺的時候，我會改用其它模型，比如 Grok。</p><hr><p>沒想到，前言還是說了不少😅，我們進入設定環節吧！</p><p>主要分成兩部分：<strong>入門</strong>與<strong>進階</strong>設定。後者可能需要一些開發經驗會比較容易上手。</p><p>我們先從以下 <strong>6 個入門設定</strong>開始，它們大多可以叫 Hermes 直接幫你完成。</p><h2 id="1-設定-Telegram-Gateway"><a href="#1-設定-Telegram-Gateway" class="headerlink" title="1. 設定 Telegram Gateway"></a>1. 設定 Telegram Gateway</h2><p>Hermes Agent 可以搭配許多通訊 app，方便你用手機下指令或聊天，實際運行的地方則是你的本機或雲端。</p><p>App 只是一個指令入口，所以稱為「gateway」。</p><p>大多數人的選擇應該都是 Telegram。Telegram 在「AI agent 整合」這塊確實做了不少努力，早已不是單純的通訊軟體了。</p><p>設定不難，跟著影片做就好。只有一點要注意：Allowlist 要填的是你的<strong>數字 ID</strong>，不是 username。</p><p>雖然設定上的細節不少，但透過看影片或問 AI，應該都能順利解決。</p><h2 id="2-使用-Tavily-Web-Search"><a href="#2-使用-Tavily-Web-Search" class="headerlink" title="2. 使用 Tavily Web Search"></a>2. 使用 Tavily Web Search</h2><p>Hermes 內建的搜尋功能，就是透過 Python 程式碼，模擬人類操作瀏覽器進行查詢。</p><p>做過 LLM app 的開發者都知道，這種做法不僅效率不佳，而且很耗 token XD</p><p><a href="https://www.tavily.com/">Tavily</a> 是專為 AI Agent 設計的搜尋 API 服務，而且每月有 1000 次的免費額度——我基本用不完。</p><p>取得 API Key，在 <code>hermes tools</code> 裡設定就好，可參考影片中的教學，在此不贅。</p><h2 id="3-上調-Memory-上限"><a href="#3-上調-Memory-上限" class="headerlink" title="3. 上調 Memory 上限"></a>3. 上調 Memory 上限</h2><p>Hermes 會記住與你的互動，讓你感覺愈來愈熟悉，其實本質上就是把一些互動記錄，寫在文字檔裡而已XD</p><p>記憶主要有兩大部分：</p><ul><li><code>USER</code></li><li><code>Memory</code></li></ul><p>因為它們會在<strong>每一次</strong>對話中被調用，所以系統設定了字數（字元）上限，以免消耗太多 token。</p><p>預設值如下：</p><ul><li><code>memory_char_limit</code>：2200 字元</li><li><code>user_char_limit</code>：1375 字元</li></ul><p>個人是覺得，這個預設上限實在太過<strong>保守</strong>了，建議調高！否則它動不動就提醒你：記憶滿載了🤯</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hermes config <span class="built_in">set</span> memory.memory_char_limit 10000</span><br><span class="line">hermes config <span class="built_in">set</span> memory.user_char_limit 5000</span><br></pre></td></tr></table></figure><p>因為平常都用 DeepSeek V4 系列，有 1M Context Window，所以調高了不少。</p><p>我覺得即使保守考慮，仍可上調到 2000（<code>USER</code>）、5000（<code>Memory</code>）會比較好用啦！</p><h2 id="4-新增「模型別名」"><a href="#4-新增「模型別名」" class="headerlink" title="4. 新增「模型別名」"></a>4. 新增「模型別名」</h2><p>雖然我並不常換模型，但需要的時候，如果還得打一長串指令或進行一連串選單操作，也是挺累人。</p><p>還好 Hermes Agent 為我們提供了「模型別名」機制。</p><p>我設了三個別名，它們分別是：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">model_aliases:</span></span><br><span class="line">  <span class="attr">gpt:</span></span><br><span class="line">    <span class="attr">provider:</span> <span class="string">openai-codex</span></span><br><span class="line">    <span class="attr">model:</span> <span class="string">gpt-5.5</span></span><br><span class="line">  <span class="attr">flash:</span></span><br><span class="line">    <span class="attr">provider:</span> <span class="string">opencode-go</span></span><br><span class="line">    <span class="attr">model:</span> <span class="string">deepseek-v4-flash</span></span><br><span class="line">  <span class="attr">pro:</span></span><br><span class="line">    <span class="attr">provider:</span> <span class="string">opencode-go</span></span><br><span class="line">    <span class="attr">model:</span> <span class="string">deepseek-v4-pro</span></span><br></pre></td></tr></table></figure><p>設定檔只是讓你參考，實作操作時，我都叫 Hermes 幫我改到好。</p><p>其中 <code>gpt</code>、<code>pro</code>、<code>flash</code> 就是你可以自定義的模型別名，任君自由發揮，正常來說是以「短」為原則。</p><p>上面提到 DeepSeek V4 沒有視覺能力，所以需要視覺時，我就要切換到 GPT 模型。</p><p>有了別名，直接 <code>/model gpt</code> 就能搞定。</p><h2 id="5-調整-Compression-門檻"><a href="#5-調整-Compression-門檻" class="headerlink" title="5. 調整 Compression 門檻"></a>5. 調整 Compression 門檻</h2><p>Hermes 預設在 context 用到 50% 時會自動壓縮對話。有人覺得這樣子<strong>太常打斷</strong>對話流程，社群常見的調整是 65% - 75%。</p><p>所謂的「打斷」是指：講到一半它開始自動壓縮，你就要<strong>等它完成</strong>。考慮到用戶體驗，我們自然不希望這件事情頻繁發生。</p><p>不過這也要看你使用的模型。一開始我用 GPT 5.5，確實覺得很容易被打斷！只好調高到 70%，才覺得舒服多了。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hermes config <span class="built_in">set</span> compression.threshold 0.7</span><br></pre></td></tr></table></figure><p>如果是大 context window 的模型（像 DeepSeek V4），預設的 50% 則綽綽有餘。</p><h2 id="6-精簡預設的-Skills-Tools"><a href="#6-精簡預設的-Skills-Tools" class="headerlink" title="6. 精簡預設的 Skills &#x2F; Tools"></a>6. 精簡預設的 Skills &#x2F; Tools</h2><p>Hermes 預設上有 <strong>90 多個 skill、30 多個 tool</strong>。聽起來很強大，但實際上，選項太多不只燒 token，還會<strong>拖累 AI 的判斷</strong>——讓它<strong>變笨</strong>！</p><p>換句話說，選項太多，AI 反而容易 miss、選錯、或乾脆跳過。仔細想想，其實人也是一樣的嘛！🤯</p><p>我的做法是先大砍一輪。直接把用不到的 skill &#x2F; tool 關掉。</p><p>不過其中 tool <strong>相對必要</strong>，能關的不多，初學者沒把握可以先按兵不動。</p><p>至於 skill，<strong>我關了一大堆</strong>，數量從預設的 9x 大幅降到 20 以下。至於哪些該關？就看你的使用場景了。</p><p><img src="https://img.kyomind.tw/img-20260712-233453.png" alt="精簡後的 tool / skill 數量"><span class="cap">精簡後的 tool / skill 數量</span></p><p>雖然 Hermes 有<a href="https://hermes-agent.nousresearch.com/docs/user-guide/features/curator">內建機制</a>，會在一段時間後，自動停用<strong>長期未使用</strong>的 skill，但預設上相當保守，我才不想等咧！</p><hr><p>剩下 <strong>4 個進階設定</strong>需要自己在 Hermes 外部實作，而且除了語音轉文字功能，其餘都比較偏<strong>開發者取向</strong>。對一般用戶僅供參考。</p><h2 id="7-OrbStack-Isolated-VM"><a href="#7-OrbStack-Isolated-VM" class="headerlink" title="7. OrbStack Isolated VM"></a>7. OrbStack Isolated VM</h2><p>影片中雖然提到「本機安裝、家用網路背後很安全」，但作為一個開發者，我當然不會這麼想☺️</p><p>我選擇用 <a href="https://orbstack.dev/">OrbStack</a> 建立 <a href="https://docs.orbstack.dev/machines/isolated">Isolated VM</a>（Ubuntu 24.04），讓 Hermes 跑在完全隔離的虛擬環境裡。</p><p>這樣即使 Hermes 被惡意 prompt 入侵，它也碰不到我的本機檔案。</p><p>我一度還想用 Docker backend 做第二層隔離，但 OrbStack VM 裡跑 Docker 會遇到 nested Docker 問題，最後決定放棄。</p><p>出於安全考量，我是覺得這種東西盡量不要跑在本機 OS 比較好XD。畢竟 AI agent 要<strong>好用</strong>，給的<strong>權限就要大</strong>——這無疑是一把<strong>雙面刃</strong>。</p><p>我是不會去冒這個險。</p><h2 id="8-語音轉文字：本機或-Groq-Whisper"><a href="#8-語音轉文字：本機或-Groq-Whisper" class="headerlink" title="8. 語音轉文字：本機或 Groq Whisper"></a>8. 語音轉文字：本機或 Groq Whisper</h2><p>Hermes 支援<strong>語音轉文字</strong>（Speech to Text，STT），適合懶得打字或手機操作的時候。</p><p>因為我 Hermes 沒裝在本機 OS，所以這東西主要用於 <strong>Telegram 的語音輸入場景</strong>。但運算上仍是透過我的本機硬體。</p><p>你可以本機跑 Whisper，隱私有保障，速度取決於你的 GPU！我因為跑虛擬機，只能調用 CPU，但速度上還也行。</p><p>我後來改用 <a href="https://console.groq.com/docs/speech-to-text">Groq Whisper</a>，它是雲端 STT 服務，免費額度夠用，速度也快。當然，這就沒有隱私可言了XD</p><p>Groq 需要申請 API Key，加到 <code>.hermes/.env</code> 裡即可。</p><h2 id="9-提示音效：使用-Mac-iTerm2"><a href="#9-提示音效：使用-Mac-iTerm2" class="headerlink" title="9. 提示音效：使用 Mac + iTerm2"></a>9. 提示音效：使用 Mac + iTerm2</h2><p>這是 macOS + iTerm2 限定的技巧。而且只能作用於 TUI，桌面版就不需要了。</p><p>如〈<a href="/agent-hooks/">為你的 AI Agent 掛上 Hooks 吧！</a>〉所言，使用 AI agent 時，任務完成通知就是<a href="/agent-hooks/#%E7%82%BA%E4%BB%80%E9%BA%BC%E3%80%8C%E9%80%9A%E7%9F%A5%E3%80%8D%E6%98%AF%E6%9C%80%E9%87%8D%E8%A6%81%E7%9A%84-Hooks">如此的重要</a>！</p><p>所幸 Hermes Agent 不用你寫 agent hooks（也沒地方寫XD），用 iTerm2 就行。</p><p>iTerm2 設定路徑：<strong>Settings → Profiles → Terminal → Bell</strong>，確保沒有勾選「Silence bell」即可。如圖：</p><p><img src="https://img.kyomind.tw/img-20260711-202212.png" alt="iTerm2 設定"><span class="cap">iTerm2 設定</span></p><p>TUI 對話完成時會有聲音提示，你可以切去做別的事，不用一直盯著畫面。</p><h2 id="10-GitHub-CLI：讀取-GitHub-上的公開內容"><a href="#10-GitHub-CLI：讀取-GitHub-上的公開內容" class="headerlink" title="10. GitHub CLI：讀取 GitHub 上的公開內容"></a>10. GitHub CLI：讀取 GitHub 上的公開內容</h2><p>如果想讓 Hermes 幫你看 GitHub 上的內容，建議安裝 <a href="https://cli.github.com/">GitHub CLI</a>。</p><p>因為透過 <code>Web Extract</code> 抓 GitHub 頁面會帶入大量 HTML 雜訊——太浪費 token。</p><p>GitHub CLI 直接透過 API 取得乾淨資料，比如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gh issue list -R owner/repo</span><br><span class="line">gh api repos/owner/repo/contents/README.md --jq <span class="string">&#x27;.content&#x27;</span> | <span class="built_in">base64</span> -d</span><br></pre></td></tr></table></figure><p>GitHub CLI 的<strong>認證方式</strong>主要有兩種。第一種是<strong>直接登入個人帳號</strong>，但這個<strong>權限過大</strong>，我只有在本機上使用 coding agent 時才會這麼做。</p><p>因此，建議採第二種：用 <a href="https://github.blog/security/application-security/introducing-fine-grained-personal-access-tokens-for-github/">Fine-Grained PAT</a>（Personal Access Token）認證，原則上只給公開 repo 讀取權限，不會洩露你的私人資訊。</p><blockquote><p>延伸閱讀：<a href="https://blog.darkthread.net/blog/github-fine-grained-pat/">筆記 - 可微調 Personal Access Token 讓 Github 存取更安全</a></p></blockquote><p>Token 取得後，可以直接在 gh 中操作認證，也可以放到前述的 <code>.hermes/.env</code> 中，讓 Hermes 自行取用。</p><hr><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p>Hermes 功能繁多、複雜度高，以上 10 個設定是我用了一個多月後的經驗整理，供你作為入門參考。</p><p>個人是覺得，這種 Personal Agent 的產品生態才剛剛起步，相信之後會有更多玩法與花樣，就讓我們繼續期待！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/img-20260712-000922.jpg&quot; alt=&quot;from Pixabay&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/08/02&lt;/code&gt; 新增：OpenCode Go 方案 &lt;a href=&quot;#%E4%BA%8C%E3%80%81OpenCode-Go-%E6%96%B9%E6%A1%88&quot;&gt;8&amp;#x2F;1 更新重點整理&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/08/01&lt;/code&gt; 更新：因應模型&lt;strong&gt;大幅降價&lt;/strong&gt;，新增 &lt;strong&gt;GPT 5.6 Luna&lt;/strong&gt; 模型推薦。目前在 &lt;a href=&quot;#%E4%B8%80%E3%80%81ChatGPT%EF%BC%88Codex%EF%BC%89&quot;&gt;ChatGPT Plus&lt;/a&gt; 與 OpenCode Go 方案皆可使用！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/07/17&lt;/code&gt; 更新：新增 &lt;strong&gt;Grok 4.5&lt;/strong&gt; 模型推薦。（&lt;a href=&quot;#%E4%BA%8C%E3%80%81OpenCode-Go-%E6%96%B9%E6%A1%88&quot;&gt;OpenCode Go 方案&lt;/a&gt;）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最近 Hermes Agent 非常紅，熱度上似乎已經超越了俗稱「龍蝦」的 OpenClaw。&lt;/p&gt;
&lt;p&gt;我自己玩了一個多月，也累積了一些心得想要與你分享。&lt;/p&gt;
&lt;p&gt;如果你還不知道它是什麼，可以先參考 PAPAYA 的這支影片：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/-EivK7vpOXY?si=sNamSkiMElvmg_7d&quot;&gt;Hermes Agent 保姆級教學來了！最安全的 AI 私人助理造成 OpenClaw 大規模棄養潮，用過就回不去了！&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;影片把安裝流程和許多功能講解得很清楚，我盡量不重複這些內容。&lt;/p&gt;
&lt;p&gt;本文將整理，我玩 Hermes Agent 覺得&lt;strong&gt;最有用的 10 個設定&lt;/strong&gt;，供感興趣的朋友們參考。&lt;/p&gt;
&lt;p&gt;值得一提的是，本文並非從零開始的完整教學，它更像是我個人的實戰經驗與分享。&lt;/p&gt;
&lt;p&gt;話不多說，讓我們一起加入「養殖業」吧！😆&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/img-20260712-000922.jpg" type="image"/>
    
    
    <category term="軟體開發" scheme="https://blog.kyomind.tw/categories/%E8%BB%9F%E9%AB%94%E9%96%8B%E7%99%BC/"/>
    
    
    <category term="AI 工具" scheme="https://blog.kyomind.tw/tags/AI-%E5%B7%A5%E5%85%B7/"/>
    
    <category term="Codex" scheme="https://blog.kyomind.tw/tags/Codex/"/>
    
    <category term="OpenCode" scheme="https://blog.kyomind.tw/tags/OpenCode/"/>
    
    <category term="ChatGPT" scheme="https://blog.kyomind.tw/tags/ChatGPT/"/>
    
  </entry>
  
  <entry>
    <title>告別 ClickOps：用 Terraform 重建 GCP 免費 VM</title>
    <link href="https://blog.kyomind.tw/terraform-gcp-free-tier-vm/"/>
    <id>https://blog.kyomind.tw/terraform-gcp-free-tier-vm/</id>
    <published>2026-07-11T00:21:15.000Z</published>
    <updated>2026-07-11T04:56:31.681Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/code-and-me.png"></p><p>大家看過古古的這篇〈<a href="https://kucw.io/blog/gcp-free-tier/">終身免費的 VM 服務！Google Cloud 免費方案分享</a>〉嗎？</p><p>文中手把手教你設定並建立 GCP Free Tier VM。說真的，以三大雲端供應商的 VM 價格來看，這樣的免費 VM 絕對堪稱大方！</p><p>去年，我照著做過一次，大概要花個十來分鐘。</p><p>後來她更新文章說有個設定沒寫到，會扣一點錢——我有發現，就先把 VM 刪了。</p><p>刪了之後，我就再也沒有重新建立過。</p><p>一來是在 <a href="/hetzner/">Hetzner</a> 上已經有一台規格更高的 VM 在跑了，沒有急迫需求。二來則是……那些「click」實在太麻煩了，想想就有點懶。</p><p>但現在不同了——因為我們有了 Terraform😎</p><span id="more"></span><hr><h2 id="ClickOps-的代價"><a href="#ClickOps-的代價" class="headerlink" title="ClickOps 的代價"></a>ClickOps 的代價</h2><p>在雲端平台的 console 上，透過大量手動操作，點來點去建立基礎設施，在圈子裡戲稱為 <a href="https://dev.to/terraformmonkey/what-is-clickops-27f9">ClickOps</a>：</p><blockquote><p>ClickOps is when engineers make manual changes directly in the cloud provider’s console.</p></blockquote><p>那為什麼說是「戲稱」呢？</p><p>因為一般而言，xxxOps（比如 <a href="https://aws.amazon.com/tw/what-is/mlops/">MLOps</a>、<a href="https://www.hwchiu.com/docs/2020/gitops">GitOps</a>）泛指某種流程透過<strong>程式碼自動化</strong>，但諷刺的是，ClickOps 裡沒有 code，只有 click😂</p><p>這種做法的優點是<strong>直觀、低門檻</strong>，但壞處也不少。</p><h3 id="一次性、不可重複"><a href="#一次性、不可重複" class="headerlink" title="一次性、不可重複"></a>一次性、不可重複</h3><p>ClickOps 最根本的問題是：做完就沒了，下次還得重來。</p><p>你花十分鐘建好一台 VM，刪掉之後想再建一台？再花十分鐘。想建十台一樣的？那就是一百分鐘。</p><p>沒有任何東西可以「重複使用」，每次都是從零開始。</p><h3 id="手動操作的疲勞"><a href="#手動操作的疲勞" class="headerlink" title="手動操作的疲勞"></a>手動操作的疲勞</h3><p>回想當初手動建 VM 的過程：小心翼翼對照文章、盯著 console 怕點錯、一堆下拉選單要確認。</p><p>Region 選對了嗎？machine type 符合免費條件嗎？disk type 要選 standard 還是 balanced？network tier 要 Premium 還是 Standard？</p><p>每一個選項都要仔細核對，因為點錯就可能開始扣錢。</p><h3 id="改動不可追溯"><a href="#改動不可追溯" class="headerlink" title="改動不可追溯"></a>改動不可追溯</h3><p>更麻煩的是，這些操作完全沒有紀錄——誰改了什麼、什麼時候改的、為什麼改，全都無從得知。</p><p>即使你截圖紀錄，也很難保證不會漏掉某個設定。更別說想 rollback 到之前的狀態——根本沒有「之前的狀態」可以回復。</p><hr><p>以上就是 ClickOps 的三大代價。</p><p>所以我刪掉那台 VM 後，就沒有動力重建了。光是想到要再點一次那些設定，就覺得心累。</p><h2 id="ClickOps-的救星：IaC"><a href="#ClickOps-的救星：IaC" class="headerlink" title="ClickOps 的救星：IaC"></a>ClickOps 的救星：IaC</h2><p>ClickOps 的反面是 IaC——<a href="https://aws.amazon.com/what-is/iac/">Infrastructure as Code</a>，用程式碼定義基礎設施。</p><p>簡單說，就是把你在 console 上點的那些設定，全部寫成程式碼。</p><p>這裡講的「程式碼」不一定是傳統程式語言，更常見的是<strong>設定檔格式</strong>——像 Terraform 用的就是 HCL（HashiCorp Configuration Language）。</p><p>重點是：它是<strong>文字檔</strong>——能留下<strong>紀錄</strong>。</p><p>下次要建同樣的東西？重跑一次就好。改壞了？Rollback 就好。想知道現在的設定是什麼？直接打開檔案看就好。</p><p>IaC 工具有很多，Terraform、<a href="https://www.pulumi.com/">Pulumi</a>、AWS CloudFormation 都是。</p><p>本文使用最常見的——Terraform。</p><hr><h2 id="Terraform-是什麼"><a href="#Terraform-是什麼" class="headerlink" title="Terraform 是什麼"></a>Terraform 是什麼</h2><p><a href="https://www.terraform.io/">Terraform</a> 是 HashiCorp 出的 IaC 工具。過去好段時間裡，它甚至是 IaC 的代名詞。</p><p>它的核心概念是<strong>宣告式</strong>：你描述「我要什麼」，Terraform 幫你算出「要怎麼做」。</p><p>換言之，就是把你在 console 點的東西寫成 <code>.tf</code> 檔案。</p><p>這些 <code>.tf</code> 檔案，如上所述，都是文字檔——可以 commit 到 Git，可以 code review，可以重複執行。</p><p>這就是 IaC 的價值。</p><h2 id="Terraform-設定的基本元件"><a href="#Terraform-設定的基本元件" class="headerlink" title="Terraform 設定的基本元件"></a>Terraform 設定的基本元件</h2><p>一個 Terraform 專案通常會有這些 <code>.tf</code> 檔案：</p><ul><li><strong>versions.tf</strong>：指定 Terraform 版本與 provider 版本</li><li><strong>provider.tf</strong>：設定雲端供應商（例如 GCP、AWS）</li><li><strong>variables.tf</strong>：定義可調整的參數</li><li><strong>main.tf</strong>：主要的資源定義</li><li><strong>outputs.tf</strong>：定義執行完成後要輸出的資訊</li></ul><p>請注意，這些檔名只是<strong>慣例</strong>，而不是規則。但社群普遍採用這套命名慣例來組織檔案，方便閱讀和協作。</p><h3 id="資源清單"><a href="#資源清單" class="headerlink" title="資源清單"></a>資源清單</h3><p>Terraform 會讀取目錄下所有 <code>.tf</code> 檔案並合併處理，檔名本身<strong>沒有特殊意義</strong>。</p><p>這是因為 <code>.tf</code> 檔案的本質就是一份<strong>資源清單</strong>——你宣告「我要這些資源」，Terraform 負責建立。它不是從上到下執行的腳本，而是根據資源之間的<strong>依賴關係</strong>，自動決定建立順序。</p><p>所以用一個檔案寫完，還是拆成五個檔案，對 Terraform 來說<strong>沒有區別</strong>。分檔純粹是為了人類好讀好維護。</p><p>知道這些，當你看到別人的 Terraform 專案時，就能大致理解它的結構。後面會分享我實際用的設定，到時還可以對照著看。</p><hr><h2 id="為什麼選-GCP-Free-Tier-VM-當練習對象"><a href="#為什麼選-GCP-Free-Tier-VM-當練習對象" class="headerlink" title="為什麼選 GCP Free Tier VM 當練習對象"></a>為什麼選 GCP Free Tier VM 當練習對象</h2><p>Terraform 是 DevOps 必備技能，這點應該沒什麼爭議。</p><p>但學 Terraform 要有練習對象。而我現有的 K3s cluster 並不適合拿來練手——就算用 Terraform 建好 VM，後面還有一堆 cluster 設定要手動處理，這部分我尚未自動化。</p><p>我需要一個可以輕鬆玩、弄壞沒關係，<strong>隨時都能砍掉重練</strong>的練習環境。</p><p>而 GCP Free Tier VM 剛好符合：</p><ul><li><strong>免費</strong>：符合條件就不用錢，練習零成本</li><li><strong>獨立</strong>：跟現有的 K3s cluster 完全分開</li><li><strong>可重來</strong>：隨時 destroy 重建，不怕搞壞</li></ul><p>這些特性，造就了一個得天獨厚的學習場景。</p><hr><h2 id="一個-apply-就搞定：Terraform-的爽快之處"><a href="#一個-apply-就搞定：Terraform-的爽快之處" class="headerlink" title="一個 apply 就搞定：Terraform 的爽快之處"></a>一個 apply 就搞定：Terraform 的爽快之處</h2><p>現在我用 Terraform 重建這台 VM，只需要不到 30 秒。</p><p>Region、machine type、disk、network tier，全部寫在 <code>.tf</code> 檔裡。不用再對照文章、不用盯著 console 怕點錯或遺漏。</p><p>想建立？一個 <code>terraform apply</code> 指令即可：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">❯ terraform apply</span><br><span class="line"></span><br><span class="line">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated</span><br><span class="line">with the following symbols:</span><br><span class="line">  + create</span><br><span class="line"></span><br><span class="line">Terraform will perform the following actions:</span><br><span class="line"></span><br><span class="line">(中略)</span><br><span class="line"></span><br><span class="line">Plan: 4 to add, 0 to change, 0 to destroy.</span><br><span class="line"></span><br><span class="line">Changes to Outputs:</span><br><span class="line">  + external_ip   = (known after apply)</span><br><span class="line">  + instance_name = <span class="string">&quot;free-tier-vm&quot;</span></span><br><span class="line">  + instance_zone = <span class="string">&quot;us-east1-b&quot;</span></span><br><span class="line">  + machine_type  = <span class="string">&quot;e2-micro&quot;</span></span><br><span class="line">  + project_id    = <span class="string">&quot;&lt;我的 GCP 專案名稱&gt;&quot;</span></span><br><span class="line"></span><br><span class="line">Do you want to perform these actions?</span><br><span class="line">  Terraform will perform the actions described above.</span><br><span class="line">  Only <span class="string">&#x27;yes&#x27;</span> will be accepted to approve.</span><br><span class="line"></span><br><span class="line">  Enter a value: <span class="built_in">yes</span></span><br></pre></td></tr></table></figure><p>填入 <code>yes</code>，按下 <code>enter</code>，完成後，你就獲得了一個完整的 VM 環境。</p><p>外部 IP、機器名稱、zone、機型等資訊都已經自動建立好，完全符合 Free Tier 條件，隨時可以連線使用。</p><p><img src="https://img.kyomind.tw/img-20260711-084923.png" alt="terraform apply 結果"><span class="cap">terraform apply 結果</span></p><p>想刪除？使用 <code>terraform destroy</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">❯ terraform destroy</span><br><span class="line"></span><br><span class="line">(中略)</span><br><span class="line"></span><br><span class="line">Destroy complete! Resources: 4 destroyed.</span><br></pre></td></tr></table></figure><p>就這麼簡單！</p><p>這種從 ClickOps 到 IaC 的落差與舒適感，親身經歷過的人更能體會。</p><p>沒錯，瑞凡，我真的回不去了！</p><hr><h2 id="我的-Terraform-設定"><a href="#我的-Terraform-設定" class="headerlink" title="我的 Terraform 設定"></a>我的 Terraform 設定</h2><p>我用來建 GCP Free Tier VM 的 Terraform 設定，已經放在 GitHub 上，可自行參考：</p><blockquote><p><a href="https://github.com/kyomind/weamind-infra/tree/main/terraform/gcp-free-tier-vm">weamind-infra&#x2F;terraform&#x2F;gcp-free-tier-vm</a></p></blockquote><p>它主要做的事情：</p><ul><li>建立一台符合 Free Tier 條件的 GCE VM</li><li>設定 network tier 為 STANDARD（Free Tier 必須）</li><li>建立 HTTP&#x2F;HTTPS&#x2F;SSH 的 firewall 規則</li><li>用 tags 讓 VM 套用這些 firewall 規則</li><li>把 SSH key 寫進 instance metadata</li></ul><p>想試的人可以 clone 下來，填好 <code>terraform.tfvars</code>，然後 <code>terraform apply</code>。</p><p>如果覺得不錯，歡迎幫我按個 ⭐️！</p><hr><h2 id="SSH-連線"><a href="#SSH-連線" class="headerlink" title="SSH 連線"></a>SSH 連線</h2><p>Terraform 建好 VM 之後，你還要能連進去。</p><p>最簡單的方式是用 <code>gcloud compute ssh</code>——它會自動透過你的 GCP 身分認證，幫你處理 SSH key，不用額外設定。</p><p>我的 Terraform 設定有另外寫 SSH key 進 instance metadata，但那需要使用者名稱、key path 完全對應，對一般人來說反而麻煩。</p><p>如果你想了解更多，可以參考 <a href="https://cloud.google.com/compute/docs/connect/standard-ssh">GCP 官方的 SSH 連線說明</a>。</p><hr><h2 id="不能倒流的時光"><a href="#不能倒流的時光" class="headerlink" title="不能倒流的時光"></a>不能倒流的時光</h2><p>由儉入奢易，由奢入儉難，我想這就是從 ClickOps 到 IaC 的心態轉變XD</p><p>Terraform 是 DevOps 必備技能，而 GCP Free Tier VM 是一個低風險、零成本的練習場。對我來說，它更是轉職路上的一塊拼圖。</p><p>如果你也想告別 ClickOps，不妨從這裡開始。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/code-and-me.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;大家看過古古的這篇〈&lt;a href=&quot;https://kucw.io/blog/gcp-free-tier/&quot;&gt;終身免費的 VM 服務！Google Cloud 免費方案分享&lt;/a&gt;〉嗎？&lt;/p&gt;
&lt;p&gt;文中手把手教你設定並建立 GCP Free Tier VM。說真的，以三大雲端供應商的 VM 價格來看，這樣的免費 VM 絕對堪稱大方！&lt;/p&gt;
&lt;p&gt;去年，我照著做過一次，大概要花個十來分鐘。&lt;/p&gt;
&lt;p&gt;後來她更新文章說有個設定沒寫到，會扣一點錢——我有發現，就先把 VM 刪了。&lt;/p&gt;
&lt;p&gt;刪了之後，我就再也沒有重新建立過。&lt;/p&gt;
&lt;p&gt;一來是在 &lt;a href=&quot;/hetzner/&quot;&gt;Hetzner&lt;/a&gt; 上已經有一台規格更高的 VM 在跑了，沒有急迫需求。二來則是……那些「click」實在太麻煩了，想想就有點懶。&lt;/p&gt;
&lt;p&gt;但現在不同了——因為我們有了 Terraform😎&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/code-and-me.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
    <category term="GCP" scheme="https://blog.kyomind.tw/tags/GCP/"/>
    
    <category term="Terraform" scheme="https://blog.kyomind.tw/tags/Terraform/"/>
    
  </entry>
  
  <entry>
    <title>為你的 AI Agent 掛上 Hooks 吧！</title>
    <link href="https://blog.kyomind.tw/agent-hooks/"/>
    <id>https://blog.kyomind.tw/agent-hooks/</id>
    <published>2026-07-10T02:16:55.000Z</published>
    <updated>2026-07-17T08:46:10.626Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/code-and-me.png"></p><blockquote><p><code>2026/07/17</code> 更新：通知腳本改為<strong>參數化</strong>，通知文字會顯示是哪一套 CLI。</p></blockquote><blockquote><p><code>2026/07/12</code> 更新：新增 Antigravity CLI hooks 設定。</p></blockquote><p>Claude Code、<a href="/cursor/">Cursor</a>、Codex，這些 AI coding agent，相信你已經耳熟能詳，甚至每天都在用了。</p><p>那你聽過 <strong>agent hooks</strong> 嗎？</p><p>本文將介紹我目前「唯二」使用的 agent hooks，並說明它們為何重要。</p><p>涵蓋工具包括 GitHub Copilot、Claude Code、OpenAI Codex、OpenCode CLI 以及 Antigravity CLI。</p><p>不過，僅限於 macOS，其餘平台，就靠大家努力了☺️</p><span id="more"></span><hr><h2 id="什麼是-Agent-Hooks"><a href="#什麼是-Agent-Hooks" class="headerlink" title="什麼是 Agent Hooks"></a>什麼是 Agent Hooks</h2><p>引領風騷的 Claude Code 最早發明了 <a href="https://code.claude.com/docs/zh-TW/hooks-guide">agent hooks</a> 這個概念。因為太過實用，後來其它工具也競相模仿。</p><p>簡單說，agent hooks 是這些 AI coding agent 提供的<strong>事件機制</strong>：當 agent 完成任務、需要確認，或發生特定事件時，<strong>自動執行你指定的腳本或指令</strong>。</p><p>如果你用過 Git hooks，比如最常見的 pre-commit hooks——在 commit 前跑腳本，agent hooks 就是同樣的概念：<strong>事件發生，執行特定指令</strong>。</p><p>只是觸發點從 Git 操作變成 <strong>agent 行為</strong>。</p><h3 id="為什麼不能只靠指令遵循"><a href="#為什麼不能只靠指令遵循" class="headerlink" title="為什麼不能只靠指令遵循"></a>為什麼不能只靠指令遵循</h3><p>我們固然可以在 prompt 裡寫下「產完程式碼後記得跑 lint」之類的要求，但 AI 不一定每次都會照做，尤其當<strong>上下文愈來愈長、指示愈來愈複雜</strong>時，它往往更傾向<strong>偷懶</strong>。</p><p>至於「做完記得通知我」就更不用說了，AI 根本沒這能力——它沒辦法「主動」播放音效或彈出系統通知。</p><p>而 hooks 保證了<strong>確定性</strong>——事件發生，腳本執行，不依靠 AI 的自主判斷。甚至做到了 AI <strong>本來不能做的事</strong>，比如上述的播放音效🔔</p><h3 id="我只設兩種-hook"><a href="#我只設兩種-hook" class="headerlink" title="我只設兩種 hook"></a>我只設兩種 hook</h3><p>Agent hooks 能做的事很多，基本上能變成指令、腳本的內容都行，比如自動跑 lint、formatter，把結果寫進檔案等等。</p><p>但這些並非本文重點——我自己只設兩種 hook：<strong>完成通知</strong>和<strong>權限請求通知</strong>，都是為了在 agent 停下來時，能即時提醒我。</p><hr><h2 id="為什麼「通知」是最重要的-Hooks"><a href="#為什麼「通知」是最重要的-Hooks" class="headerlink" title="為什麼「通知」是最重要的 Hooks"></a>為什麼「通知」是最重要的 Hooks</h2><p>沒有通知，AI 幹活時你只有兩種選擇：在前景盯著它，或不停來回確認。顯然兩種都不太有效率😅</p><p>有通知，我們才好真正「非同步」使用它：把任務交給 agent，去做別的事，聽到聲音再回來。</p><p>至於 lint、formatter，另有替代方案——<a href="https://pre-commit.com/">pre-commit</a> 這類工具、CI&#x2F;CD 都能做。但對沒有內建通知機制的工具，只能透過 agent hooks 來達成。</p><blockquote><p>相關文章：<a href="/pre-commit/">Python 開發：pre-commit 設定 Git Hooks 教學</a></p></blockquote><p>所以，其他 hooks 可以不設，但這個<strong>必須有</strong>！</p><hr><h2 id="通用性的偏好"><a href="#通用性的偏好" class="headerlink" title="通用性的偏好"></a>通用性的偏好</h2><p>我總共幫五個 AI coding agent 設定過 hooks：GitHub Copilot、OpenAI Codex、Claude Code、OpenCode CLI、Antigravity CLI。</p><p>至於 Google 的 <a href="https://antigravity.google/product/antigravity-2">Antigravity 2.0</a> app，有內建通知機制，如果沒用 CLI 可以不必設定。如果同時設定了 hooks 通知，則都會觸發，建議關掉內建通知。</p><p>我只寫全域 hooks，不寫 project-level。這些設定放在 home 目錄，透過 <a href="https://yadm.io/">yadm</a> 在不同機器之間同步。</p><blockquote><p>相關文章：<a href="/yadm-cross-platform/">yadm 教學：實作 macOS 與 Linux 的 dotfiles 跨平台同步</a></p></blockquote><p>我的 agent skills 也是採取相同策略——幾乎都是<strong>全域</strong>的，很少寫 project-level。關於「<a href="/unsubscribe-github-copilot/#%E9%80%9A%E7%94%A8-vs-%E5%B0%88%E7%94%A8">通用 vs 專用</a>」，之前文章有討論過。</p><hr><p>接下來直接看設定，腳本也一併附上。</p><h2 id="GitHub-Copilot：直接共用-Claude-Code-設定"><a href="#GitHub-Copilot：直接共用-Claude-Code-設定" class="headerlink" title="GitHub Copilot：直接共用 Claude Code 設定"></a>GitHub Copilot：直接共用 Claude Code 設定</h2><p>GitHub Copilot 能讀取 Claude Code 的設定檔中，有關 hooks 的設定，所以可以直接共用，不一定要另外寫。</p><p>不過目前 Copilot 支援的事件種類沒有 Claude Code 多——<code>Stop</code> 事件有支援；不支援的事件會跳過，不會出錯。</p><p>考慮到我目前已經暫時棄用 GitHub Copilot 了，這部分請容我略過😆</p><p>如有需求，可參考<a href="https://docs.github.com/en/copilot/concepts/agents/hooks">官方文件</a>。</p><h2 id="Claude-Code"><a href="#Claude-Code" class="headerlink" title="Claude Code"></a>Claude Code</h2><p>設定位置：<code>~/.claude/settings.json</code>，內容如下：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;hooks&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;Stop&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;matcher&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;hooks&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;command&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;bash ~/scripts/mac/notify-agent-stop.sh &#x27;Claude Code&#x27;&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;PermissionRequest&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;matcher&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;hooks&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;command&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;bash ~/scripts/mac/notify-agent-permission-request.sh &#x27;Claude Code&#x27;&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p><code>Stop</code> 是<strong>完成通知</strong>：agent 停下來了。</p><p><code>PermissionRequest</code> 是<strong>權限請求通知</strong>：當 agent 執行到需要<strong>額外權限</strong>時，需要你<strong>確認</strong>才能繼續。這個很有用，因為有時候你離開太久，回來發現 agent 早就在等你，白白浪費了時間。</p><p>上面的 <code>command</code> 的 path 請改成你放置腳本的地方，還有檔名。</p><h2 id="OpenAI-Codex"><a href="#OpenAI-Codex" class="headerlink" title="OpenAI Codex"></a>OpenAI Codex</h2><p>Codex 的設定對 app 和 CLI 都會生效，下面的 Antigravity 也是如此。</p><p>設定位置：<code>~/.codex/config.toml</code></p><figure class="highlight toml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[hooks]</span></span><br><span class="line"></span><br><span class="line"><span class="section">[[hooks.Stop]]</span></span><br><span class="line"><span class="attr">matcher</span> = <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="section">[[hooks.Stop.hooks]]</span></span><br><span class="line"><span class="attr">type</span> = <span class="string">&quot;command&quot;</span></span><br><span class="line"><span class="attr">command</span> = <span class="string">&quot;bash ~/scripts/mac/notify-agent-stop.sh Codex&quot;</span></span><br><span class="line"><span class="attr">statusMessage</span> = <span class="string">&quot;Sending agent stop notification&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="section">[[hooks.PermissionRequest]]</span></span><br><span class="line"><span class="attr">matcher</span> = <span class="string">&quot;&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="section">[[hooks.PermissionRequest.hooks]]</span></span><br><span class="line"><span class="attr">type</span> = <span class="string">&quot;command&quot;</span></span><br><span class="line"><span class="attr">command</span> = <span class="string">&quot;bash ~/scripts/mac/notify-agent-permission-request.sh Codex&quot;</span></span><br><span class="line"><span class="attr">statusMessage</span> = <span class="string">&quot;Sending agent permission request notification&quot;</span></span><br></pre></td></tr></table></figure><p>Codex 設定檔採用 <a href="https://toml.io/en/">TOML</a> 格式，和 Claude Code 的 JSON 語法不同，但結構類似。</p><p>第一次設定，重啟 Codex app 時，會需要你確認 hooks 的內容與安全性。</p><h2 id="OpenCode-CLI"><a href="#OpenCode-CLI" class="headerlink" title="OpenCode CLI"></a>OpenCode CLI</h2><p>OpenCode 比較特別：<strong>不能在設定檔裡寫 hooks，必須用 plugin。</strong></p><p>而 <code>plugin/</code> 目錄要放在 opencode 設定檔（<code>opencode.json</code>）所在的目錄底下。即：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~/.config/opencode/</span><br><span class="line">├── opencode.json</span><br><span class="line">└── plugin/</span><br><span class="line">    └── notify.js</span><br></pre></td></tr></table></figure><p>本體是一個 js 檔，內容如下（這是我用 AI Vibe 的，你可以自行調整）：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">NotifyPlugin</span> = <span class="keyword">async</span> (<span class="params">&#123; $ &#125;</span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    <span class="attr">event</span>: <span class="keyword">async</span> (&#123; event &#125;) =&gt; &#123;</span><br><span class="line">      <span class="keyword">if</span> (process.<span class="property">platform</span> !== <span class="string">&quot;darwin&quot;</span>) <span class="keyword">return</span></span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (event.<span class="property">type</span> === <span class="string">&quot;session.idle&quot;</span>) &#123;</span><br><span class="line">        <span class="keyword">await</span> $<span class="string">`bash ~/scripts/mac/notify-agent-stop.sh OpenCode`</span></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (event.<span class="property">type</span> === <span class="string">&quot;permission.asked&quot;</span>) &#123;</span><br><span class="line">        <span class="keyword">await</span> $<span class="string">`bash ~/scripts/mac/notify-agent-permission-request.sh OpenCode`</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>另外要注意的是，event type 是 <code>session.idle</code>，不是 <code>Stop</code>。不過意思差不多啦！</p><h3 id="透過-Attention-設定"><a href="#透過-Attention-設定" class="headerlink" title="透過 Attention 設定"></a>透過 Attention 設定</h3><p>其實，OpenCode CLI 還可以透過 <a href="https://opencode.ai/docs/tui/#attention">Attention</a> 功能——需要另外寫 <code>tui.json</code>，方便你設定通知，不一定要靠 plugin。</p><p>但我不確定它是否適用於「非互動模式」（即 <code>opencode run</code>），而且我感覺這做法的<strong>通用性，還不如直接寫 plugin</strong>。畢竟通知腳本可以共用。</p><h2 id="Antigravity-CLI"><a href="#Antigravity-CLI" class="headerlink" title="Antigravity CLI"></a>Antigravity CLI</h2><p>Antigravity CLI 是 Google 用來<strong>取代</strong> Gemini CLI 的命令列工具。所以它的部分設定檔位置，還是延用了  Gemini CLI。</p><blockquote><p>Google 真是狠，財大氣粗，說換就換😆</p></blockquote><p>設定位置：<code>~/.gemini/config/hooks.json</code>，內容如下：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;notify-stop&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;Stop&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">      <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;command&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;bash /Users/kyo/scripts/mac/notify-agent-stop.sh Antigravity; echo &#x27;&#123;&#125;&#x27;&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;timeout&quot;</span><span class="punctuation">:</span> <span class="number">30</span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">]</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>幾個注意事項：</p><ol><li><strong>必須用絕對路徑</strong>：Antigravity 在 <code>-p</code> 模式下，相對路徑會失敗</li><li><strong>腳本必須輸出合法 JSON</strong>：Antigravity 會檢查 stdout，所以結尾補上 <code>; echo &#39;&#123;&#125;&#39;</code></li><li><strong>沒有 PermissionRequest</strong>：Antigravity 目前不支援這個事件</li></ol><p>Antigravity CLI 已將舊 Gemini CLI 的多個 hook，精簡成<strong>僅剩 5 個核心事件</strong>。所以沒有 <code>PermissionRequest</code>——但 5 個也太少了吧！</p><hr><h2 id="共用的通知腳本"><a href="#共用的通知腳本" class="headerlink" title="共用的通知腳本"></a>共用的通知腳本</h2><p>上述工具的 hooks 都呼叫同一組 shell 腳本。腳本接受<strong>第一個參數作為 CLI 名稱</strong>，這樣多個 agent 並行時，看到通知就知道該回去哪個工具，不用一個個檢查。</p><p>沒傳參數時，則顯示預設的 <code>Agent</code>。程式碼如下：</p><h3 id="notify-agent-stop-sh"><a href="#notify-agent-stop-sh" class="headerlink" title="notify-agent-stop.sh"></a>notify-agent-stop.sh</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line">agent_name=<span class="string">&quot;<span class="variable">$&#123;1:-Agent&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 播放 Glass 音效</span></span><br><span class="line">afplay /System/Library/Sounds/Glass.aiff &amp;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 顯示 Notification Center 通知</span></span><br><span class="line">osascript -e <span class="string">&quot;display notification \&quot;<span class="variable">$&#123;agent_name&#125;</span> 已回覆\&quot; with title \&quot;Agent Stop\&quot;&quot;</span> &amp;</span><br></pre></td></tr></table></figure><p><code>afplay</code> 是 macOS 內建的指令，而音效名稱 <code>Glass</code> 也是內建的。</p><p>可以到系統的「<strong>設定 &gt; 聲音 &gt; 提示聲</strong>」去聆聽每一種內建音效，換成自己喜歡的。</p><p>也可以用 <code>afplay</code> 播放任何路徑下的音效檔（如 mp3、wav），只要檔案存在，指令就能正常運作。</p><p>而 <code>osascript</code> 則能在<strong>通知中心</strong>發出<strong>文字提醒</strong>。這兩個指令搭配起來，就能在任務完成時，同時播放音效和彈出通知，讓你知道 agent 已經處理完畢。</p><p>覺得這樣有點吵的話，可以二選一就好。</p><h3 id="notify-agent-permission-request-sh"><a href="#notify-agent-permission-request-sh" class="headerlink" title="notify-agent-permission-request.sh"></a>notify-agent-permission-request.sh</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line">agent_name=<span class="string">&quot;<span class="variable">$&#123;1:-Agent&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 播放 Funk 音效</span></span><br><span class="line">afplay /System/Library/Sounds/Funk.aiff &amp;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 顯示 Notification Center 通知</span></span><br><span class="line">osascript -e <span class="string">&quot;display notification \&quot;<span class="variable">$&#123;agent_name&#125;</span> 需要權限確認\&quot; with title \&quot;Agent Permission Request\&quot;&quot;</span> &amp;</span><br></pre></td></tr></table></figure><p>我覺得 <code>Funk</code> 音效很適合當「確認」使用XD</p><hr><h2 id="工具會換，需求長存"><a href="#工具會換，需求長存" class="headerlink" title="工具會換，需求長存"></a>工具會換，需求長存</h2><p>儘管不同的工具有不同的設定，但「通知」這個需求是一樣的。</p><p>所以我在每個工具中都實作了它，讓<strong>核心行為保持一致</strong>。</p><p>如此一來，你想換工具或退掉其中一部分時，體驗上不會受到太大影響。你只需要維護一組通知腳本，所有 agent 都能共用。</p><p>畢竟，工具只是工具，<a href="/unsubscribe-github-copilot/#%E5%B7%A5%E5%85%B7%E5%8F%AA%E6%98%AF%E5%B7%A5%E5%85%B7%EF%BC%8C%E4%B8%8D%E8%A6%81%E4%BE%9D%E6%88%80%E5%AE%83">不要依戀它</a>。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/code-and-me.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/07/17&lt;/code&gt; 更新：通知腳本改為&lt;strong&gt;參數化&lt;/strong&gt;，通知文字會顯示是哪一套 CLI。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/07/12&lt;/code&gt; 更新：新增 Antigravity CLI hooks 設定。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Claude Code、&lt;a href=&quot;/cursor/&quot;&gt;Cursor&lt;/a&gt;、Codex，這些 AI coding agent，相信你已經耳熟能詳，甚至每天都在用了。&lt;/p&gt;
&lt;p&gt;那你聽過 &lt;strong&gt;agent hooks&lt;/strong&gt; 嗎？&lt;/p&gt;
&lt;p&gt;本文將介紹我目前「唯二」使用的 agent hooks，並說明它們為何重要。&lt;/p&gt;
&lt;p&gt;涵蓋工具包括 GitHub Copilot、Claude Code、OpenAI Codex、OpenCode CLI 以及 Antigravity CLI。&lt;/p&gt;
&lt;p&gt;不過，僅限於 macOS，其餘平台，就靠大家努力了☺️&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/code-and-me.png" type="image"/>
    
    
    <category term="軟體開發" scheme="https://blog.kyomind.tw/categories/%E8%BB%9F%E9%AB%94%E9%96%8B%E7%99%BC/"/>
    
    
    <category term="AI 工具" scheme="https://blog.kyomind.tw/tags/AI-%E5%B7%A5%E5%85%B7/"/>
    
    <category term="GitHub Copilot" scheme="https://blog.kyomind.tw/tags/GitHub-Copilot/"/>
    
    <category term="Claude Code" scheme="https://blog.kyomind.tw/tags/Claude-Code/"/>
    
    <category term="Codex" scheme="https://blog.kyomind.tw/tags/Codex/"/>
    
    <category term="OpenCode" scheme="https://blog.kyomind.tw/tags/OpenCode/"/>
    
  </entry>
  
  <entry>
    <title>WeaMind Infra 介紹：VM、Load Balancer 與雲端架構</title>
    <link href="https://blog.kyomind.tw/weamind-infra/"/>
    <id>https://blog.kyomind.tw/weamind-infra/</id>
    <published>2026-07-05T06:29:12.000Z</published>
    <updated>2026-07-12T04:59:56.155Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png"></p><blockquote><p>📌 這是 <a href="/weamind-series/">WeaMind 系列</a> 的第 7 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p><a href="/weamind/">WeaMind</a> 跑在什麼上面？</p><p>最早是單一台 VM + 容器化部署，現在則<strong>複雜多了</strong>——K3s cluster、多台 VM、Load Balancer。</p><p>這篇要介紹 WeaMind 的基礎設施——<strong>cloud infra 層</strong>。後續會有好些 K8s 相關文章，都會以這個架構為基礎，所以我們先把前提講清楚。</p><p>簡單來說就是 4 台 VM + 1 個 Load Balancer，全部跑在 <a href="/hetzner/">Hetzner Cloud</a> 上，月費大約一千台幣。</p><p>K8s 相關的部署設定（<a href="https://github.com/kyomind/weamind-infra/tree/main/manifests">manifests</a>），皆已公開在這個 GitHub 專案：<a href="https://github.com/kyomind/weamind-infra">weamind-infra</a>。歡迎參考、指教。</p><span id="more"></span><hr><h2 id="總覽：WeaMind-的硬體組成"><a href="#總覽：WeaMind-的硬體組成" class="headerlink" title="總覽：WeaMind 的硬體組成"></a>總覽：WeaMind 的硬體組成</h2><p>讓我們先看一下全貌：</p><table><thead><tr><th>元件</th><th>VM 型號與規格</th><th>角色</th></tr></thead><tbody><tr><td>堡壘機</td><td>CAX21（Arm，4C&#x2F;8GB）</td><td>資料層 + SSH 跳板</td></tr><tr><td>Control Plane</td><td>CX23（x86，2C&#x2F;4GB）</td><td>K8s API Server</td></tr><tr><td>Worker × 2</td><td>CX23（x86，2C&#x2F;4GB）</td><td>跑應用 Pod</td></tr><tr><td>Load Balancer</td><td>LB11</td><td>外部入口</td></tr></tbody></table><p>這四台機器都在同一個 Hetzner Private Network 裡。內網 IP 分別是 <code>10.0.0.2</code> 至 <code>10.0.0.5</code>。</p><p>K8s 三台 node 不暴露公網。平常操作是在本機或堡壘機（<a href="https://en.wikipedia.org/wiki/Bastion_host">Bastion host</a>）用 <code>kubectl</code> 控制 cluster。這也是常見的小型 K8s 部署架構。</p><blockquote><p>延伸閱讀：<a href="https://blog.yangjerry.tw/posts/it2022-day02/">《關於我怎麼把一年內學到的新手 IT&#x2F;SRE 濃縮到 30 天筆記這檔事》 Day 02 基礎架構設定 - 網路架構</a></p></blockquote><p>實際上，我就是從上述文章第一次認識到堡壘機這個角色。</p><p>整體呈現一個「<strong>混合架構</strong>」：應用層（LINE Bot）跑在 K8s 叢集，可以彈性擴充，資料層（PostgreSQL、Redis）則留在堡壘機。彼此透過內網連接。</p><hr><h2 id="堡壘機：原本的單機版-VM"><a href="#堡壘機：原本的單機版-VM" class="headerlink" title="堡壘機：原本的單機版 VM"></a>堡壘機：原本的單機版 VM</h2><p>這台機器的角色有點特別。</p><p>最早的 WeaMind 是單機版，整個應用就跑在這台 VM 上——app、Nginx、Docker、PostgreSQL、Redis，全部塞在一起。</p><p>後來把應用層搬進 K8s 叢集，這台就「退役」成堡壘機，但資料還是留在這裡。</p><h3 id="什麼是堡壘機？"><a href="#什麼是堡壘機？" class="headerlink" title="什麼是堡壘機？"></a>什麼是堡壘機？</h3><p><strong>堡壘機</strong>（Bastion host）是內網中唯一暴露公網 IP 的機器，作為進入內部網路的<strong>跳板</strong>。</p><p>所有 SSH 連線都必須先經過它，再從內網連到其他機器。這樣的設計<strong>減少了攻擊面</strong>——只需要守住一個入口，而不是讓每台機器都暴露在外。</p><p>在 WeaMind 的架構中，堡壘機除了當跳板，還<strong>兼任資料層</strong>的角色。這不是標準做法，但對小型專案來說，把兩個功能放在同一台機器可以省下不少成本。</p><h3 id="主要規格與運行中服務"><a href="#主要規格與運行中服務" class="headerlink" title="主要規格與運行中服務"></a>主要規格與運行中服務</h3><p>規格是 Hetzner 的 <a href="https://www.hetzner.com/cloud/cost-optimized">CAX21</a>，Arm 架構，4 核 8GB。跑三個東西：</p><ul><li>PostgreSQL：存放天氣資料。</li><li>Redis：分散式鎖、Rate Limiter。</li><li>weamind-data：ETL daemon 程式，定期抓中央氣象署的天氣 API 資料，並更新至 PostgreSQL。</li></ul><p>除此之外，我在這台 VM 還運行了好幾個<strong>開源服務</strong>，比如替代 GA4 的 <a href="/weekly-review-21/">Umami</a>；替代 WakaTime 的 <a href="https://wakapi.dev/">Wakapi</a>。當然，一定少不了負責流量轉發與 TLS 憑證申請的 Nginx 與 Certbot。</p><p>儘管如此，它們總共也只佔了 1.2 GB 的 RAM，對於這台有 8 GB RAM 的機器，顯然還是浪費了！</p><p>之後預計會把 <a href="https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack">kube-prometheus-stack</a> 中，前兩大吃資源的 Pod——Prometheus 與 Grafana——移到這台上。</p><blockquote><p>延伸閱讀：<a href="https://ithelp.ithome.com.tw/articles/10329845">可觀測性宇宙的第十三天 - Kube-Prometheus-Stack 實戰（一）</a></p></blockquote><h3 id="為什麼資料層不搬進-K8s？"><a href="#為什麼資料層不搬進-K8s？" class="headerlink" title="為什麼資料層不搬進 K8s？"></a>為什麼資料層不搬進 K8s？</h3><p>主要有三個理由：</p><ol><li><strong>簡化管理</strong>：K8s StatefulSet 管理是另一個大坑，暫不考慮採用。</li><li><strong>成本考量</strong>：不需要額外搞 PV、StorageClass。</li><li><strong>資源利用</strong>：堡壘機是最大台的 VM，不多跑點東西太浪費😎</li></ol><p>總之，堡壘機確實做了不少事情，但資源上還游刃有餘。如何有效利用剩下的空間，是我接下來的課題。</p><hr><h2 id="K8s-叢集：三台節點"><a href="#K8s-叢集：三台節點" class="headerlink" title="K8s 叢集：三台節點"></a>K8s 叢集：三台節點</h2><p>K8s 叢集的部署方案採用 <a href="https://k3s.io/">K3s</a>，配置為 1 Control Plane + 2 Worker。</p><p>三台都是 <a href="https://www.hetzner.com/cloud/cost-optimized">CX23</a>：x86 架構，2 核 4GB。</p><p>這個規格對 K3s 來說綽綽有餘。K3s 本身很輕量，Control Plane 不需要太多資源；而 WeaMind 的 LINE Bot 本質上就是用 FastAPI 寫的 webhook server，也很輕量。</p><p>為什麼要兩台 Worker 而不是一台？主要是為了高可用：如果一台 VM 掛了，Pod 可以在另一台重新調度，不會整個服務直接中斷。</p><p>當然，這樣的高可用程度相對有限，或許更簡單的理由是——<strong>帥</strong>！</p><p>至於為什麼選 K3s 而不是 kubeadm，我在〈<a href="/k3s-for-weamind/">K3s 是什麼？為什麼我選擇用 K3s 部署 WeaMind</a>〉已有說明，不再重複。</p><h2 id="網路連線與防火牆"><a href="#網路連線與防火牆" class="headerlink" title="網路連線與防火牆"></a>網路連線與防火牆</h2><p>安全設計上，這三台 VM 都配有公網 IP，方便系統更新，但防火牆只允許內網流量，外部無法直接連入。</p><p><img src="https://img.kyomind.tw/img-20260705-203044.png" alt="防火牆規則"><span class="cap">防火牆規則</span></p><blockquote><p>發文後重看，我才發現第一條規則其實是<strong>多餘</strong>的——因為第二條規則已經對整個 <code>10.0.0.0/16</code> 開放了所有 TCP port，SSH 自然也包含在內。這是典型的「先開 SSH、後來才加 Private Network 全開」的演進痕跡😅</p></blockquote><p>要管理它們，必須先 SSH 到堡壘機，再從內網連進去。而對外的流量入口只有一個：Hetzner Load Balancer。</p><hr><h2 id="成本與選型考量"><a href="#成本與選型考量" class="headerlink" title="成本與選型考量"></a>成本與選型考量</h2><p>Hetzner 在今年 4 月與 6 月連續兩次漲價，據官方公告，主因是記憶體供不應求，導致巨大成本壓力（AI 熱潮的連鎖效應）。</p><p>我的機器是今年年初建立的，目前適用 4 月調整後的「舊」價格。如果你現在要開新機器，則會是 6&#x2F;15 後的新價格。</p><p><a href="https://docs.hetzner.com/general/infrastructure-and-availability/price-adjustment/">價格對照</a>：</p><table><thead><tr><th>元件</th><th>舊價格（4 月後）</th><th>新價格（6&#x2F;15 後）</th></tr></thead><tbody><tr><td>CAX21</td><td>€7.99</td><td>€10.49</td></tr><tr><td>CX23 × 3</td><td>€11.97（單台 €3.99）</td><td>€16.47（單台 €5.49）</td></tr><tr><td>LB11</td><td>€7.49</td><td>€7.49</td></tr><tr><td>固定 IP × 4</td><td>€2.00</td><td>€2.00</td></tr><tr><td><strong>總計</strong></td><td><strong>€29.45</strong></td><td><strong>€36.45</strong></td></tr></tbody></table><p>換算成台幣，大約是 NT$1,020 到 NT$1,260。</p><p>至於為什麼選 Hetzner，我在〈<a href="/hetzner-vm/">在 Hetzner 開新 VM 指南</a>〉有比較詳細的說明。簡單講就是：<strong>便宜、穩定</strong>。</p><p>但它的缺點是<strong>台灣連歐洲機房延遲偏高</strong>，對於重視用戶體驗的服務可能不適合。</p><hr><h2 id="結語：新世界的大門"><a href="#結語：新世界的大門" class="headerlink" title="結語：新世界的大門"></a>結語：新世界的大門</h2><p>這規模對 Side Project 來說，無疑是 overkill。要不是 Hetzner 的價格優勢（雖然漲了兩次價🥲），我大概也不會想自己維護一個 K8s cluster。</p><p>其實，大多數 Side Project 用一台 VM 就能搞定——但<strong>我選擇擁有叢集</strong>。</p><p>不只為了磨練技術，更重要的是，當你<strong>真的</strong>擁有一個 cluster，你的角色將<strong>從此不同</strong>：你是這個系統的管理者，而不只是單純的開發者。</p><p>這樣的心態轉變，對我而言，就像打開新世界的大門，再也回不去了。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;/weamind-series/&quot;&gt;WeaMind 系列&lt;/a&gt; 的第 7 篇。&lt;br&gt;本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;/weamind/&quot;&gt;WeaMind&lt;/a&gt; 跑在什麼上面？&lt;/p&gt;
&lt;p&gt;最早是單一台 VM + 容器化部署，現在則&lt;strong&gt;複雜多了&lt;/strong&gt;——K3s cluster、多台 VM、Load Balancer。&lt;/p&gt;
&lt;p&gt;這篇要介紹 WeaMind 的基礎設施——&lt;strong&gt;cloud infra 層&lt;/strong&gt;。後續會有好些 K8s 相關文章，都會以這個架構為基礎，所以我們先把前提講清楚。&lt;/p&gt;
&lt;p&gt;簡單來說就是 4 台 VM + 1 個 Load Balancer，全部跑在 &lt;a href=&quot;/hetzner/&quot;&gt;Hetzner Cloud&lt;/a&gt; 上，月費大約一千台幣。&lt;/p&gt;
&lt;p&gt;K8s 相關的部署設定（&lt;a href=&quot;https://github.com/kyomind/weamind-infra/tree/main/manifests&quot;&gt;manifests&lt;/a&gt;），皆已公開在這個 GitHub 專案：&lt;a href=&quot;https://github.com/kyomind/weamind-infra&quot;&gt;weamind-infra&lt;/a&gt;。歡迎參考、指教。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/WeaMind-logo-min.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
  </entry>
  
  <entry>
    <title>我退訂了 GitHub Copilot</title>
    <link href="https://blog.kyomind.tw/unsubscribe-github-copilot/"/>
    <id>https://blog.kyomind.tw/unsubscribe-github-copilot/</id>
    <published>2026-06-18T07:30:36.000Z</published>
    <updated>2026-07-14T07:53:43.837Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/code-and-me.png"></p><p>AI 輔助程式設計工具 <a href="https://github.com/features/copilot">GitHub Copilot</a> 在今年 6 月 1 號全面改制為 <a href="https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/">usage-based billing</a>，也就是<strong>按用量計費</strong>。</p><p>作為 <a href="/github-copilot/">2022</a> 年就開始付費的老用戶，我則趕在 5 月 20 號「大限」之前，退訂了原本將在 8 月 16 號到期的 Pro+ 年約，這樣可以拿回一定比例的剩餘退款。</p><p>改制到現在已逾兩週，社群反應<a href="https://www.reddit.com/r/github/comments/1ttcpw0/github_copilots_new_creditbased_pricing_is/">非常激烈</a>，尤其是個人用戶。</p><p>本文分享我決定退訂的判斷與理由，以及我的替代方案。</p><span id="more"></span><hr><h2 id="舊制：大方到不可思議的-PRU"><a href="#舊制：大方到不可思議的-PRU" class="headerlink" title="舊制：大方到不可思議的 PRU"></a>舊制：大方到不可思議的 PRU</h2><p>GitHub Copilot 過去採用 PRU（Premium Request Unit）方式計費。</p><p>簡單來說，在一次請求之內，不管 AI agent 做了多少步驟，都<strong>只消耗一次 Premium Request 額度</strong>。這確實非常大方！因此誕生了各式各樣<strong>佔便宜</strong>的用法XD</p><p>最典型的做法就是：先用 0x 模型（不消耗 PRU）撰寫<strong>完整的開發計畫</strong>，然後只需要用一次或相對少次的 PRU，就可以大量消耗 token 並完成任務。</p><p>如此一來，單次請求能跑上十幾二十分鐘——甚至更久！</p><p>在這般<strong>極限操作</strong>之下，你可能只需要付 10 美元（最低等級的月費訂閱），就可以實際使用超過 500 美元等值的 API token。</p><p>可想而知，在 AI agent 行為愈來愈複雜的今天，這樣的商業模式肯定無法持續。</p><p>尤其在 Subagent（子代理）誕生之後，情況變得更加嚴峻。</p><p>在忍無可忍之下，GitHub 決定出手改制了！</p><h2 id="新制：Usage-based-Billing"><a href="#新制：Usage-based-Billing" class="headerlink" title="新制：Usage-based Billing"></a>新制：Usage-based Billing</h2><p>現在的 Copilot 改成用 AI Credits 計費，1 Credit 等於 0.01 美元。</p><p>所謂 AI Credits，就像賭場裡的籌碼，只是現金的等價替代品，主要是為了方便計算，所以我們直接想成現金就好了。</p><p>個人方案分成<a href="https://github.com/features/copilot/plans">三種</a>：Pro 月費 10 美元（相當於 1000 Credits，以下同）、Pro+ 月費 39 美元、Max 月費 100 美元。每個方案都含有一定額度的 Credits（含 Flex 額度），用完就要加錢或等下個月。</p><table><thead><tr><th>方案</th><th>月費</th><th>Base</th><th>Flex</th><th>總額度</th></tr></thead><tbody><tr><td>Pro</td><td>$10</td><td>$10</td><td>$5</td><td>~$15</td></tr><tr><td>Pro+</td><td>$39</td><td>$39</td><td>$31</td><td>~$70</td></tr><tr><td>Max</td><td>$100</td><td>$100</td><td>$100</td><td>~$200</td></tr></tbody></table><p>關鍵來了：<strong>Credit 的計價方式，跟你自己直接去 OpenAI、Anthropic 官網使用 API 的價格完全一樣。</strong></p><p>換言之，真正「額外」給你的，只有那些 <strong>Flex 額度</strong>！而且這部分竟然是<strong>可變動</strong>的——GitHub <strong>有權調整</strong> Flex 額度的多寡。</p><hr><h2 id="API-Token-真的很燒錢"><a href="#API-Token-真的很燒錢" class="headerlink" title="API Token 真的很燒錢"></a>API Token 真的很燒錢</h2><p>乍看覺得，付 10 元給 15 元額度、39 元給 70 元、100 元給 200 元，似乎還可以呀？</p><p>可是瑞凡，API token，真的很燒錢！——消耗速度極快。</p><p>要知道，AI 模型推理過程中的那些「自言自語」，可是全都算入 token 消耗的——而且都歸類在更貴的 output token。</p><p>以前用 PRU 沒感覺，現在改成按 token 計費，你不禁發現，才一個簡單請求，還沒做多少事，就已經消耗掉幾萬甚至十幾萬的 token。</p><p>這些都是錢吶！</p><h2 id="別人更大方"><a href="#別人更大方" class="headerlink" title="別人更大方"></a>別人更大方</h2><p>Token 燒錢是一回事，但跟對手比，GitHub Copilot 的新方案也顯得<strong>太過小氣</strong>。</p><p>從 X 上的這篇<a href="https://x.com/SemiAnalysis_/status/2064815042374074396">貼文</a>可知，ChatGPT Plus 月費 20 美元，如果週週用滿，實測大約可以達到 700 美元等值的 API token（指 <a href="https://openai.com/zh-Hant/codex/">Codex</a>），倍數高達 35 倍，補貼力道驚人。</p><p>即使是相對沒那麼慷慨的 Claude Pro，月費 20 美元，最多也能用到 400 美元等值。還是非常大方！</p><p>原文中，不同方案的完整測試如下：</p><table><thead><tr><th>方案</th><th>月費</th><th>最大可能消耗（約）</th></tr></thead><tbody><tr><td><strong>Anthropic — Claude</strong></td><td></td><td></td></tr><tr><td>claude-pro</td><td>$20</td><td>$400</td></tr><tr><td>claude-max-5x</td><td>$100</td><td>$2,000</td></tr><tr><td>claude-max-20x</td><td>$200</td><td>$8,000</td></tr><tr><td><strong>OpenAI — ChatGPT &#x2F; Codex</strong></td><td></td><td></td></tr><tr><td>chatgpt-plus</td><td>$20</td><td>$700</td></tr><tr><td>chatgpt-pro-5x</td><td>$100</td><td>$3,500</td></tr><tr><td>chatgpt-pro-20x</td><td>$200</td><td>$14,000</td></tr></tbody></table><p>按照這個表格，GitHub Copilot 即使是 100 美元的 Max 方案，似乎都還沒有 20 美元的競爭對手香。</p><p>當然，兩者未必能直接比較，但差距確實相當明顯。</p><hr><h2 id="可以理解但無法諒解"><a href="#可以理解但無法諒解" class="headerlink" title="可以理解但無法諒解"></a>可以理解但無法諒解</h2><p>老實說，過去的舊模式無法持續，這是完全可以想像的。</p><p>所以我基本贊同 GitHub Copilot 應該改成更貼近現實的收費模式，讓服務能盈利且更可持續。</p><p>但這次的改動，得不到絕大多數用戶——包括我——的認同。</p><p>兩個星期過去，Reddit 和 X.com 上還是罵聲一片，鮮少有人站出來幫 GitHub 聲援。</p><h3 id="從超大方到超小氣"><a href="#從超大方到超小氣" class="headerlink" title="從超大方到超小氣"></a>從超大方到超小氣</h3><p>畢竟，過去給的福利如此大方，如今急轉直下，難免讓人覺得有幾分「不近人情」。</p><p>而且即使社群罵聲連連，官方的態度看起來也十分堅決。</p><p>我甚至不禁懷疑，GitHub Copilot 是否像 Perplexity 那樣，試圖改以企業用戶作為主要 TA。而不再那麼在乎個人用戶的感受——畢竟賺的錢有限。</p><p>以上純屬個人猜測，反正木已成舟，多說無益。接下來聊聊我的替代方案。</p><hr><h2 id="Token-早已過剩😅"><a href="#Token-早已過剩😅" class="headerlink" title="Token 早已過剩😅"></a>Token 早已過剩😅</h2><p>退訂之前，我就隱隱發現 token 有點消耗不過來了！</p><p>如〈<a href="/essential-subscriptions-2025/">2025 我離不開的 8 項付費訂閱</a>〉一文所言，除了 GitHub Copilot，我同時還訂閱了 ChatGPT Plus、Claude Pro、Google AI Pro 三個 20 美元的方案。</p><p>加上我目前正轉職 DevOps，寫程式的量本來就不大。主要是看文件、整理筆記、準備面試，這些任務用現有的訂閱就夠了。</p><p>既然需求下降、價格又變貴，退訂是很自然的選擇——雖然我還是會不捨辣！</p><h2 id="我更推薦哪個？"><a href="#我更推薦哪個？" class="headerlink" title="我更推薦哪個？"></a>我更推薦哪個？</h2><p>如果上述提到的工具你一個都沒有訂閱，而現在考慮要訂閱其中一個試水溫或作為日常的 AI 主力，那我會<strong>優先推薦 ChatGPT Plus</strong>——它也是我<a href="https://www.threads.com/@kyomind.tw/post/DWyWqbugREA">最早訂閱的 AI 聊天服務</a>。</p><p>理由有以下 3+1 點。</p><h3 id="聊天與-Coding-額度獨立計算"><a href="#聊天與-Coding-額度獨立計算" class="headerlink" title="聊天與 Coding 額度獨立計算"></a>聊天與 Coding 額度獨立計算</h3><p>ChatGPT Plus 的額度分成兩種：一般聊天和 Codex。兩者分開計算，不會互相排擠。</p><p>這代表你可以一邊用 ChatGPT 處理工作瑣事、查資料、寫文件，同時開 Codex 跑程式任務，不用擔心聊天把 coding 額度吃光。</p><p>這點 Claude 就比不上了——Claude 的額度是共享的。</p><p>當然，我知道，很多人訂閱它都是衝著 <a href="https://code.claude.com/docs/zh-TW/overview">Claude Code</a> 去的，誰跟你聊天！（我個人是聊滿多的☺️）</p><h3 id="優秀的-Codex-App-使用體驗"><a href="#優秀的-Codex-App-使用體驗" class="headerlink" title="優秀的 Codex App 使用體驗"></a>優秀的 Codex App 使用體驗</h3><p>Codex 有獨立的桌面 app（macOS、Windows 都有），重點是！它的體驗非常好——設計成熟、互動流暢。大大提升了 Codex 這個服務的能見度！</p><p>說來好笑，當初是<a href="https://www.threads.com/@kyomind.tw/post/DWvOTmIAZZS">為了教女友用，結果自己反而用最多</a>。</p><p>隨著 Codex app 的流行，讓 Google 也忍不住<a href="https://www.threads.com/@kyomind.tw/post/DYoE72CgdIX">有樣學樣</a>，把他們家的 Antigravity IDE 從 1.0 的 VS Code fork 版本，直接重構成 2.0 的獨立 app 版本，只能說，真香！</p><p>而且桌面 app 形式，相較於 CLI，對一般人（非開發者）顯然<strong>更加友善且直觀</strong>。</p><h3 id="更大方的-Token-用量"><a href="#更大方的-Token-用量" class="headerlink" title="更大方的 Token 用量"></a>更大方的 Token 用量</h3><p>前面已經算過了，ChatGPT Plus 月費 20 美元，實測最多可以用到約 700 美元等值的 API token，補貼倍數高達 35 倍——這還只是 coding 部分。</p><p>這個數字遠超 Claude Pro 的 20 倍，更不用說 Copilot 那感人的 Flex「補貼」了。</p><h3 id="額外好處：可以養「龍蝦」"><a href="#額外好處：可以養「龍蝦」" class="headerlink" title="額外好處：可以養「龍蝦」"></a>額外好處：可以養「龍蝦」</h3><p>Sam Altman 在 5 月<a href="https://x.com/sama/status/2050357911915028689">宣布</a>，ChatGPT 訂閱可以直接接入 OpenClaw 使用。</p><p><a href="https://openclaw.ai/">OpenClaw</a> 是一個開源的 AI agent 框架，可以連結各種 LLM，在 WhatsApp、Telegram、Slack 等平台上自動執行任務——管日曆、發信、整理檔案、寫程式都行。</p><p>因為它的 logo 是一隻龍蝦，所以社群俗稱「養龍蝦」。</p><p>現在 ChatGPT Plus 就能跑，不用另外付錢，算是額外的福利。如此一來，就算你不寫程式，還是可以拿來<strong>聊天兼養蝦</strong>！</p><p>而且據我所知，Claude 和 Google 在這方面都是不鼓勵的，如果把付費訂閱帳號拿來養龍蝦，帳號可能被 ban！</p><hr><h2 id="工具只是工具，不要依戀它"><a href="#工具只是工具，不要依戀它" class="headerlink" title="工具只是工具，不要依戀它"></a>工具只是工具，不要依戀它</h2><p>很長一段時間裡，我都是 GitHub Copilot 的<strong>忠實用戶</strong>。</p><p>無論是 IDE 競品 <a href="/cursor/">Cursor</a> 或 Windsurf，還是如旋風一般席捲開發圈的 Claude Code，都沒有動搖我對它的忠誠。</p><p><strong>我始終以 GitHub Copilot 作為我的開發主力。</strong></p><p>直到這一次的變動。</p><p>無奈退訂之後，我的想法<strong>似乎也跟著改變了</strong>——工具退回了工具該有的角色。</p><p>Claude Code 很好用，Codex 也不錯。哪個順手用哪個，沒有非得選邊站的理由。</p><h3 id="通用-vs-專用"><a href="#通用-vs-專用" class="headerlink" title="通用 vs 專用"></a>通用 vs 專用</h3><p>我比較不喜歡的是那種 <strong>tool-specific</strong>（只有特定工具才有）的功能。</p><p>比如 Copilot 有個「<a href="https://vscode.com.tw/docs/copilot/agents/memory">記憶</a>」功能，會在 repo 底下建一個 <code>memories</code> 資料夾。問題是，這個資料夾只有 GitHub Copilot 會用，其他 agent 根本不認識。</p><p>什麼爛東西XD（好啦，<a href="https://docs.github.com/en/copilot/tutorials/customization-library/prompt-files">prompt files</a> 就是我覺得很成功的設計，我幾乎每個 repo 都有使用）</p><p>相較之下，我更偏好<strong>通用的機制</strong>，像是 <a href="https://agents.md/">AGENTS.md</a>、<a href="https://code.claude.com/docs/zh-TW/hooks-guide">hooks</a>（現在各家都有了，只是設定略有不同）、<a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a>、<a href="https://agentskills.io/home">agent skills</a> 等。這些東西不管用哪個工具都能用，換工具時不會被綁住。</p><blockquote><p>相關文章：<a href="/agent-hooks/">為你的 AI Agent 掛上 Hooks 吧！</a></p></blockquote><p>正因為工具可以互換，所以沒必要為一個定價不合理的服務堅持。</p><hr><p>如果 10 美元的 GitHub Copilot Pro 方案能再大方一點，我還是會考慮續訂。</p><p>但現在，我才不要💩</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/code-and-me.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;AI 輔助程式設計工具 &lt;a href=&quot;https://github.com/features/copilot&quot;&gt;GitHub Copilot&lt;/a&gt; 在今年 6 月 1 號全面改制為 &lt;a href=&quot;https://github.blog/news-insights/company-news/github-copilot-is-moving-to-usage-based-billing/&quot;&gt;usage-based billing&lt;/a&gt;，也就是&lt;strong&gt;按用量計費&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;作為 &lt;a href=&quot;/github-copilot/&quot;&gt;2022&lt;/a&gt; 年就開始付費的老用戶，我則趕在 5 月 20 號「大限」之前，退訂了原本將在 8 月 16 號到期的 Pro+ 年約，這樣可以拿回一定比例的剩餘退款。&lt;/p&gt;
&lt;p&gt;改制到現在已逾兩週，社群反應&lt;a href=&quot;https://www.reddit.com/r/github/comments/1ttcpw0/github_copilots_new_creditbased_pricing_is/&quot;&gt;非常激烈&lt;/a&gt;，尤其是個人用戶。&lt;/p&gt;
&lt;p&gt;本文分享我決定退訂的判斷與理由，以及我的替代方案。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/code-and-me.png" type="image"/>
    
    
    <category term="心得" scheme="https://blog.kyomind.tw/categories/%E5%BF%83%E5%BE%97/"/>
    
    
    <category term="AI 工具" scheme="https://blog.kyomind.tw/tags/AI-%E5%B7%A5%E5%85%B7/"/>
    
    <category term="GitHub Copilot" scheme="https://blog.kyomind.tw/tags/GitHub-Copilot/"/>
    
    <category term="ChatGPT" scheme="https://blog.kyomind.tw/tags/ChatGPT/"/>
    
    <category term="付費訂閱" scheme="https://blog.kyomind.tw/tags/%E4%BB%98%E8%B2%BB%E8%A8%82%E9%96%B1/"/>
    
  </entry>
  
  <entry>
    <title>我 40 歲，主動離職，All in DevOps</title>
    <link href="https://blog.kyomind.tw/all-in-on-devops/"/>
    <id>https://blog.kyomind.tw/all-in-on-devops/</id>
    <published>2026-06-14T05:03:31.000Z</published>
    <updated>2026-08-03T12:29:06.927Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20260614-143640.jpg"></p><p>2018 年夏，我剛從資策會結訓不久，參加了一場同為「<a href="https://www.ispan.com.tw/longterm/JJBDSET/">大數據班</a>」學長姐們的聚餐。想當然耳，只有還繼續留在軟體這個領域的人才會想出席吧！</p><p>那時正處於「<strong>人生的暑假</strong>」——結訓後不知道該何去何從，對程式的興趣普通，不清楚自己能做什麼，所以就去了，聽聽前輩們的意見也好。</p><p>會上遇到了一個正在當 DevOps 的學長，和他聊了許多，幾天後我才重新振作，繼續自學程式，隔年終於找到工作，開始了我的軟體開發之路。</p><hr><p>從資料工程師到 Python 後端，隨著時間的推移，我自認對程式充滿熱情。</p><p>幾年前和女友介紹什麼是 <a href="https://zh.wikipedia.org/zh-tw/DevOps">DevOps</a>，她聽完後不禁問我：</p><blockquote><p>那你會不會想當 DevOps？</p></blockquote><p>我記得當時的回答是：</p><blockquote><p>可以考慮啦！但我現在<strong>更喜歡開發</strong>，或許等我 40 歲以後，新技術學不動了，可能就會「轉」DevOps 了。</p></blockquote><p>現在想想，那時真是天真吶！DevOps 豈是你想轉就轉的？</p><p>然而，沒想到的是：「40 歲轉 DevOps」這句話竟然一語成讖——只是方式完全不同😂</p><p><strong>2026 年 3 月，我主動離職，全力轉向 DevOps</strong>。</p><p>本文是「轉職 DevOps 三部曲」的第一篇，有關<strong>起點與決心</strong>。</p><span id="more"></span><hr><h2 id="你喜歡改善開發流程嗎？"><a href="#你喜歡改善開發流程嗎？" class="headerlink" title="你喜歡改善開發流程嗎？"></a>你喜歡改善開發流程嗎？</h2><blockquote><p>我很喜歡。</p></blockquote><p>不知是<a href="/orange-days-02/">法律系出身</a>緣故，還是個性使然——<strong>我並不喜歡隨心所欲、雜亂無章地做事</strong>。</p><p>而第二份工作恰恰給了我一個<strong>絕佳的舞台</strong>。</p><p>如同〈<a href="https://ithelp.ithome.com.tw/articles/10352694">卷 5：Python 現代開發工具介紹</a>〉這篇文章中提到的，能一步步落實這些現代化的 Python 開發實踐，是件<strong>幸福</strong>的事。</p><h3 id="從零開始的現代化開發流程"><a href="#從零開始的現代化開發流程" class="headerlink" title="從零開始的現代化開發流程"></a>從零開始的現代化開發流程</h3><p>在這份後端工作中，我主導了整個團隊的<strong>開發流程建設</strong>，從零開始導入了：Poetry、pyenv、Ruff、pre-commit、Mypy、Python docstring 規範、pytest 單元測試、code review 流程等。也為此寫了<a href="/tags/Code-Formatting/">不少文章</a>。</p><p>可以主導這些，倒不是因為我最資深，而是因為我<strong>最在乎</strong>。此外，更要感謝後端同事們的配合，那是我轉職以來最快樂的一段時光。</p><p>有了這些流程與規範，我們至少不必在 code review 時大眼瞪小眼，為了不必要的低級問題（比如 import 順序不符合 <a href="https://peps.python.org/pep-0008/">PEP 8</a>）傷神。</p><p>其中的關鍵是：有些制度一旦建立，可以省下<strong>很多人的時間</strong>。</p><p>這段時光，可算是我的 <strong>DevOps 啟蒙</strong>，讓我第一次感受到<strong>流程與規範的重要性</strong>。</p><hr><h2 id="刺激-2025"><a href="#刺激-2025" class="headerlink" title="刺激 2025"></a>刺激 2025</h2><p>2025 年，AI 輔助開發的進展快得嚇人。</p><p>年初，AI coding agent 還沒那麼稱手好用，寫出來的東西常常需要大幅修改，但擁有視覺能力（vision）的模型已經逐漸成為標配。</p><p>到了年中，工具成熟的速度遠超預期——GitHub Copilot 推出 Agent 模式，AI 不再只是補全程式碼，而是能<strong>理解整個專案的脈絡</strong>，主動完成跨檔案的修改。</p><p>年底，AI 已經能透過自然語言互動，幾分鐘內完成過去需要工程師花好幾個小時才能寫好的功能。</p><p>現在再回頭看之前寫的這篇〈<a href="/cursor/">Cursor IDE 心得：三大亮點與三個阻礙</a>〉，不禁感嘆，那簡直是「上古時代」的事了——其實才過了快 2 年而已😅</p><h2 id="AI-正在重寫開發生態"><a href="#AI-正在重寫開發生態" class="headerlink" title="AI 正在重寫開發生態"></a>AI 正在重寫開發生態</h2><p>作為 2022 年就開始使用 GitHub Copilot 的老用戶，我的 AI 輔助開發演進史如下：</p><ul><li><strong>2022 年</strong>：開始嘗試 <a href="/github-copilot/">GitHub Copilot</a>，但說真的感受普通。</li><li><strong>2022 年底</strong>：ChatGPT 橫空出世，改成問 ChatGPT，IDE 複製貼上。</li><li><strong>2023 年</strong>：在 IDE 中使用 AI 自動補完，tab、tab、tab…，在 AI 的加持之下，這個自動提示的品質可比 2022 年強多了。</li><li><strong>2024 年</strong>：在 IDE 的 Chat 視窗中直接問 AI，透過內建功能自動貼上；開始有專案 RAG，可以<strong>直接對專案內容進行提問</strong>。這就是前述 Cursor 文章的背景。</li><li><strong>2025 年</strong>：透過自然語言對話，讓 AI 寫程式碼，自己主要負責 review。</li></ul><p>短短數年間，軟體開發已<strong>不再是我們過去熟悉的那個模樣</strong>——<a href="https://zh.wikipedia.org/zh-tw/Vibe_coding">Vibe Coding</a> 大行其道，任何人都可以「寫」程式了。</p><p>我不禁有感而發，留下這篇〈<a href="/vibe-coding/">Vibe Coding 與人類的時代</a>〉，表達<strong>內心的不安與悸動</strong>。</p><p>身邊越來越多開發者開始感受到同一件事：</p><blockquote><p>如果 AI 能接手更多實作，那工程師的價值到底還剩下什麼？</p></blockquote><p>這個問題，每個人有自己的答案。可以確定的是，從 2025 下半年開始，我已<a href="/about/#AI-%E6%99%82%E4%BB%A3%E7%9A%84%E9%96%8B%E7%99%BC%E8%80%85">不再自己動手寫程式</a>。</p><hr><h2 id="Application-的極限"><a href="#Application-的極限" class="headerlink" title="Application 的極限"></a>Application 的極限</h2><p>第三份工作，我首次進到了有完整 SRE 團隊的公司，開發 LLM App 專案，可以想成是企業內部版的 ChatGPT。</p><p>我所在的後端團隊負責寫 application，SRE 則用 <a href="https://kubernetes.io/">Kubernetes</a> 部署與維運。雖然分工明確，但後端也需要透過 Jenkins 觸發部署、登入 <a href="https://www.rancher.com/">Rancher</a> 查看 Pod log 來排查問題。這讓我逐漸意識到：application 寫好，<strong>不代表</strong>服務就會穩定運作。</p><p>有些時候不一定是程式邏輯出錯，而是環境、部署、微服務之間的<strong>協調</strong>問題。有時則是 <a href="https://ai.azure.com/">AI Foundry</a> 或其他 infra 組件出了狀況。</p><p>這些東西——<strong>尤其是 Kubernetes</strong>——我開始接觸，但理解仍然有限。</p><p>以前都是 VM 部署，然後 <a href="https://docs.docker.com/compose/">Docker Compose</a>，這是我第一次深深感受到，<strong>服務遠不止是寫程式而已</strong>。</p><p>部署並不是配角。而當下的我只懂應用層，這是一個<strong>明顯的局限</strong>。</p><h2 id="回到入職之前"><a href="#回到入職之前" class="headerlink" title="回到入職之前"></a>回到入職之前</h2><p>其實在 2025 年 3 月入職前，我就有考慮要學習 DevOps 相關技能。</p><p>因此在面試那一波後端職缺時，都會特別問到：「你們有沒有 SRE 團隊？DevOps 流程怎麼跑？」——這是我挑選職缺的重要考量之一。</p><p>當時的想法是：「我已具備一定後端經驗，如果再多學些 DevOps 技能，像是 CI&#x2F;CD、雲端架構等，就能成為一個<strong>更全面的後端開發者</strong>。」</p><p>所以我選了這份工作：有完整 SRE 團隊，同時是開發 LLM App——目前正流行，也是自己很想接觸的領域。</p><p>但不得不承認，那時的心態還是「<strong>後端才是王道，DevOps 只是輔助</strong>」。</p><p>看著對面的 SRE leader，每天對著不同的 YAML 檔搞部署。總覺得那<strong>不是我要的</strong>——我只是想「多學一點技能」而已。</p><hr><h2 id="八月的一場聚會"><a href="#八月的一場聚會" class="headerlink" title="八月的一場聚會"></a>八月的一場聚會</h2><p>2025 年 8 月，我參加了一場軟體工程師聚會。</p><p>遇到幾個年資相近的後端，彼此分享了不少後端甘苦談。聊著聊著，話題自然而然轉向了一個靈魂拷問：「<strong>職涯滿 5 年之後</strong>，下一步是什麼？」</p><p>我們好像都遇到了一個「瓶頸」——這似乎是軟體工程師的普遍現象。</p><p>職涯的前 5 年，你可以自由探索、發揮，學一堆技能，但滿 5 年之後，市場可能會用<strong>完全不一樣的標準</strong>來看待你：你要資深、要擁有深刻的實戰經驗。</p><p>屆時若沒有一個相對鮮明的<strong>角色定位</strong>，你很難說出自己能帶來什麼不一樣的價值。</p><p>這場聚會，成了我軟體職涯的<strong>重要轉折點</strong>。</p><hr><h2 id="收起「扮家家酒」的決心"><a href="#收起「扮家家酒」的決心" class="headerlink" title="收起「扮家家酒」的決心"></a>收起「扮家家酒」的決心</h2><p>這次聚會讓我意識到，原先那種「既要、又要」、「後端才是主體、DevOps 只是輔助」的心態，雖然不能說是錯，但它可能會讓我最終一事無成，依舊是個平庸的後端。</p><p>這不是我想要的模樣。<strong>要玩，就要 all in</strong>。</p><p>但此刻要做出重大改變，顯有困難，而且基於團隊與職責分工，作為後端人員，我無法接觸到完整的 infra，這是一個瓶頸。</p><blockquote><p>那怎麼辦？</p></blockquote><p>自己弄！</p><h3 id="WeaMind-上線"><a href="#WeaMind-上線" class="headerlink" title="WeaMind 上線"></a>WeaMind 上線</h3><p>第一步是繼續完成我的 <a href="https://github.com/kyomind/WeaMind">WeaMind</a>：一個查詢台灣天氣的 LINE Bot。</p><p>有興趣可參考〈<a href="/weamind/">WeaMind 專案解析：從單機 LINE Bot 到 K8s 叢集</a>〉一文。</p><p>這個專案其實從 5 月就開始做了，但常常三天打魚兩天曬網，有一搭沒一搭地進行。說來神奇，聚會結束之後，它就快速開展了XD</p><p>最終花了約 150 小時，趕在 9 月底前上線。</p><p>你說，為什麼要做這個？這跟 DevOps 有關嗎？當然是有後話的！</p><h3 id="通過-AWS-SAA-認證"><a href="#通過-AWS-SAA-認證" class="headerlink" title="通過 AWS SAA 認證"></a>通過 AWS SAA 認證</h3><p>10 月初的雙十連假，我開始準備 AWS 的 <a href="https://aws.amazon.com/tw/certification/certified-solutions-architect-associate/">SAA</a>。過程中接觸到 VPC、IAM、ELB、Lambda、S3 等，讓我對雲端架構有了系統性的理解。</p><p>學著學著，興趣越來越濃。我發現自己不只是在「補技能」，而是窺見了一個<strong>從未知曉的新世界</strong>。</p><p>後端要辛苦手刻的 <a href="https://ithelp.ithome.com.tw/articles/10267454">db 主從複製</a>，雲端早就服務化了！不得不說，有一種「已知用火」的興奮感🤩</p><p>一邊工作一邊準備，總計花了 105 小時，終於在 12 月 15 日<a href="https://www.credly.com/badges/b23af905-9523-41cf-ad93-02106c6d1be0">通過了 SAA 考試</a>。</p><p>此時我轉職 DevOps 的<strong>篤定感</strong>，已從 8 月時的 20-30% 大幅成長到 60-70%。</p><h3 id="遷移到-K3s"><a href="#遷移到-K3s" class="headerlink" title="遷移到 K3s"></a>遷移到 K3s</h3><p>通過 SAA 後，我「休息」了一星期，接著開始學習 Kubernetes（K8s）。</p><p>哪怕已有近 6 年的後端開發經驗，說真的，<strong>剛開始我很難上手</strong>，看 Udemy 的線上課也覺得成效不佳。</p><p>於是我決定——<strong>直接實作</strong>：把 WeaMind 從單機部署遷移到 <a href="https://k3s.io/">K3s</a> 叢集。這剛好是一個絕佳的練習機會。</p><blockquote><p>相關文章：<a href="/k3s-for-weamind/">K3s 是什麼？為什麼我選擇用 K3s 部署 WeaMind</a></p></blockquote><p>在 AI 輔助下，從頭開始在 <a href="https://blog.kyomind.tw/hetzner/">Hetzner</a> 上建立 <strong>Kubernetes 叢集</strong>：開 VM、架私有網路、加 Node、寫 Deployment、設定 Ingress、搞定 TLS 憑證等。</p><p>過程中踩了不少坑——比如節點竟然預設吃公網 IP！——但也因此對 K8s 的運作有了更多了解。</p><p>2026 年 1 月底，<a href="https://github.com/kyomind/weamind-infra">K3s 版本的 WeaMind</a> 上線。</p><blockquote><p>相關文章：<a href="/weamind-infra/">WeaMind Infra 介紹：VM、Load Balancer 與雲端架構</a></p></blockquote><p>此時，我轉職 DevOps 的決心，已經來到 80% 以上——足夠了。</p><hr><h2 id="我離職了"><a href="#我離職了" class="headerlink" title="我離職了"></a>我離職了</h2><p>2026 年 3 月，我主動申請離職。</p><p>因為我知道，一邊工作一邊用業餘時間學習是<strong>有極限</strong>的。想要真正搞懂 Kubernetes，我需要一段<strong>更完整、不被打斷的時間投入</strong>。</p><p>雖然裸辭讓人不安，但從事後看來，這個決定是正確的——如今的我對 Kubernetes，有著<strong>遠超 3 個月前的理解</strong>，不過這些算是第二篇的內容了。</p><p>如果 AI 能接手越來越多的實作，那軟體工程師的價值究竟是什麼？這個問題，每個人有自己的答案。</p><p>而此時此刻，我的答案是：</p><blockquote><p><strong>擁抱 infra，all in DevOps。</strong></p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/img-20260614-143640.jpg&quot;&gt;&lt;/p&gt;
&lt;p&gt;2018 年夏，我剛從資策會結訓不久，參加了一場同為「&lt;a href=&quot;https://www.ispan.com.tw/longterm/JJBDSET/&quot;&gt;大數據班&lt;/a&gt;」學長姐們的聚餐。想當然耳，只有還繼續留在軟體這個領域的人才會想出席吧！&lt;/p&gt;
&lt;p&gt;那時正處於「&lt;strong&gt;人生的暑假&lt;/strong&gt;」——結訓後不知道該何去何從，對程式的興趣普通，不清楚自己能做什麼，所以就去了，聽聽前輩們的意見也好。&lt;/p&gt;
&lt;p&gt;會上遇到了一個正在當 DevOps 的學長，和他聊了許多，幾天後我才重新振作，繼續自學程式，隔年終於找到工作，開始了我的軟體開發之路。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;從資料工程師到 Python 後端，隨著時間的推移，我自認對程式充滿熱情。&lt;/p&gt;
&lt;p&gt;幾年前和女友介紹什麼是 &lt;a href=&quot;https://zh.wikipedia.org/zh-tw/DevOps&quot;&gt;DevOps&lt;/a&gt;，她聽完後不禁問我：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;那你會不會想當 DevOps？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我記得當時的回答是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以考慮啦！但我現在&lt;strong&gt;更喜歡開發&lt;/strong&gt;，或許等我 40 歲以後，新技術學不動了，可能就會「轉」DevOps 了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;現在想想，那時真是天真吶！DevOps 豈是你想轉就轉的？&lt;/p&gt;
&lt;p&gt;然而，沒想到的是：「40 歲轉 DevOps」這句話竟然一語成讖——只是方式完全不同😂&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2026 年 3 月，我主動離職，全力轉向 DevOps&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文是「轉職 DevOps 三部曲」的第一篇，有關&lt;strong&gt;起點與決心&lt;/strong&gt;。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/img-20260614-143640.jpg" type="image"/>
    
    
    <category term="Self" scheme="https://blog.kyomind.tw/categories/Self/"/>
    
    
    <category term="軟體工程師" scheme="https://blog.kyomind.tw/tags/%E8%BB%9F%E9%AB%94%E5%B7%A5%E7%A8%8B%E5%B8%AB/"/>
    
    <category term="人生思考" scheme="https://blog.kyomind.tw/tags/%E4%BA%BA%E7%94%9F%E6%80%9D%E8%80%83/"/>
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
  </entry>
  
  <entry>
    <title>Kubernetes 視覺化工具怎麼選？初學者的 GUI、TUI 指南</title>
    <link href="https://blog.kyomind.tw/kubernetes-gui-tui-guide/"/>
    <id>https://blog.kyomind.tw/kubernetes-gui-tui-guide/</id>
    <published>2026-04-12T09:30:22.000Z</published>
    <updated>2026-06-20T07:06:10.078Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20260412-174100.png" alt="圖片來源：Headlamp GitHub"><span class="cap">圖片來源：Headlamp GitHub</span></p><p>前陣子讀《<a href="https://readmoo.com/book/210309079000101">從異世界歸來發現只剩自己不會 Kubernetes</a>》時，作者在開篇不久就推薦了 Kubernetes Dashboard。</p><p>我立刻燃起了興趣！畢竟我本來就是 GUI 愛好者。</p><p>尤其 Kubernetes 這種東西，一開始光是名詞就夠多了。Pod、Deployment、Service、Node、Namespace，還沒開始排查問題，光是先建立畫面感就已經很吃力。</p><p>如果有個視覺化工具，對初學者想必會很有幫助，本書作者也是這麼想的。</p><p>本文想回答的問題是：「現在如果想用視覺化方式看 Kubernetes 叢集，該選什麼？」</p><span id="more"></span><p>討論範圍只限用來看叢集狀態的 GUI 和 TUI。像 Prometheus、Grafana、stern 這類不同範疇的工具，就先不展開。</p><hr><h2 id="Kubernetes-Dashboard：時代的眼淚"><a href="#Kubernetes-Dashboard：時代的眼淚" class="headerlink" title="Kubernetes Dashboard：時代的眼淚"></a>Kubernetes Dashboard：時代的眼淚</h2><p><a href="https://github.com/kubernetes-retired/dashboard">Kubernetes Dashboard</a> 是官方推出的 Web UI，由 Kubernetes 社群維護，部署在 cluster 內，並透過瀏覽器存取。</p><p>我照著書中的說明去裝了，也實際把它跑起來了，如下圖：</p><p><img src="https://img.kyomind.tw/img-20260410-151325.png" alt="Kubernetes Dashboard"><span class="cap">Kubernetes Dashboard</span></p><p>然而，這個專案已經在 2026 年 1 月 21 日被官方<strong>封存</strong>了。</p><p>實際裝過一次之後，我也必須承認，它真的<strong>不算友好</strong>。</p><h3 id="麻煩一：自己部署進-cluster"><a href="#麻煩一：自己部署進-cluster" class="headerlink" title="麻煩一：自己部署進 cluster"></a>麻煩一：自己部署進 cluster</h3><p>首先，它不是下載即用。你得把一整套元件<strong>手動部署到自己的 cluster</strong>，即便用 Helm 這種最簡單的方式，也需要一連串步驟才能裝好。</p><p>而且這不只是「多做幾步」那麼簡單——它會<strong>持續佔用</strong> cluster 的資源。</p><h3 id="麻煩二：每次連線都要重來一輪"><a href="#麻煩二：每次連線都要重來一輪" class="headerlink" title="麻煩二：每次連線都要重來一輪"></a>麻煩二：每次連線都要重來一輪</h3><p>更煩的是後續使用。每次要開 Dashboard，你得先跑一次 port-forward，然後透過指令產生 token。</p><p>而且 token 的效期很短——用 <code>kubectl create token</code> 產生的話，預設只有一小時，過了就得重拿。長效 token 則要用另一套流程來產生。</p><p>相較之下，像 Headlamp 這種直接吃 kubeconfig 的桌面 App，進入門檻明顯低得多。</p><h3 id="舊時代的退場"><a href="#舊時代的退場" class="headerlink" title="舊時代的退場"></a>舊時代的退場</h3><p>只能說，Dashboard 這種 browser-based、in-cluster 的思路，確實愈來愈不符合現在大家使用 Kubernetes 的方式。</p><p>也難怪它會被官方封存了。</p><hr><h2 id="現役選項一覽"><a href="#現役選項一覽" class="headerlink" title="現役選項一覽"></a>現役選項一覽</h2><p>講完退場的，接下來進入現役選項。本文要介紹的工具如下：</p><table><thead><tr><th>工具</th><th>類型</th><th>特色</th><th>適合情境</th></tr></thead><tbody><tr><td>Headlamp</td><td>GUI</td><td>輕量、直接吃 kubeconfig、由 Kubernetes SIG 維護</td><td>個人學習、單叢集、想要 GUI 輔助</td></tr><tr><td>Lens</td><td>GUI</td><td>功能完整、整合度高、視覺化強</td><td>想要 all-in-one 體驗、不介意工具較重</td></tr><tr><td>Rancher</td><td>GUI</td><td>多叢集管理、權限與平台治理</td><td>企業、平台團隊、多叢集場景</td></tr><tr><td>K9s</td><td>TUI</td><td>快、輕、排查導向</td><td>日常巡檢、快速觀察、鍵盤工作流</td></tr></tbody></table><hr><h2 id="Headlamp：Dashboard-接班人"><a href="#Headlamp：Dashboard-接班人" class="headerlink" title="Headlamp：Dashboard 接班人"></a>Headlamp：Dashboard 接班人</h2><p>Kubernetes Dashboard 被封存後，官方在 repo 中建議改用 <a href="https://headlamp.dev/">Headlamp</a> 作為替代方案。它目前由 Kubernetes SIG 維護，是一條有延續性的路線。</p><p>實際用過之後，不難理解它為什麼會被指定為替代選項。</p><p><img src="https://img.kyomind.tw/img-20260410-191937.png" alt="Headlamp UI"><span class="cap">Headlamp UI</span></p><p>Headlamp 一樣支援透過 Helm 以 <a href="https://headlamp.dev/docs/latest/installation/in-cluster/">in-cluster</a> 的方式部署成 Web UI。</p><p>不過對大多數人而言，最直覺的用法還是桌面版 app：可直接讀取本機的 kubeconfig 連線資訊，不需要先往 cluster 裡裝一套東西，有效降低了使用門檻。</p><p>對「<strong>我只是想看懂叢集裡有什麼</strong>」這個需求來說，這條路明顯簡單得多。</p><p>更別說它一樣能夠操作資源，但通常我不會這麼做😅。操作資源我會乖乖使用 <code>kubectl</code>。</p><p>我未必認為它的畫面呈現有全方位超越 Dashboard，但它至少把安裝與登入的摩擦感降了很多。</p><p>有了 Headlamp，你可以很快地點進 Pod、Deployment、Node，看資源關係、事件、YAML，先把整個 cluster 的結構感建立起來。對還在學 Kubernetes 的人來說，這種畫面感很有價值。</p><p>所以如果你的需求是：單人、單叢集、學習導向、想保留 GUI 輔助，那 Headlamp 幾乎就是目前最合理的起點。</p><hr><h2 id="Lens：完整，但更重"><a href="#Lens：完整，但更重" class="headerlink" title="Lens：完整，但更重"></a>Lens：完整，但更重</h2><p><a href="https://lenshq.io/">Lens</a> 是由 Mirantis 維護的 Kubernetes 桌面客戶端，也是目前功能最完整的選項之一。</p><p>比起 Headlamp，Lens 的整合度與周邊都更完整：內建的 metrics 視覺化、整合式 terminal、多 cluster workspace，以及比較成熟的 extension 生態，這些都是它長年累積下來的優勢。</p><p>對於想用一個工具滿足多種需求的人來說，這種體驗是有吸引力的。</p><p>但它的缺點也很明顯，就是比較「<strong>重</strong>」。不只是執行層面的重，也包括整個工具帶有比較強的<strong>商業產品感</strong>。雖然有免費版可以用，但你打開它的時候，感受上比較像是進入一個完整產品的生態，而不只是開了一個輕量工具。</p><p>更多關於 Lens 的介紹，可參考以下文章：</p><blockquote><p>延伸閱讀：<a href="https://ithelp.ithome.com.tw/articles/10325689">可觀測性宇宙的第八天 - Kubernetes Lens 推坑 K8S GUI 神器介紹</a></p></blockquote><hr><h2 id="Rancher：不只是-cluster-viewer"><a href="#Rancher：不只是-cluster-viewer" class="headerlink" title="Rancher：不只是 cluster viewer"></a>Rancher：不只是 cluster viewer</h2><p><a href="https://www.rancher.com/">Rancher</a> 是由 SUSE 維護的開源平台，跟我<a href="/k3s-for-weamind/">之前文章</a>介紹過的 K3s 是同一家出品。</p><p>它的定位跟前面兩個桌面工具不太一樣。如果只是把它跟 Headlamp、Lens 一起當成「看叢集狀態的工具」，就有點小看它了。</p><p>先用一張表看清楚差異：</p><table><thead><tr><th></th><th>Headlamp &#x2F; Lens</th><th>Rancher</th></tr></thead><tbody><tr><td>定位</td><td>桌面客戶端</td><td>平台級管理介面</td></tr><tr><td>部署方式</td><td>本機安裝，直接吃 kubeconfig</td><td>需要部署到 cluster 或獨立主機上</td></tr><tr><td>使用對象</td><td>個人開發者、學習者</td><td>平台團隊、多叢集管理者</td></tr><tr><td>核心能力</td><td>查看與操作叢集資源</td><td>多叢集治理、權限控管、應用發佈、團隊協作</td></tr></tbody></table><p>Rancher 真正的主場，是平台團隊、多叢集、權限控管這些工作。它解決的是<strong>治理</strong>，而不僅僅是「看懂叢集」這樣的需求。</p><p>Lens 和 Rancher 我在工作上都用過。就個人使用感受來說，Rancher 的 UI 我比較能接受；Lens 那種一看就知道是用 Electron 寫的笨重感，如果可以，我真的不想用XD</p><hr><h2 id="K9s：TUI-的首選"><a href="#K9s：TUI-的首選" class="headerlink" title="K9s：TUI 的首選"></a>K9s：TUI 的首選</h2><p><a href="https://k9scli.io/">K9s</a> 是一個開源的 Kubernetes TUI 工具。所謂 TUI，就是「<strong>Terminal UI</strong>」——在終端機裡提供類似 GUI 的視覺化介面，但以鍵盤操作為主。像 htop（系統監控）、lazygit（Git 操作），都是經典的 TUI 工具。</p><p>如果說 GUI 比較像是幫你<strong>建立畫面感</strong>，那 TUI 更像是幫你<strong>建立操作節奏</strong>——K9s 的價值就在這裡。它快、輕，而且非常排查導向。</p><p>你可以透過它快速切換 namespace、查看 Pod 的狀態、進入容器的 terminal，甚至直接在裡面編輯資源的 YAML。</p><p>跟 Headlamp、Lens 一樣，它也是本機安裝、直接吃 kubeconfig，不需要在 cluster 裡部署任何東西。</p><p>對已經有一點 Kubernetes 手感、也不排斥終端機的人來說，K9s 很容易變成日常主力，因為它剛好補上了 GUI 不擅長的那一面。</p><hr><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p><code>kubectl</code> 當然是最重要的，這點無庸置疑。</p><p>GUI 和 TUI 的價值在於，它們讓初學者可以先透過比較友善的介面建立全局感，以更低的認知負擔熟悉 Kubernetes。</p><p>所以如果你問我，Kubernetes 視覺化工具，該從哪個開始？</p><p>那就是 <strong>Headlamp</strong>！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/img-20260412-174100.png&quot; alt=&quot;圖片來源：Headlamp GitHub&quot;&gt;&lt;/p&gt;
&lt;p&gt;前陣子讀《&lt;a href=&quot;https://readmoo.com/book/210309079000101&quot;&gt;從異世界歸來發現只剩自己不會 Kubernetes&lt;/a&gt;》時，作者在開篇不久就推薦了 Kubernetes Dashboard。&lt;/p&gt;
&lt;p&gt;我立刻燃起了興趣！畢竟我本來就是 GUI 愛好者。&lt;/p&gt;
&lt;p&gt;尤其 Kubernetes 這種東西，一開始光是名詞就夠多了。Pod、Deployment、Service、Node、Namespace，還沒開始排查問題，光是先建立畫面感就已經很吃力。&lt;/p&gt;
&lt;p&gt;如果有個視覺化工具，對初學者想必會很有幫助，本書作者也是這麼想的。&lt;/p&gt;
&lt;p&gt;本文想回答的問題是：「現在如果想用視覺化方式看 Kubernetes 叢集，該選什麼？」&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/img-20260412-174100.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="開箱評論" scheme="https://blog.kyomind.tw/tags/%E9%96%8B%E7%AE%B1%E8%A9%95%E8%AB%96/"/>
    
  </entry>
  
  <entry>
    <title>K3s 是什麼？為什麼我選擇用 K3s 部署 WeaMind</title>
    <link href="https://blog.kyomind.tw/k3s-for-weamind/"/>
    <id>https://blog.kyomind.tw/k3s-for-weamind/</id>
    <published>2026-03-29T04:54:39.000Z</published>
    <updated>2026-07-14T09:12:29.107Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png"></p><blockquote><p>📌 這是 <a href="/weamind-series/">WeaMind 系列</a> 的第 6 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p>「<strong>想學 Kubernetes，要用什麼工具？</strong>」這是我在轉向 DevOps 時，必須回答的問題。</p><p>你可能拿到的標準答案是：「<strong>用 Minikube 或 Kind 在本機開個環境，先跑起來再說</strong>」。這當然沒錯，對多數人來說是合理的起點。但對我而言，問題則複雜一些。</p><p>這篇文章針對「<strong>想自己建 Kubernetes 叢集，但又不想搞得太複雜</strong>」的情境，說明 K3s 是什麼、適合誰，以及我為什麼最後選擇它。</p><span id="more"></span><hr><h2 id="Minikube-和-Kind：合理的工具，但不是我要的"><a href="#Minikube-和-Kind：合理的工具，但不是我要的" class="headerlink" title="Minikube 和 Kind：合理的工具，但不是我要的"></a>Minikube 和 Kind：合理的工具，但不是我要的</h2><p>學習 Kubernetes 的最佳起手式，無疑就是 <a href="https://minikube.sigs.k8s.io/">Minikube</a> 或 <a href="https://kind.sigs.k8s.io/">Kind</a> 這兩個工具。</p><p>它們都是專為在本機快速建立 Kubernetes 環境而設計的，安裝簡單、資源需求低，很適合初學者。</p><p>如果你只是想練習 <code>kubectl</code> 的指令、跑幾個 Deployment 看看效果，這兩個工具已經足夠。可謂進入門檻低、環境乾淨、不用花錢，一台電腦就能搞定。</p><h3 id="方便的代價"><a href="#方便的代價" class="headerlink" title="方便的代價"></a>方便的代價</h3><p>但為了<strong>方便與降低門檻</strong>，它們在架構上都存在著<strong>一定程度的簡化</strong>：網路行為、多節點環境、儲存層，這些都和真實 production 環境有差距。</p><p>這並非缺點，只是<strong>設計上的取捨</strong>——為了在本機好用，犧牲了一些真實性。</p><h3 id="我需要更多真實感"><a href="#我需要更多真實感" class="headerlink" title="我需要更多真實感"></a>我需要更多真實感</h3><p>但對我來說，這個取捨剛好<strong>與我的學習目標衝突</strong>。我準備轉職 DevOps，想多了解建置過程本身：節點怎麼加入叢集、網路介面怎麼配置、Ingress 怎麼和 Load Balancer 串起來等等。</p><p>用真實的 VM 學習，這些議題會<strong>更具體些</strong>，不被環境提前幫你簡化掉。</p><p>剛好我也已經在用 <a href="/hetzner/">Hetzner Cloud</a>，開一台最小規格的 VM 只需一個月數歐元。有這樣的條件，用真實環境學習似乎是<strong>更自然的選擇</strong>。</p><p>簡言之，不是因為 Minikube 或 Kind 不好，而是對我的目標而言，這樣的做法能得到<strong>更接近現實</strong>的學習效果。</p><hr><h2 id="三條-K8s-叢集建置路線"><a href="#三條-K8s-叢集建置路線" class="headerlink" title="三條 K8s 叢集建置路線"></a>三條 K8s 叢集建置路線</h2><p>決定用真實 VM 之後，問題就從「<strong>用哪個工具模擬</strong>」變成「<strong>用哪種方式建立叢集</strong>」。這是另一層選擇，面向的是想認真接觸真實環境的人。此時有三條路可以選：</p><table><thead><tr><th>路線</th><th>control plane 誰管</th><th>維運成本</th><th>適合情境</th></tr></thead><tbody><tr><td>EKS &#x2F; GKE</td><td>雲端供應商</td><td>低</td><td>想專注把服務跑起來、不要自己維護底層</td></tr><tr><td>kubeadm</td><td>自己</td><td>高</td><td>想完整掌握 Kubernetes 底層，或企業需要高度控制</td></tr><tr><td>K3s</td><td>自己</td><td>中</td><td>想自己建叢集，但不想從零組裝每個元件</td></tr></tbody></table><p>這三條路代表三種不同的假設，選哪條取決於你的目標是什麼。以下我們依序來看。</p><h2 id="EKS-GKE：適合想「省事」的人"><a href="#EKS-GKE：適合想「省事」的人" class="headerlink" title="EKS &#x2F; GKE：適合想「省事」的人"></a>EKS &#x2F; GKE：適合想「省事」的人</h2><p><a href="https://aws.amazon.com/eks/">EKS</a> &#x2F; <a href="https://cloud.google.com/kubernetes-engine">GKE</a> 這類服務屬於<strong>託管式 Kubernetes</strong>（managed K8s），也就是<strong>由雲端供應商代管 control plane</strong> 的 Kubernetes。對想把服務跑起來、不想維護基礎設施的情境來說，這是最省事的選擇。</p><p>但「<strong>省事</strong>」只是表面。</p><p>它真正的價值在於<strong>高可用與穩定性</strong>——control plane 的多副本、自動修復、SLA 保證，都不是自己建叢集能輕易複製的——甚至大部分的公司也無法做到這一點。</p><p>這是為什麼大部分 production 環境的首選還是 <a href="https://aws.amazon.com/eks/">EKS</a> 或 <a href="https://cloud.google.com/kubernetes-engine">GKE</a>，而不是自建叢集。</p><p>對企業來說尤其合理——工程師的時間比 VM 費用貴，沒有必要把人力花在 Kubernetes 底層維護上。它的存在價值，就是讓團隊專注在應用層。</p><p>代價是：你幾乎碰不到底層。Control plane 的建置、節點的加入、網路設定大多由雲端處理好，因此你的學習重心會更偏向操作，而不是從頭建置。</p><h2 id="kubeadm：適合想掌控底層的人"><a href="#kubeadm：適合想掌控底層的人" class="headerlink" title="kubeadm：適合想掌控底層的人"></a>kubeadm：適合想掌控底層的人</h2><p><a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/">kubeadm</a> 是 Kubernetes 官方的叢集建置工具，需要你<strong>從頭開始，手動組裝</strong>：安裝 kubelet、設定 API server、用 token 讓 worker node 加入。</p><p>它讓你最直接碰到 Kubernetes 的原生建置流程。這條路適合 platform team，或需要對底層有完整掌控的企業環境。</p><p>其代價是<strong>複雜</strong>——網路套件、憑證管理、etcd 備份，每個環節都要自己處理。</p><p>對我這種單人維運的小型專案來說，這樣的複雜度<strong>很難換來相應的回報</strong>。</p><h2 id="K3s：我的選擇"><a href="#K3s：我的選擇" class="headerlink" title="K3s：我的選擇"></a>K3s：我的選擇</h2><p><a href="https://k3s.io/">K3s</a> <strong>介於兩者之間</strong>。它不像 EKS 那樣把底層全部藏起來，也不像 kubeadm 那樣把所有複雜度都攤在你面前。</p><p>對我來說，這正是我需要的<strong>平衡</strong>。</p><p>我選 K3s 的核心原因很簡單：我不只是想把 Kubernetes 用起來，還想理解它是<strong>怎麼被建起來的</strong>。它的價值不在於「比較輕」，而在於保留了<strong>恰到好處</strong>的建置細節，同時又不會把維運成本一下子拉得太高。</p><p>這是採用 K3s 的幾個實際考量：</p><ul><li><strong>整合度高</strong>：<a href="https://traefik.io/">Traefik</a>、<a href="https://github.com/flannel-io/flannel">Flannel</a> 等網路套件開箱即用，不需要像 kubeadm 一樣逐一自己安裝。</li><li><strong>夠真實</strong>：節點加入、kubeconfig 管理、網路介面綁定這些事還是要自行處理。</li><li><strong>不適合大型叢集</strong>：高度客製化底層或企業級規模的需求，kubeadm 或託管式 K8s 才是更好的選擇。</li></ul><hr><h2 id="K3s-是什麼"><a href="#K3s-是什麼" class="headerlink" title="K3s 是什麼"></a>K3s 是什麼</h2><p><a href="https://k3s.io/">K3s</a> 不是另一套系統，它是 Kubernetes 的一個<strong>發行版</strong>（distribution）。</p><p>「distribution」這個詞，用過 Linux 的人應該不陌生。Linux kernel 是基礎，Ubuntu、Fedora、Arch Linux 則是不同的發行版（distribution）——它們都是 Linux，但各自做了不同的<strong>打包與整合</strong>。</p><p>K3s 和 Kubernetes 的關係類似：它不是另一套不同的系統，而是建立在 <strong>Kubernetes 標準安裝</strong>之上的一個<strong>輕量發行版</strong>，由 Rancher Labs 開發，現由 SUSE（2020 年收購 Rancher Labs）維護，並通過 CNCF 認證。</p><p>這裡說的 Kubernetes 標準安裝，就是 Kubernetes 專案原本提供的元件與安裝方式，不會先幫你把常用元件整合成開箱即用的發行版。</p><p>和標準安裝相比，K3s 的核心差異是：單一執行檔、更精簡的依賴、預設內建 Traefik Ingress Controller，資料儲存則改用 SQLite 這類較輕量的方案，而非原生的 etcd。</p><p>你不需要自己從無到有，把這些零件組裝起來，就能快速擁有一個能跑的叢集。</p><table><thead><tr><th></th><th>Kubernetes 標準安裝</th><th>K3s</th></tr></thead><tbody><tr><td>安裝方式</td><td>多元件分開安裝</td><td>單一執行檔</td></tr><tr><td>預設 Ingress Controller</td><td>無</td><td>Traefik（內建）</td></tr><tr><td>預設網路套件</td><td>無</td><td>Flannel（內建）</td></tr><tr><td>資料儲存</td><td>etcd</td><td>SQLite（預設，可切換）</td></tr><tr><td>記憶體需求</td><td>較高</td><td>較低（適合小型 VM）</td></tr><tr><td>CNCF 認證</td><td>✓</td><td>✓</td></tr></tbody></table><hr><h2 id="WeaMind-的-K3s-叢集長什麼樣"><a href="#WeaMind-的-K3s-叢集長什麼樣" class="headerlink" title="WeaMind 的 K3s 叢集長什麼樣"></a>WeaMind 的 K3s 叢集長什麼樣</h2><p>叢集是 1 個控制平面節點 + 2 個工作節點，跑在 Hetzner 私有網路內。</p><p>可以把這個架構簡單理解成：應用層放進 K3s 叢集，資料層則獨立留在叢集外。</p><p><img src="https://img.kyomind.tw/img-20260329-223939.png" alt="WeaMind K3s 叢集架構圖，使用 Obsidian 渲染"><span class="cap">WeaMind K3s 叢集架構圖，使用 Obsidian 渲染</span></p><p>K3s 預設以 DaemonSet 方式部署 Traefik，所以每台 worker 都會有一個實例。</p><p>外部流量先經過 Hetzner Load Balancer 的 TCP 443 passthrough，再在 Traefik 這一層完成 TLS 終止，憑證則由 cert-manager 向 Let’s Encrypt 取得。</p><p>資料層沒有放進叢集，而是保留在叢集外的堡壘機，透過 Hetzner 私有網路連接。</p><hr><h2 id="結語：剛剛好的複雜"><a href="#結語：剛剛好的複雜" class="headerlink" title="結語：剛剛好的複雜"></a>結語：剛剛好的複雜</h2><p>回到最初的問題：想學 Kubernetes，要用什麼工具？</p><p>如果你的情境和我類似——個人專案或作品集、目標是理解建置過程、不想花大錢——那 K3s + 雲端 VM 是目前我覺得最務實的起點。</p><p>不在 Minikube 和 Kind 之間糾結，也不需要一開始就上託管式 K8s 或硬啃 kubeadm。選一個夠真實、又不會把你淹沒的環境，先跑起來再說。</p><blockquote><p>相關文章：<a href="/weamind-infra/">WeaMind Infra 介紹：VM、Load Balancer 與雲端架構</a></p></blockquote><hr><blockquote><p><strong>如果這篇文章對你有幫助，歡迎到 <a href="https://github.com/kyomind/WeaMind">WeaMind GitHub 首頁</a> 給我一個星星</strong><br>想試用 WeaMind，可掃描下方 QR Code 或搜尋 LINE ID <code>@370ndhmf</code> 加入好友<br>你的支持是我持續分享的動力</p></blockquote><p><img src="https://img.kyomind.tw/wea-qrcode-min-20250929-223022.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;/weamind-series/&quot;&gt;WeaMind 系列&lt;/a&gt; 的第 6 篇。&lt;br&gt;本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;「&lt;strong&gt;想學 Kubernetes，要用什麼工具？&lt;/strong&gt;」這是我在轉向 DevOps 時，必須回答的問題。&lt;/p&gt;
&lt;p&gt;你可能拿到的標準答案是：「&lt;strong&gt;用 Minikube 或 Kind 在本機開個環境，先跑起來再說&lt;/strong&gt;」。這當然沒錯，對多數人來說是合理的起點。但對我而言，問題則複雜一些。&lt;/p&gt;
&lt;p&gt;這篇文章針對「&lt;strong&gt;想自己建 Kubernetes 叢集，但又不想搞得太複雜&lt;/strong&gt;」的情境，說明 K3s 是什麼、適合誰，以及我為什麼最後選擇它。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/WeaMind-logo-min.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="Linux" scheme="https://blog.kyomind.tw/tags/Linux/"/>
    
    <category term="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
  </entry>
  
  <entry>
    <title>細數我過去的待業時光（二）律師國考與告別法律</title>
    <link href="https://blog.kyomind.tw/orange-days-02/"/>
    <id>https://blog.kyomind.tw/orange-days-02/</id>
    <published>2026-03-21T04:13:05.000Z</published>
    <updated>2026-06-20T07:06:10.076Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/weekly-review.png"></p><p>〈<a href="/weekly-review-38/">Kyo 待業中！細數我過去的待業時光</a>〉寫到，我在 2011 年底考上書記官，展開人生的第一段職涯。</p><p>再回顧那段待業時光，大概就是從「不知人生為何物」到「好吧，我要努力上榜！」的過程。</p><p>無論如何，最終總算是上榜了，雖然不是律師，但也算是個不錯的結果。</p><p>然而，這樣就可以了嗎？</p><span id="more"></span><hr><h2 id="五年公務員的內心掙扎"><a href="#五年公務員的內心掙扎" class="headerlink" title="五年公務員的內心掙扎"></a>五年公務員的內心掙扎</h2><p>我在法務行政執行署宜蘭分署當了五年多的書記官。</p><p>任職的前兩年，每天早上起床時，<strong>總有個聲音一直在耳邊迴盪</strong>：「法律系畢業，不去考律師、司法官，就這樣當個書記官，是不是有點太沒有志氣了？」</p><p>法律系的「正確答案」，好像不是這個。</p><p>而且我相信有一天，我會突然醒悟，然後就會去考律師了。</p><p>第三、四年，我開始<strong>自我說服</strong>：「穩定是有價值的，這份工作也<strong>沒有什麼不好</strong>。薪水夠用，而且我的物欲也不高，還有什麼好嫌的？」也許我就是一個<strong>不適合冒險的人</strong>。</p><p>到了第五年，滿 30 歲之後，我突然意識到：「<strong>靠！原來我一直在騙自己！</strong>」</p><p>當資深同事不時在討論退休，而年紀相仿的同事對公職的<strong>穩定感</strong>表現出高度的自我認同時，我感受到的是一種「強烈的<strong>孤獨</strong>」——我打從心底<strong>不認同</strong>這些價值觀。</p><blockquote><p><strong>我必須離開。</strong></p></blockquote><blockquote><p><code>2026/06/18</code> 補充：雖然是事後諸葛，不過如今看來，還好當初果斷離開，因為後來書記官的<a href="https://news.pts.org.tw/article/804316">案件量暴增</a>，工作環境已不可同日而語。<br>　<br>其實從我入職到離開時，短短 5 年，案件量就足足增加了一倍。這還只是宜蘭，雙北的可怕程度更是不在話下。</p></blockquote><hr><h2 id="一邊工作一邊準備的半年"><a href="#一邊工作一邊準備的半年" class="headerlink" title="一邊工作一邊準備的半年"></a>一邊工作一邊準備的半年</h2><p>發現自己在自欺欺人之後，我暗暗決定了方向：先考律師，如果上了，再衝一波名校的法律研究所——遵循著「功成名就法律人」的既定路線往前走。</p><p>只是這個決定，執行起來比想像中難熬。</p><p>法律系都知道，律師國考是一場<strong>長期消耗戰</strong>——題目廣、難度高。至少在我那個年代，能邊工作邊準備並上榜的人，可謂少之又少。</p><p>大多數上榜者不是全職準備，就是在讀研究所的期間通過考試——因為那時候才有足夠充裕的時間。</p><p>但我還在上班。</p><p>於是，我那時的生活就是：6 點下班，先吃飯，吃完往往會很睏XD。只好倒頭就睡，睡到晚上 8、9 點才醒來，才有一點精神開始讀書，讀到 10、11 點。</p><p>就這樣過了半年。</p><p>在相對疲憊的日子裡醒來時，盯著書桌發呆，會不禁思索：「這樣到底是在準備，還是在安慰自己『<strong>有在準備</strong>』？」</p><p>我覺得這樣下去<strong>很可能會考不上</strong>，然後也無法離開這個環境。30 歲的時候還有迴旋的餘地，如果 35 歲我還是一個公務員，那我就真的<strong>哪裡都去不了</strong>了。</p><p>2017 年 4 月，我離職了。</p><hr><h2 id="六個月的全職備考"><a href="#六個月的全職備考" class="headerlink" title="六個月的全職備考"></a>六個月的全職備考</h2><p>離職的時候，我沒有任何「離開法律」的念頭。只覺得自己又「回到正軌」了XD</p><p>老實說，我<strong>並不是真的很想當律師</strong>——但我只會考試！</p><p>還好，經過書記官考試的「鍛鍊」，哪怕沒那麼喜歡，我也能全力以赴地準備隨之而來的律師考試。</p><p>有一點值得釐清：律師雖然不是我想要的，但<strong>學習法律</strong>這件事，還是讓我樂在其中。</p><p>法律的邏輯性、系統性，還有對<strong>制度與秩序</strong>的追求，很符合我的價值觀——這大概說明了為什麼我會想走 DevOps。</p><p>總之，那六個月，就是讀書。</p><hr><h2 id="考場上的十五分鐘"><a href="#考場上的十五分鐘" class="headerlink" title="考場上的十五分鐘"></a>考場上的十五分鐘</h2><p>律師考試分為一試和二試，一試是選擇題，二試是申論題。</p><p>8 月的一試我最終以「前 3%」的成績通過了，10 月的二試則是決勝負的關鍵。</p><p>而結果就如同〈<a href="https://medium.com/code-and-me/datalog-%E5%91%8A%E5%88%A5%E6%B3%95%E5%BE%8B-ccec58db9acb">告別法律</a>〉裡寫的，我不只沒有考上，還在刑事法那一科的考場上足足哭了 15 分鐘😂</p><p>這就是最終的結果——我<strong>沒有辦法</strong>繼續我的法律之路。所謂的「正軌」，就在要過橋的時候直接斷了。</p><p>沒有「上榜」這座橋梁作為銜接，你是無法再往前一步的。</p><hr><h2 id="等待放榜的兩個月"><a href="#等待放榜的兩個月" class="headerlink" title="等待放榜的兩個月"></a>等待放榜的兩個月</h2><p>考完到放榜，中間有兩個月。</p><p>這兩個月，我什麼也做不了。</p><p>畢竟結果還沒出來，後面的路就沒辦法決定。要繼續準備研究所嗎？如果律師沒上，那準備研究所豈不是一個笑話？</p><blockquote><p>那要不要考其他的東西？畢竟法律人很擅長考試。</p></blockquote><p>但仔細想想，所謂的「其他考試」，基本上全都是公職考試，這又回到了原點——而我已經回不去了。</p><p>那段時間唯一記得的事，是去了在實踐大學舉辦的<a href="https://pansci.asia/archives/author/panfest">泛知識節</a>。聽了一些和 AI、大數據有關的東西，畢竟那時 AlphaGo 已經大紅，感覺一切都要 Data Driven 了。</p><hr><h2 id="Facebook-廣告"><a href="#Facebook-廣告" class="headerlink" title="Facebook 廣告"></a>Facebook 廣告</h2><p>現在說起來或許輕描淡寫，但那個時候的我，真的不知道自己該何去何從，頗有世界觀即將崩潰的絕望感。</p><p>畢竟，從大學一年級開始，到律師落榜為止，我已在法律這條<strong>單一且漫長</strong>的路上，走了超過十年了。</p><p><strong>我只會法律，也只會考試</strong>——原來我的結構竟是如此<strong>脆弱</strong>XD</p><p>想著未來的迷茫時，我在 Facebook 上看到一則廣告，是新竹自強基金會的大數據班的招生廣告。</p><p>這好像是一個方向？</p><p>最後我沒去新竹上課，畢竟太遠了！而是選擇報名台北的資策會大數據班。</p><p>以為要成為很潮的資料分析師，結果並非如此，不過這是下一篇的故事了。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/weekly-review.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;〈&lt;a href=&quot;/weekly-review-38/&quot;&gt;Kyo 待業中！細數我過去的待業時光&lt;/a&gt;〉寫到，我在 2011 年底考上書記官，展開人生的第一段職涯。&lt;/p&gt;
&lt;p&gt;再回顧那段待業時光，大概就是從「不知人生為何物」到「好吧，我要努力上榜！」的過程。&lt;/p&gt;
&lt;p&gt;無論如何，最終總算是上榜了，雖然不是律師，但也算是個不錯的結果。&lt;/p&gt;
&lt;p&gt;然而，這樣就可以了嗎？&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/weekly-review.png" type="image"/>
    
    
    <category term="Self" scheme="https://blog.kyomind.tw/categories/Self/"/>
    
    
    <category term="人生思考" scheme="https://blog.kyomind.tw/tags/%E4%BA%BA%E7%94%9F%E6%80%9D%E8%80%83/"/>
    
  </entry>
  
  <entry>
    <title>WeaMind 專案解析：從單機 LINE Bot 到 K8s 叢集</title>
    <link href="https://blog.kyomind.tw/weamind/"/>
    <id>https://blog.kyomind.tw/weamind/</id>
    <published>2026-03-16T08:02:40.000Z</published>
    <updated>2026-07-14T09:56:18.105Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png"></p><blockquote><p>📌 這是 <a href="/weamind-series/">WeaMind 系列</a> 的第 5 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p><a href="https://github.com/kyomind/WeaMind">WeaMind</a> 是一個查詢台灣天氣的 LINE Bot——<strong>點擊選單或輸入地名</strong>就能查天氣，是我花了數個月共 150+ 小時催生的 Side Project。</p><p>以下會從<strong>兩個層面</strong>介紹這個專案：</p><ul><li>第一部分是<strong>應用層</strong>（你直接看到、用到的那一面），聊聊這個 Bot 本身的技術設計和工程品質追求。</li><li>第二部分是<strong>基礎設施層</strong>（支撐 Bot 在雲端運行的底層環境），談談為什麼我要把它部署到 K8s 叢集上。</li></ul><p>從本文開始，這個寫了近 5 年的 Python 後端部落格，寫作重心將逐漸從<strong>後端開發</strong>轉向<strong>雲端與 DevOps</strong>。</p><p>這是一個全新的開始。</p><span id="more"></span><hr><h2 id="第一部分：一個天氣-Bot-的誕生"><a href="#第一部分：一個天氣-Bot-的誕生" class="headerlink" title="第一部分：一個天氣 Bot 的誕生"></a>第一部分：一個天氣 Bot 的誕生</h2><blockquote><p>最好的 side project 往往來自於<strong>自己的痛點</strong>。</p></blockquote><p>我個人是中央氣象局「<a href="https://www.cwa.gov.tw/V8/C/S/eservice/app/app_w.html">生活氣象 App</a> 」的<strong>重度使用者</strong>，但每次要在<strong>不同行政區之間</strong>切換查天氣，操作都很麻煩。</p><p>這個痛點存在很久了，一直希望有更好的手機查詢體驗。考慮到氣象資料有<a href="https://opendata.cwa.gov.tw/index">公開資料與 API</a>，我就想說：「乾脆自己做一個 LINE Bot 吧！」</p><p>除此之外，它必須是一個能展示我<strong>真實 Infra 能力</strong>的作品——不只是把 Bot 寫好，而是從程式碼到雲端部署，都<strong>有真實工程水準</strong>的那種。</p><p>多年前，從法律公務員轉職軟體工程師，我正是花了兩個月做了這個「<a href="https://medium.com/code-and-me/my-python-flask-web-service-2844b8b2f7b0">給嗜讀者的 Python Flask 網頁服務</a>」才順利找到工作。</p><h3 id="三個第一次"><a href="#三個第一次" class="headerlink" title="三個第一次"></a>三個第一次</h3><p>這是我<strong>第一次</strong>做 LINE Bot——要學習令人痛苦的 <a href="https://github.com/line/line-bot-sdk-python">LINE Bot SDK - Python</a>😂——強烈懷疑它就是 <strong>Java 版本直接「翻譯」過來</strong>，程式碼非常不 Pythonic！</p><p><strong>第一次</strong>用 FastAPI（工作上都是 Django）、<strong>第一次</strong>大量使用 AI（GitHub Copilot）輔助開發。</p><p>三個「第一次」疊在一起，學習曲線並不低。但正因為有 Copilot 全程參與，一個人也能在合理時間內把這些東西做出來——還做得<strong>有模有樣</strong>！</p><p>老實說，如果沒有 AI 輔助，我大概不會想一口氣挑戰「三個第一次」。</p><p>這大概就是 AI 時代的開發樣貌。</p><hr><h2 id="功能介紹"><a href="#功能介紹" class="headerlink" title="功能介紹"></a>功能介紹</h2><p>WeaMind 的核心功能很直覺：直接輸入行政區名稱就能查天氣，像是「大安區」、「中壢」；也可以<strong>設定住家和公司地址</strong>，之後<strong>一鍵查詢</strong>——<strong>後者</strong>才是重點，因為它真正解決了我切換行政區的難題。</p><p>還有地圖查詢功能，在 LINE 地圖上選任意位置就能查。系統也會記錄最近查過的 5 個地點，方便快速重複查詢。</p><p><img src="https://img.kyomind.tw/2352352we-min-20250929-222126.png" alt="WeaMind UI"><span class="cap">WeaMind UI</span></p><p>我相信這就是一個好的 Bot 該做的事：<strong>簡單易用、直指痛點</strong>。</p><hr><h2 id="應用層架構設計"><a href="#應用層架構設計" class="headerlink" title="應用層架構設計"></a>應用層架構設計</h2><p>做過 LINE Bot 的人都知道，它有幾個<strong>特別的「坑」</strong>：</p><ul><li>webhook <strong>必須在時限內回應</strong>（具體要多久之內是<strong>動態</strong>的，官方不會告訴你），否則 LINE Platform 會重送請求——用戶此時會收到<strong>重複的回覆</strong>，影響體驗。</li><li>無論有心還是無意，少部分用戶可能會<strong>瘋狂連點按鈕</strong>XD。而 LINE Platform 並未提供類似 rate limit 的機制，後端對每個請求都要處理——你的 db 正在燃燒🔥</li><li>webhook handler 邏輯不同於<strong>一般 API 開發</strong>，天然容易變成一團大泥球——解析、查詢、回覆全擠在一起，功能一多就很難看懂與維護。</li></ul><p>WeaMind 對這三個問題都有明確的解法：</p><ul><li><strong>Fast ACK Webhook</strong>：花數十毫秒先回應 LINE Platform，業務邏輯交給 FastAPI 的 <code>BackgroundTasks</code> 非同步運行，用戶感受到的回應在 <strong>2 秒以內</strong>——實際只需要<strong>幾百毫秒</strong>，但 Hetzner 主機對台灣的延遲很高😂</li><li><strong>Redis 分散式鎖</strong>：按鈕操作有 2 秒鎖定以防止連點，文字查詢則不受影響。</li><li><strong>DDD 模組劃分</strong>：<code>core</code>、<code>user</code>、<code>line</code>、<code>weather</code> 四個領域，並以 router → service → model 三層分離，邊界清晰不互相污染。</li></ul><p>更多細節可參考 WeaMind 專案 README 的「<a href="https://github.com/kyomind/WeaMind?tab=readme-ov-file#%E9%96%8B%E7%99%BC%E8%80%85%E6%8A%80%E8%A1%93%E4%BA%AE%E9%BB%9E">開發者技術亮點</a>」。</p><hr><h2 id="工程品質的「刻意」追求"><a href="#工程品質的「刻意」追求" class="headerlink" title="工程品質的「刻意」追求"></a>工程品質的「刻意」追求</h2><p>自己的專案，可以用<strong>自己的標準</strong>。</p><h3 id="我親愛的偏執狂"><a href="#我親愛的偏執狂" class="headerlink" title="我親愛的偏執狂"></a>我親愛的偏執狂</h3><p><strong>100% 的 type hints 覆蓋</strong>——使用 Pyright、<strong>95% 的單元測試覆蓋率</strong>、pre-commit 強制檢查、完整的 CI pipeline。</p><blockquote><p>相關文章：</p><ul><li><a href="/robust-python-01/">《強健的 Python》筆記：如何有效導入 Type Hints</a></li><li><a href="/django-ninja-29/">單元測試——使用 Test Client 與 pytest 測試 API</a></li><li><a href="/pre-commit/">Python 開發：pre-commit 設定 Git Hooks 教學</a></li></ul></blockquote><p>這些都不是偶然，而是<strong>刻意選擇</strong>的結果。在自己的專案裡，終於沒有人會說「這個可以之後再補」。</p><p>你可能會好奇「為什麼測試覆蓋率不是 100%？現在不是有 AI 了嗎？讓它一口氣寫完不就好了？」</p><p>我的看法是，覆蓋率畢竟只是測試品質的其中一個面向而已。為了讓覆蓋率達到百分之百，而寫一大堆不好讀、不好維護的<strong>機械性測試邏輯</strong>，這不符合我的開發價值觀。</p><p>哪怕是在 AI 時代，凡事也宜<strong>適可而止</strong>。</p><h3 id="偏執狂的工具鏈與-CI"><a href="#偏執狂的工具鏈與-CI" class="headerlink" title="偏執狂的工具鏈與 CI"></a>偏執狂的工具鏈與 CI</h3><p>工具鏈基本上是，想的到的一口氣全上了——說好的適可而止呢XD</p><p><a href="https://docs.astral.sh/uv/">uv</a> 管理 Python 虛擬環境；<a href="https://docs.astral.sh/ruff/">Ruff</a> 一個工具取代了 Flake8、Black、isort 三個；<a href="https://github.com/microsoft/pyright">Pyright</a> 做型別檢查。</p><blockquote><p>相關文章：</p><ul><li><a href="/introducing-uv/">Python 套件管理器 uv 介紹——與 Poetry 比較</a></li><li><a href="/ruff/">Python 開發：Ruff Linter、Formatter 介紹 + 設定教學</a></li><li><a href="/pyright/">Pyright 上手指南：Python 型別檢查的新選擇</a></li></ul></blockquote><p>安全掃描建了三層，角色不同：Bandit（靜態分析）、pip-audit（CVE 檢查）、detect-secrets（敏感資料防護）。這是我以前比較生疏的部分，這次特別加強。</p><p>每次 push 都會跑完 Ruff → Pyright → Bandit → pip-audit → pytest + Codecov 的完整流程。</p><blockquote><p>相關文章：<a href="/weamind-ci/">用 Side Project 學 CI：WeaMind 的 CI 實作策略</a></p></blockquote><p>第一階段 CI 通過後，最後會<strong>自動推送</strong>新版 image 到 <a href="https://github.com/kyomind/WeaMind/pkgs/container/weamind">GHCR</a>。</p><hr><h2 id="第二部分：從單機到叢集"><a href="#第二部分：從單機到叢集" class="headerlink" title="第二部分：從單機到叢集"></a>第二部分：從單機到叢集</h2><p>講完應用層，你可能會想：</p><blockquote><p>這個 LINE Bot 跑在單機 VM 上就能正常運作了，幹嘛還要搞 K8s？</p></blockquote><p>原因很簡單：因為這個專案從一開始就「不只是」為了做一個 LINE Bot——它是我為了 DevOps 轉職所做的<strong>刻意練習</strong>。</p><h3 id="K3s-on-Hetzner"><a href="#K3s-on-Hetzner" class="headerlink" title="K3s on Hetzner"></a>K3s on Hetzner</h3><p>我在 <a href="https://www.hetzner.com/">Hetzner</a> 上另外開了三台 VM 組成 K3s 叢集，加上一台付費的 Load Balancer——<strong>都是錢啊啊啊</strong>！🤯</p><p>原本那台跑 Docker Compose 的 VM，在叢集建成後角色順勢轉變為<a href="https://en.wikipedia.org/wiki/Bastion_host">堡壘機</a><strong>兼資料層</strong>，負責跑 PostgreSQL 和 Redis，同時作為 SSH 跳板與管理叢集——雖然我大部分時候都是在本機透過 <code>ProxyJump</code> 連到 Control Plane 上的 API Server。</p><h3 id="持續演進的平台"><a href="#持續演進的平台" class="headerlink" title="持續演進的平台"></a>持續演進的平台</h3><p>對我來說，這套 Kubernetes 部署不是做完就收工的作品。接下來，我還想在上面實作<a href="https://zh.wikipedia.org/zh-tw/%E5%8F%AF%E8%A7%80%E6%B8%AC%E6%80%A7">可觀測性</a>、<a href="https://helm.sh/">Helm</a> 等 DevOps 必修課題。</p><p>任何我想學的 DevOps 技能，都可以在這上面繼續疊加。它顯然比任何線上課附的 lab 都<strong>有趣且真實</strong>多了——想想就有點小興奮🤩</p><hr><h2 id="Infra-關鍵架構決策"><a href="#Infra-關鍵架構決策" class="headerlink" title="Infra 關鍵架構決策"></a>Infra 關鍵架構決策</h2><p>叢集是 <strong>K3s 三節點</strong>（1 控制平面 + 2 工作節點），跑在 Hetzner 私有網路內；資料層（PostgreSQL + Redis）留在堡壘機，透過內網連接。</p><p><strong>流量路徑</strong>：LINE Platform 的 webhook 請求會先到 Hetzner Load Balancer（TCP 443 passthrough），再由 Traefik Ingress Controller 完成 TLS 終止，最後轉送到 line-bot Service 與 line-bot Pod。</p><blockquote><p>相關文章：<a href="/weamind-infra/">WeaMind Infra 介紹：VM、Load Balancer 與雲端架構</a></p></blockquote><h3 id="為什麼選-K3s？"><a href="#為什麼選-K3s？" class="headerlink" title="為什麼選 K3s？"></a>為什麼選 K3s？</h3><p><a href="https://k3s.io/">K3s</a> 是由 <a href="https://www.rancher.com/">Rancher</a>（現為 SUSE）推出的<strong>輕量級 Kubernetes 發行版</strong>，專為<strong>資源受限</strong>的環境設計。</p><p>K3s 這個名稱意味「<strong>比 K8s 少 5 個字元的複雜度</strong>」——本質上就是一個<strong>更精簡、更易部署</strong>的 Kubernetes。</p><p>採單一 binary 檔、內建 Traefik Ingress Controller，並通過 <strong>CNCF 認證</strong>。</p><p>對於單人維運的小型叢集，它可能是<strong>最接近真實環境</strong>（相比於 <a href="https://minikube.sigs.k8s.io/">Minikube</a>、<a href="https://kind.sigs.k8s.io/">Kind</a>）而且<strong>最務實</strong>的選擇。</p><blockquote><p>相關文章：<a href="/k3s-for-weamind/">K3s 是什麼？為什麼我選擇用 K3s 部署 WeaMind</a></p></blockquote><h3 id="為什麼選-Hetzner？"><a href="#為什麼選-Hetzner？" class="headerlink" title="為什麼選 Hetzner？"></a>為什麼選 Hetzner？</h3><blockquote><p>相關文章：<a href="/hetzner/">Hetzner VPS 實測：比 DigitalOcean 更划算的選擇？</a></p></blockquote><p>當然是因為<strong>便宜</strong>！雖然它在今年 4 月就要<a href="https://www.hetzner.com/pressroom/statement-price-adjustment/">漲價</a>了🥲</p><p>表格是整個架構的所有成本（每月&#x2F;歐元，漲價前、稅前）：</p><table><thead><tr><th>節點</th><th>規格</th><th>月費</th></tr></thead><tbody><tr><td>原 VM（堡壘機兼資料層）</td><td>4C&#x2F;8GB</td><td>€6.5</td></tr><tr><td>K8s 控制平面</td><td>2C&#x2F;4GB</td><td>€3.5</td></tr><tr><td>K8s 工作節點 × 2</td><td>2C&#x2F;4GB</td><td>€7</td></tr><tr><td>Hetzner Load Balancer</td><td>—</td><td>€5</td></tr><tr><td><strong>合計</strong></td><td></td><td><strong>€22&#x2F;月</strong></td></tr></tbody></table><p>總體開銷，差不多等於訂閱一個 ChatGPT Plus 的月費。</p><p>但同樣的機器若要部署在 DigitalOcean 或者 GCP 上，所需的價格大概是 4 到 6 倍。（即使 Hetzner 漲價後也要 3 到 5 倍）</p><p>總之，我愛 Hetzner，德國人萬歲！</p><h3 id="資料層為什麼留在-VM？"><a href="#資料層為什麼留在-VM？" class="headerlink" title="資料層為什麼留在 VM？"></a>資料層為什麼留在 VM？</h3><p>簡潔與穩定性優先。</p><p>PostgreSQL 和 Redis 現階段不需要水平擴展——以後大概也不需要XD，放進 K8s 反而要處理 StatefulSet 和 PV 的管理複雜度。</p><p>而且用內網連接，延遲幾乎可以忽略不計。</p><h3 id="LINE-Webhook-URL-切換"><a href="#LINE-Webhook-URL-切換" class="headerlink" title="LINE Webhook URL 切換"></a>LINE Webhook URL 切換</h3><p>這是一個<strong>意外好用</strong>的設計！</p><p>我原本的想法是：LINE webhook 固定打 <a href="https://api.kyomind.tw/">api.kyomind.tw</a>（你直接點擊網址，會回應 <code>&#123;&quot;message&quot;:&quot;Welcome to WeaMind API&quot;&#125;</code>）上的 webhook endpoint，平常 DNS 的 A record 指向 Hetzner Load Balancer。</p><p>若叢集出問題需要 rollback，就<strong>手動把 A record 改回舊 VM 的 IP 地址</strong>，這樣就能快速切換回單機環境。</p><p>但這樣的問題是 <strong>DNS 傳播有延遲</strong>，少則幾分鐘、多則數小時，rollback 並不即時。</p><p>後來發現一個更簡單的做法：保留 <a href="https://api.kyomind.tw/">api.kyomind.tw</a> 指向舊 VM，另外新建一個 <a href="https://k8s.kyomind.tw/">k8s.kyomind.tw</a> 指向 Hetzner Load Balancer——兩個環境各自有固定網址。</p><p>切換時，只要在 LINE Platform 後台<strong>把 webhook URL 從一個換成另一個</strong>，秒級生效，不需要動 DNS。</p><p>這讓 K8s 環境和原本的單機環境可以並行運行，測試和 rollback 都很方便。</p><hr><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p>WeaMind 對我來說不只是一個天氣 Bot。</p><p>應用層是五年後端經驗的集大成之作——終於有機會按自己的標準，從頭到尾做一次。基礎設施則是跨入 DevOps 的第一步，用真金白銀搭出來的練兵場🐥</p><p>如同我在自己的 <a href="https://kyomind.tw/">Landing Page</a> 說的：</p><blockquote><p>AI 與 Infra 是開發者的未來。</p></blockquote><p>而 WeaMind，則是未來的開端。</p><hr><p>想看程式碼的讀者，歡迎逛逛 GitHub，並給我一個 ⭐️ 唷！</p><ul><li>應用層：<a href="https://github.com/kyomind/WeaMind">WeaMind</a></li><li>基礎設施：<a href="https://github.com/kyomind/weamind-infra">weamind-infra</a></li></ul><blockquote><p>想試用 WeaMind，可掃描下方 QR Code 或搜尋 LINE ID <code>@370ndhmf</code> 加入好友<br>你的支持是我持續分享的動力</p></blockquote><p><img src="https://img.kyomind.tw/wea-qrcode-min-20250929-223022.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;/weamind-series/&quot;&gt;WeaMind 系列&lt;/a&gt; 的第 5 篇。&lt;br&gt;本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kyomind/WeaMind&quot;&gt;WeaMind&lt;/a&gt; 是一個查詢台灣天氣的 LINE Bot——&lt;strong&gt;點擊選單或輸入地名&lt;/strong&gt;就能查天氣，是我花了數個月共 150+ 小時催生的 Side Project。&lt;/p&gt;
&lt;p&gt;以下會從&lt;strong&gt;兩個層面&lt;/strong&gt;介紹這個專案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一部分是&lt;strong&gt;應用層&lt;/strong&gt;（你直接看到、用到的那一面），聊聊這個 Bot 本身的技術設計和工程品質追求。&lt;/li&gt;
&lt;li&gt;第二部分是&lt;strong&gt;基礎設施層&lt;/strong&gt;（支撐 Bot 在雲端運行的底層環境），談談為什麼我要把它部署到 K8s 叢集上。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;從本文開始，這個寫了近 5 年的 Python 後端部落格，寫作重心將逐漸從&lt;strong&gt;後端開發&lt;/strong&gt;轉向&lt;strong&gt;雲端與 DevOps&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;這是一個全新的開始。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/WeaMind-logo-min.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
    <category term="GitHub Actions" scheme="https://blog.kyomind.tw/tags/GitHub-Actions/"/>
    
  </entry>
  
</feed>
