<?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-10-06T00:00:00+08:00</updated>
  <id>https://blog.kyomind.tw/</id>
  <author>
    <name>Kyo Huang</name>
  </author>
  <generator uri="https://astro.build/">Astro</generator>
  <entry>
    <title>一波三折的 CKA 之旅</title>
    <link href="https://blog.kyomind.tw/stumbling-on-cka/"/>
    <id>https://blog.kyomind.tw/stumbling-on-cka/</id>
    <published>2026-10-04T00:31:50+08:00</published>
    <updated>2026-10-06T00:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20261004-002239.jpg" alt="from Pixabay"><span class="cap">from Pixabay</span></p>
<p><a target="_blank" rel="noopener" href="https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/">CKA</a>（Certified Kubernetes Administrator）是 Kubernetes 的管理員認證。</p>
<p>考試時間 2 小時，你要連進一個遠端桌面，在真實的 Kubernetes 環境裡，用指令一題一題把答案敲出來。全程線上進行，由監考人員透過 webcam 盯著你。</p>
<p>不像 <a target="_blank" rel="noopener" href="https://aws.amazon.com/certification/certified-solutions-architect-associate/">AWS SAA</a> 可以去特約考場考，CKA 在台灣你要自備場地！我住的地方雜物太多不符合要求，只好另外找地方考——感謝多次幫我搬 27 吋螢幕到考場的女友🥹</p>
<p>我會去考它，一方面因為<a href="/all-in-on-devops/">轉職 DevOps</a> 的這一年，我在 Cloud Infra、Kubernetes、IaC、CI/CD 上前前後後投入了<strong>超過 400 小時</strong>——我都有計時。其中 Kubernetes 無疑是最多的一塊，大概占了<strong>六成</strong>。我想拿它來當作 Kubernetes 自學的驗收。</p>
<p>另一方面，這張證照對有 DevOps 工作經驗的人來說，可能只是錦上添花，但對正在求職的我而言，卻是少數能從外部證明自己的東西。</p>
<p>那就來考吧！</p>
<span id="more"></span>
<hr>
<p>本以為，有了從 3 月開始陸續打下的 Kubernetes 基礎，再準備個一、兩個月應該就能通過。結果 5 月第一次做 Udemy 課程附贈的 CKA 模擬考時，才第一題就傻住了。</p>
<p>題目要我建立一個 Pod（Kubernetes 裡最基本的運行單位），裡面要有 3 個容器，而且每個容器的規格要求都不同——我竟完全不知從何下手🤯</p>
<p><code>kubectl run</code>（建立 Pod 的指令）能帶哪些參數？為什麼要加 <code>--dry-run=client</code>？我幾乎都不熟。</p>
<blockquote>
<p>看樣子，這 CKA，沒有想像中容易！</p>
</blockquote>
<p>這就是我 CKA 之旅的起點。後來的發展，只能用「一波三折」來形容。雖然最終通過了，但值得好好記錄一下其中的「壯烈」之處。</p>
<h2 id="本文並非備考攻略"><a href="#本文並非備考攻略" class="headerlink" title="本文並非備考攻略"></a>本文並非備考攻略</h2>
<p>如果你想知道 CKA 該怎麼準備，網路上已經有寫得很好的心得，我自己也受益良多。推薦這兩篇：</p>
<ul>
<li><a target="_blank" rel="noopener" href="https://www.ptt.cc/bbs/Soft_Job/M.1740370039.A.FD8.html">[心得] CKA、CKAD 證照準備心得</a></li>
<li><a target="_blank" rel="noopener" href="https://blueswen.com/blog/2026/02/20/kubernetes-cka-%E8%88%87-cks-%E8%AA%8D%E8%AD%89%E8%80%83%E8%A9%A6%E5%BF%83%E5%BE%97%E5%88%86%E4%BA%AB/">Kubernetes CKA 與 CKS 認證考試心得分享</a></li>
</ul>
<p>這篇想分享的是另一個角度：一個沒有 DevOps 實務經驗的人，考 CKA 的真實過程。</p>
<p>當然，準備方式還是會簡單帶到，畢竟它也是這段經歷的一部分。</p>
<hr>
<h2 id="學了-9-週仍一知半解"><a href="#學了-9-週仍一知半解" class="headerlink" title="學了 9 週，仍一知半解"></a>學了 9 週，仍一知半解</h2>
<p>在開始準備 CKA 之前，我已經跑完一輪為期 9 週的自學計畫，其中前 6 週 focus 在 Kubernetes。</p>
<p>學習的過程與紀錄，都放在 <a target="_blank" rel="noopener" href="https://github.com/kyomind/weamind-infra/tree/main/learning">GitHub</a> 上了。</p>
<p>這段期間我學到了很多概念：Pod、Deployment、Service、Ingress，也把 <a href="/weamind/">WeaMind</a> 實際部署到叢集，運行至今。</p>
<p>但這些概念，當時在我腦中，只是<strong>一個個獨立的點</strong>。</p>
<p>我知道它們各自是什麼，卻很少從零開始，親手用指令把它們建出來。就算給我一份現成的 YAML 檔讓我改，也還是感到很生疏。</p>
<p>而且，單人維護的 side project，有些東西很難碰到：一個人用，無須權限控管；<a href="/k3s-for-weamind/">K3s</a> 則是輕量版 Kubernetes，把整個叢集的「記憶」——<a target="_blank" rel="noopener" href="https://digest.kyomind.tw/etcd-explained/">etcd</a>——簡化了。</p>
<p>所以除了 Pod、Deployment、Service、Ingress、ConfigMap 這些基本元件，CKA 考的東西，還有很多是我自學時沒機會實際操作的範圍。</p>
<h2 id="刷完-74-題才發現是舊考綱"><a href="#刷完-74-題才發現是舊考綱" class="headerlink" title="刷完 74 題，才發現是舊考綱"></a>刷完 74 題，才發現是舊考綱</h2>
<p>提到備考，大家普遍推薦 KodeKloud，我原本也打算照做，但 Udemy 課程的模擬題就跑在 KodeKloud 上，做的時候常常斷線。一氣之下，我改用 <a target="_blank" rel="noopener" href="https://killercoda.com/">Killercoda</a> 這個免費練習平台，刷一位叫 Sachin 的作者整理的 <a target="_blank" rel="noopener" href="https://killercoda.com/sachin/course/CKA">74 題題庫</a>。</p>
<h3 id="練習-killercoda"><a href="#練習-killercoda" class="headerlink" title="練習 Killercoda"></a>練習 Killercoda</h3>
<p>第一輪我做得很慢，很多新內容要花時間理解，比如儲存相關的 PV、PVC，只能一邊跟 AI 討論，一邊做筆記。不少題都得靠它幫忙才解得出來。</p>
<p>第二輪就好多了，在複習過筆記後，大部分題目 3 到 5 分鐘就能完成，而且不需要再頻繁求助於 AI。</p>
<p>那時我真心覺得：我變強了！（也沒有變禿）</p>
<p>然而，在原定考試日的三天前，我才發現——<strong>這 74 題，全是舊考綱。</strong></p>
<p>2025 年 CKA 改版，新增了 Helm、Kustomize、Gateway API 等一整批新內容，而我花了兩個月練的，一題都沒有涵蓋到。</p>
<p>這無疑是我整個準備過程中，<strong>最大的失誤</strong>。</p>
<h3 id="臨時抱佛腳"><a href="#臨時抱佛腳" class="headerlink" title="臨時抱佛腳"></a>臨時抱佛腳</h3>
<p>我趕緊去做官方附贈的 Killer Shell 模擬考。做完的感想只有一個：這跟 Killercoda 簡直是<strong>兩個世界</strong>。</p>
<p>幾乎沒有單純建 Pod、建 Service 的題目，大多是往<strong>叢集管理</strong>靠攏，讓我非常挫敗。</p>
<p>最後我決定把考試延後幾天。那些新東西需要時間消化，而我也需要休息。</p>
<p>儘管如此，我對於第一次考試還是有點信心——覺得有一半的機會能過。</p>
<p>然後就接連吃癟了🥲</p>
<hr>
<h2 id="第一次被新考綱突襲"><a href="#第一次被新考綱突襲" class="headerlink" title="第一次：被新考綱突襲"></a>第一次：被新考綱突襲</h2>
<p>8 月 3 日，第一次上考場。</p>
<h3 id="開考前的插曲"><a href="#開考前的插曲" class="headerlink" title="開考前的插曲"></a>開考前的插曲</h3>
<p>CKA 是線上監考，開考前要先核對身分。監考人員覺得我上傳的證件照不清楚，要我用 webcam 直接拍證件給他看——偏偏我的 webcam 無法近距離對焦，證件怎麼拍都是糊的。</p>
<p>就這樣來回了半小時，後來好像換了一位監考人員，反正就通過驗證了。我表定 14:00 開考，13:35 就進場，結果直到 14:15 才開始考試，有驚無險。</p>
<h3 id="我還是太天真了"><a href="#我還是太天真了" class="headerlink" title="我還是太天真了"></a>我還是太天真了</h3>
<p>一看到題目，就有一種強烈的「突襲感」。舊考綱範圍的題目還應付得來，但新考綱的部分，我交了兩三題白卷。</p>
<p>走出考場時，我回想大概有五題沒寫完，心裡更沒底了。考完 24 小時內會公布成績，這 24 小時真的是度日如年，覺都睡不好。</p>
<p>隔天起來，光 email 就反覆確認了十幾次，內心的焦躁感可想而知，最後成績出來：<strong>55 分</strong>——滿分 100 分，及格線是 66 分。</p>
<p>當下的第一個想法是：</p>
<blockquote>
<p>天啊！又要再來一次了，好累喔。</p>
</blockquote>
<h3 id="反省與檢討"><a href="#反省與檢討" class="headerlink" title="反省與檢討"></a>反省與檢討</h3>
<p>休息整整 5 天後（準備這考試讓我身心俱疲），冷靜下來回頭檢視，失分主要集中在新考綱，我想情況還不算太糟。</p>
<p>所幸 CKA 可以免費重考一次。接下來將近兩週，我專心補新考綱。</p>
<p>我把 5 月沒做完的 Udemy 模擬考重新做完——這次終於不再頻繁斷線了😂，然後再把附贈的第二份 Killer Shell 模擬考題做一做，我覺得這樣就差不多了。</p>
<hr>
<h2 id="第二次來自東方的神秘力量"><a href="#第二次來自東方的神秘力量" class="headerlink" title="第二次：來自東方的神秘力量"></a>第二次：來自東方的神秘力量</h2>
<p>8 月 20 日，第二次考試。</p>
<p>補完新考綱之後，我進考場前信心滿滿，還跟女友表示：「這次我有八成把握！」，沒想到，考試還沒開始就先出狀況。</p>
<h3 id="差點失去資格"><a href="#差點失去資格" class="headerlink" title="差點失去資格"></a>差點失去資格</h3>
<p>第一次考完後，我查到可以用手機檢查考試環境，心想這次證件總能拍清楚了吧！所以除了 webcam，還帶了手機。結果真的又要驗證證件時，監考人員表示：手機<strong>只能用來檢查環境</strong>，不能拿來給他看證件。我差點沒暈過去🫠</p>
<p>後來查，還真是這樣，只是那段說明的字很小，沒實際試過根本不會知道。附帶一提，無論有沒有帶手機，webcam 都必須全程開著。</p>
<p>所以，我只能在監考人員進來之前，反覆用手機重拍證件、重新上傳，但只要上傳的照片不被接受，監考人員就會要求我用 webcam 出示證件，而 webcam 一定拍不清楚，此時驗證流程就得<strong>整個重來</strong>。</p>
<p>直到第 4 次時，再失敗我就沒有時間了——還好這次終於通過驗證！</p>
<p>其實我本來已經放棄了，準備走出考場跟女友說「對不起」，沒想到柳暗花明，又重獲新生！但背後已經嚇出一身冷汗。</p>
<p>14:28 終於開考，前後總共花了 50 分鐘。</p>
<p>CKA 的規定是，表定開考的時間過了 30 分鐘還沒開始，就會「<strong>視為缺席</strong>」，直接失去本次考試資格。等於白白消耗了一次機會。我表定 14:00 開考，只差 2 分鐘。</p>
<h3 id="失控的左鍵"><a href="#失控的左鍵" class="headerlink" title="失控的左鍵"></a>失控的左鍵</h3>
<p>好不容易進了考試的遠端桌面，我以為一切終於要苦盡甘來。沒想到，來的是第二個挑戰：<strong>滑鼠左鍵在終端機和瀏覽器裡嚴重失控</strong>，切換視窗卡頓，連複製貼上都有困難。</p>
<p>奇怪的是，只有這兩塊區域有問題，旁邊的題目區卻一切正常。</p>
<p>當下我懷疑是滑鼠壞了，內心還在自責：「可惡，早知道該檢查的！」——但考前操作並沒有什麼異常呀？</p>
<p>面對這個問題，我只能盡力「避開」。就像一位鋼琴家在表演時，發現鋼琴有一個琴鍵壞了，只能在彈奏時盡量避開那個琴鍵。我只能<strong>盡量避免反白、複製等左鍵操作</strong>，效率下降很多，但勉強還是可以做題。</p>
<p>就這樣持續了 70 分鐘，直到一次偶然的 vim 指令操作不慎，直接當掉，我被迫重開終端機——它竟然好了！</p>
<p>但這時只剩 50 分鐘。考試時間結束時，有兩題我明明會寫，卻來不及做完。</p>
<p>於是，我又度過了漫長的一夜。最後成績出來：<strong>62 分</strong>。</p>
<p>真的是要氣死我🤬</p>
<h3 id="提出申訴"><a href="#提出申訴" class="headerlink" title="提出申訴"></a>提出申訴</h3>
<p>絕望的我只能摸摸鼻子，打算再買一次 CKA 應考資格，不過在此之前，我決定先向主辦方 Linux Foundation 提出申訴，說明考試過程中遇到的系統問題。</p>
<p>所幸 4 個小時後就收到回覆：同意讓我免費再考一次。</p>
<p>我立刻預約了下週四。</p>
<hr>
<h2 id="第三次神明保佑"><a href="#第三次神明保佑" class="headerlink" title="第三次：神明保佑"></a>第三次：神明保佑</h2>
<p>第二次考完後，我和 AI 整理了一套應變步驟：如果左鍵又失控，先關掉終端機重開；還是不行，就按工具列上的 Reset Desktop。</p>
<p>8 月 27 日，第三次考試。</p>
<p>一開考沒多久，同樣的故障又出現了。</p>
<p>我照著步驟做。重開終端機，<strong>沒用</strong>。Reset Desktop，<strong>也沒用</strong>。</p>
<blockquote>
<p>完蛋了，不會又要來了吧？</p>
</blockquote>
<p>那一刻我很害怕，不禁想起了當年在律師考場上的<a href="/orange-days-02/#%E8%80%83%E5%A0%B4%E4%B8%8A%E7%9A%84%E5%8D%81%E4%BA%94%E5%88%86%E9%90%98">絕望感</a>。</p>
<p>接下來 10 分鐘，我只能胡亂嘗試。然後，<strong>它就好了</strong>！怎麼好的，我到現在都不知道。也許是因為我有去拜拜吧。</p>
<p>剩下 110 分鐘，我埋頭把所有題目做完。</p>
<p>隔天，成績出來：<strong>93 分</strong>，終於通過了。法克。</p>
<hr>
<h2 id="結語從一知半解到初窺門徑"><a href="#結語從一知半解到初窺門徑" class="headerlink" title="結語：從一知半解到初窺門徑"></a>結語：從一知半解到初窺門徑</h2>
<p>5 月的我，雖然已經學習一段時間，但面對 Kubernetes 這頭巨獸，只能算一知半解。</p>
<p>在超乎預期漫長的 3 個月 CKA 準備中，又一步步補上了這些重要拼圖：PV、PVC、StorageClass、RBAC、etcd 備份與還原、Helm、Kustomize、Gateway API、CNI，以及各種 troubleshooting。</p>
<p>投入了超過 100 小時，累積了數萬字的 CKA 筆記與 1500 張 <a target="_blank" rel="noopener" href="https://www.threads.com/@kyomind.tw/post/DYWMCPvgSi2/">Logseq 閃卡</a>。</p>
<p>如果可以重來，我還是希望自己一次就通過 CKA，但無論如何，我相信現在的自己，已算是初窺門徑了。</p>
]]></content>
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/img-20261004-002239.jpg&quot; alt=&quot;from Pixabay&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://training.linuxfoundation.org/certification/certified-kubernetes-administrator-cka/&quot;&gt;CKA&lt;/a&gt;（Certified Kubernetes Administrator）是 Kubernetes 的管理員認證。&lt;/p&gt;
&lt;p&gt;考試時間 2 小時，你要連進一個遠端桌面，在真實的 Kubernetes 環境裡，用指令一題一題把答案敲出來。全程線上進行，由監考人員透過 webcam 盯著你。&lt;/p&gt;
&lt;p&gt;不像 &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://aws.amazon.com/certification/certified-solutions-architect-associate/&quot;&gt;AWS SAA&lt;/a&gt; 可以去特約考場考，CKA 在台灣你要自備場地！我住的地方雜物太多不符合要求，只好另外找地方考——感謝多次幫我搬 27 吋螢幕到考場的女友🥹&lt;/p&gt;
&lt;p&gt;我會去考它，一方面因為&lt;a href=&quot;/all-in-on-devops/&quot;&gt;轉職 DevOps&lt;/a&gt; 的這一年，我在 Cloud Infra、Kubernetes、IaC、CI/CD 上前前後後投入了&lt;strong&gt;超過 400 小時&lt;/strong&gt;——我都有計時。其中 Kubernetes 無疑是最多的一塊，大概占了&lt;strong&gt;六成&lt;/strong&gt;。我想拿它來當作 Kubernetes 自學的驗收。&lt;/p&gt;
&lt;p&gt;另一方面，這張證照對有 DevOps 工作經驗的人來說，可能只是錦上添花，但對正在求職的我而言，卻是少數能從外部證明自己的東西。&lt;/p&gt;
&lt;p&gt;那就來考吧！&lt;/p&gt;</summary>
    <content src="https://img.kyomind.tw/img-20261004-002239.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="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
  </entry>
  <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-12T01:00:35+08:00</published>
    <updated>2026-08-02T12:00:01+08:00</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%8Copencode-go-%E6%96%B9%E6%A1%88">8/1 更新重點整理</a>。</p>
</blockquote>
<p>最近 Hermes Agent 非常紅，熱度上似乎已經超越了俗稱「龍蝦」的 OpenClaw。</p>
<p>我自己玩了一個多月，也累積了一些心得想要與你分享。</p>
<p>如果你還不知道它是什麼，可以先參考 PAPAYA 的這支影片：</p>
<blockquote>
<p><a target="_blank" rel="noopener" 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%E6%A8%A1%E5%9E%8B%E5%88%A5%E5%90%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 / 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%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%E4%BD%BF%E7%94%A8-mac--iterm2">提示音效：使用 Mac + iTerm2</a></li>
<li><a href="#10-github-cli%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 target="_blank" rel="noopener" href="https://hermes-agent.nousresearch.com/">Hermes Agent</a> 是 <a target="_blank" rel="noopener" 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="一chatgptcodex"><a href="#一chatgptcodex" 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">選擇 ChatGPT Plus</a>。</p>
<p>因為它不僅可以聊天、寫程式，還可以拿來「<a href="/unsubscribe-github-copilot/#%E9%A1%8D%E5%A4%96%E5%A5%BD%E8%99%95%E5%8F%AF%E4%BB%A5%E9%A4%8A%E9%BE%8D%E8%9D%A6">養龍蝦</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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://opencode.ai/zht/go">OpenCode Go</a>。</p>
<p>在此暫不詳述，只要知道它可以作為 Hermes Agent 的 provider 即可。</p>
<p>我現在就是以 Go 方案作為主力，而 Codex 額度僅在必要時才用。</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 target="_blank" rel="noopener" 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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">hermes</span><span style="color:#9ECBFF"> config</span><span style="color:#9ECBFF"> set</span><span style="color:#9ECBFF"> memory.memory_char_limit</span><span style="color:#79B8FF"> 10000</span></span>
<span class="line"><span style="color:#B392F0">hermes</span><span style="color:#9ECBFF"> config</span><span style="color:#9ECBFF"> set</span><span style="color:#9ECBFF"> memory.user_char_limit</span><span style="color:#79B8FF"> 5000</span></span></code></pre>
<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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="yaml"><code><span class="line"><span style="color:#85E89D">model_aliases</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">  gpt</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">    provider</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">openai-codex</span></span>
<span class="line"><span style="color:#85E89D">    model</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">gpt-5.5</span></span>
<span class="line"><span style="color:#85E89D">  flash</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">    provider</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">opencode-go</span></span>
<span class="line"><span style="color:#85E89D">    model</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">deepseek-v4-flash</span></span>
<span class="line"><span style="color:#85E89D">  pro</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#85E89D">    provider</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">opencode-go</span></span>
<span class="line"><span style="color:#85E89D">    model</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">deepseek-v4-pro</span></span></code></pre>
<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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">hermes</span><span style="color:#9ECBFF"> config</span><span style="color:#9ECBFF"> set</span><span style="color:#9ECBFF"> compression.threshold</span><span style="color:#79B8FF"> 0.7</span></span></code></pre>
<p>如果是大 context window 的模型（像 DeepSeek V4），預設的 50% 則綽綽有餘。</p>
<h2 id="6-精簡預設的-skills--tools"><a href="#6-精簡預設的-skills--tools" class="headerlink" title="6. 精簡預設的 Skills / Tools"></a>6. 精簡預設的 Skills / Tools</h2>
<p>Hermes 預設上有 <strong>90 多個 skill、30 多個 tool</strong>。聽起來很強大，但實際上，選項太多不只燒 token，還會<strong>拖累 AI 的判斷</strong>——讓它<strong>變笨</strong>！</p>
<p>換句話說，選項太多，AI 反而容易 miss、選錯、或乾脆跳過。仔細想想，其實人也是一樣的嘛！🤯</p>
<p>我的做法是先大砍一輪。直接把用不到的 skill / 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 target="_blank" rel="noopener" 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>出於安全考量，我選擇用 <a target="_blank" rel="noopener" href="https://orbstack.dev/">OrbStack</a> 建立 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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%E9%80%9A%E7%9F%A5%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 target="_blank" rel="noopener" href="https://cli.github.com/">GitHub CLI</a>。</p>
<p>因為透過 <code>Web Extract</code> 抓 GitHub 頁面會帶入大量 HTML 雜訊——太浪費 token。</p>
<p>GitHub CLI 直接透過 API 取得乾淨資料，比如：</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">gh</span><span style="color:#9ECBFF"> issue</span><span style="color:#9ECBFF"> list</span><span style="color:#79B8FF"> -R</span><span style="color:#9ECBFF"> owner/repo</span></span>
<span class="line"><span style="color:#B392F0">gh</span><span style="color:#9ECBFF"> api</span><span style="color:#9ECBFF"> repos/owner/repo/contents/README.md</span><span style="color:#79B8FF"> --jq</span><span style="color:#9ECBFF"> '.content'</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> base64</span><span style="color:#79B8FF"> -d</span></span></code></pre>
<p>GitHub CLI 的<strong>認證方式</strong>主要有兩種。第一種是<strong>直接登入個人帳號</strong>，但這個<strong>權限過大</strong>，我只有在本機上使用 coding agent 時才會這麼做。</p>
<p>因此，建議採第二種：用 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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%8Copencode-go-%E6%96%B9%E6%A1%88&quot;&gt;8/1 更新重點整理&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 target=&quot;_blank&quot; rel=&quot;noopener&quot; 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-11T08:21:15+08:00</published>
    <updated>2026-07-12T00:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/code-and-me.png" alt=""></p>
<p>大家看過古古的這篇〈<a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://aws.amazon.com/tw/what-is/mlops/">MLOps</a>、<a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">❯</span><span style="color:#9ECBFF"> terraform</span><span style="color:#9ECBFF"> apply</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">Terraform</span><span style="color:#9ECBFF"> used</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> selected</span><span style="color:#9ECBFF"> providers</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> generate</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> following</span><span style="color:#9ECBFF"> execution</span><span style="color:#9ECBFF"> plan.</span><span style="color:#9ECBFF"> Resource</span><span style="color:#9ECBFF"> actions</span><span style="color:#9ECBFF"> are</span><span style="color:#9ECBFF"> indicated</span></span>
<span class="line"><span style="color:#B392F0">with</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> following</span><span style="color:#9ECBFF"> symbols:</span></span>
<span class="line"><span style="color:#B392F0">  +</span><span style="color:#9ECBFF"> create</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">Terraform</span><span style="color:#9ECBFF"> will</span><span style="color:#9ECBFF"> perform</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> following</span><span style="color:#9ECBFF"> actions:</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">(</span><span style="color:#B392F0">中略</span><span style="color:#E1E4E8">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">Plan:</span><span style="color:#79B8FF"> 4</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> add,</span><span style="color:#79B8FF"> 0</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> change,</span><span style="color:#79B8FF"> 0</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> destroy.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">Changes</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> Outputs:</span></span>
<span class="line"><span style="color:#B392F0">  +</span><span style="color:#9ECBFF"> external_ip</span><span style="color:#9ECBFF">   =</span><span style="color:#E1E4E8"> (known </span><span style="color:#9ECBFF">after</span><span style="color:#9ECBFF"> apply</span><span style="color:#E1E4E8">)</span></span>
<span class="line"><span style="color:#B392F0">  +</span><span style="color:#9ECBFF"> instance_name</span><span style="color:#9ECBFF"> =</span><span style="color:#9ECBFF"> "free-tier-vm"</span></span>
<span class="line"><span style="color:#B392F0">  +</span><span style="color:#9ECBFF"> instance_zone</span><span style="color:#9ECBFF"> =</span><span style="color:#9ECBFF"> "us-east1-b"</span></span>
<span class="line"><span style="color:#B392F0">  +</span><span style="color:#9ECBFF"> machine_type</span><span style="color:#9ECBFF">  =</span><span style="color:#9ECBFF"> "e2-micro"</span></span>
<span class="line"><span style="color:#B392F0">  +</span><span style="color:#9ECBFF"> project_id</span><span style="color:#9ECBFF">    =</span><span style="color:#9ECBFF"> "&lt;我的 GCP 專案名稱&gt;"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">Do</span><span style="color:#9ECBFF"> you</span><span style="color:#9ECBFF"> want</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> perform</span><span style="color:#9ECBFF"> these</span><span style="color:#9ECBFF"> actions?</span></span>
<span class="line"><span style="color:#B392F0">  Terraform</span><span style="color:#9ECBFF"> will</span><span style="color:#9ECBFF"> perform</span><span style="color:#9ECBFF"> the</span><span style="color:#9ECBFF"> actions</span><span style="color:#9ECBFF"> described</span><span style="color:#9ECBFF"> above.</span></span>
<span class="line"><span style="color:#B392F0">  Only</span><span style="color:#9ECBFF"> 'yes'</span><span style="color:#9ECBFF"> will</span><span style="color:#9ECBFF"> be</span><span style="color:#9ECBFF"> accepted</span><span style="color:#9ECBFF"> to</span><span style="color:#9ECBFF"> approve.</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">  Enter</span><span style="color:#9ECBFF"> a</span><span style="color:#9ECBFF"> value:</span><span style="color:#9ECBFF"> yes</span></span></code></pre>
<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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">❯</span><span style="color:#9ECBFF"> terraform</span><span style="color:#9ECBFF"> destroy</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">(</span><span style="color:#B392F0">中略</span><span style="color:#E1E4E8">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">Destroy</span><span style="color:#9ECBFF"> complete!</span><span style="color:#9ECBFF"> Resources:</span><span style="color:#79B8FF"> 4</span><span style="color:#9ECBFF"> destroyed.</span></span></code></pre>
<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 target="_blank" rel="noopener" href="https://github.com/kyomind/weamind-infra/tree/main/terraform/gcp-free-tier-vm">weamind-infra/terraform/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/HTTPS/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 target="_blank" rel="noopener" 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; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;大家看過古古的這篇〈&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; 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-10T10:16:55+08:00</published>
    <updated>2026-07-17T12:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/code-and-me.png" alt=""></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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://pre-commit.com/">pre-commit</a> 這類工具、CI/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 target="_blank" rel="noopener" href="https://antigravity.google/product/antigravity-2">Antigravity 2.0</a> app，有內建通知機制，如果沒用 CLI 可以不必設定。如果同時設定了 hooks 通知，則都會觸發，建議關掉內建通知。</p>
<p>我只寫全域 hooks，不寫 project-level。這些設定放在 home 目錄，透過 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="json"><code><span class="line"><span style="color:#9ECBFF">"hooks"</span><span style="color:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#79B8FF">  "Stop"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">    {</span></span>
<span class="line"><span style="color:#79B8FF">      "matcher"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">""</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">      "hooks"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">        {</span></span>
<span class="line"><span style="color:#79B8FF">          "type"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"command"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">          "command"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"bash ~/scripts/mac/notify-agent-stop.sh 'Claude Code'"</span></span>
<span class="line"><span style="color:#E1E4E8">        }</span></span>
<span class="line"><span style="color:#E1E4E8">      ]</span></span>
<span class="line"><span style="color:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#E1E4E8">  ],</span></span>
<span class="line"><span style="color:#79B8FF">  "PermissionRequest"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">    {</span></span>
<span class="line"><span style="color:#79B8FF">      "matcher"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">""</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">      "hooks"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">        {</span></span>
<span class="line"><span style="color:#79B8FF">          "type"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"command"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">          "command"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"bash ~/scripts/mac/notify-agent-permission-request.sh 'Claude Code'"</span></span>
<span class="line"><span style="color:#E1E4E8">        }</span></span>
<span class="line"><span style="color:#E1E4E8">      ]</span></span>
<span class="line"><span style="color:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#E1E4E8">  ]</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre>
<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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="toml"><code><span class="line"><span style="color:#E1E4E8">[</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">]</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">[[</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">.</span><span style="color:#B392F0">Stop</span><span style="color:#E1E4E8">]]</span></span>
<span class="line"><span style="color:#E1E4E8">matcher = </span><span style="color:#9ECBFF">""</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">[[</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">.</span><span style="color:#B392F0">Stop</span><span style="color:#E1E4E8">.</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">]]</span></span>
<span class="line"><span style="color:#E1E4E8">type = </span><span style="color:#9ECBFF">"command"</span></span>
<span class="line"><span style="color:#E1E4E8">command = </span><span style="color:#9ECBFF">"bash ~/scripts/mac/notify-agent-stop.sh Codex"</span></span>
<span class="line"><span style="color:#E1E4E8">statusMessage = </span><span style="color:#9ECBFF">"Sending agent stop notification"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">[[</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">.</span><span style="color:#B392F0">PermissionRequest</span><span style="color:#E1E4E8">]]</span></span>
<span class="line"><span style="color:#E1E4E8">matcher = </span><span style="color:#9ECBFF">""</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">[[</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">.</span><span style="color:#B392F0">PermissionRequest</span><span style="color:#E1E4E8">.</span><span style="color:#B392F0">hooks</span><span style="color:#E1E4E8">]]</span></span>
<span class="line"><span style="color:#E1E4E8">type = </span><span style="color:#9ECBFF">"command"</span></span>
<span class="line"><span style="color:#E1E4E8">command = </span><span style="color:#9ECBFF">"bash ~/scripts/mac/notify-agent-permission-request.sh Codex"</span></span>
<span class="line"><span style="color:#E1E4E8">statusMessage = </span><span style="color:#9ECBFF">"Sending agent permission request notification"</span></span></code></pre>
<p>Codex 設定檔採用 <a target="_blank" rel="noopener" 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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#F97583">~</span><span style="color:#E1E4E8">/.config/opencode/</span></span>
<span class="line"><span style="color:#B392F0">├──</span><span style="color:#9ECBFF"> opencode.json</span></span>
<span class="line"><span style="color:#B392F0">└──</span><span style="color:#9ECBFF"> plugin/</span></span>
<span class="line"><span style="color:#B392F0">    └──</span><span style="color:#9ECBFF"> notify.js</span></span></code></pre>
<p>本體是一個 js 檔，內容如下（這是我用 AI Vibe 的，你可以自行調整）：</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="js"><code><span class="line"><span style="color:#F97583">export</span><span style="color:#F97583"> const</span><span style="color:#B392F0"> NotifyPlugin</span><span style="color:#F97583"> =</span><span style="color:#F97583"> async</span><span style="color:#E1E4E8"> ({ </span><span style="color:#FFAB70">$</span><span style="color:#E1E4E8"> }) </span><span style="color:#F97583">=&gt;</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#F97583">  return</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#B392F0">    event</span><span style="color:#E1E4E8">: </span><span style="color:#F97583">async</span><span style="color:#E1E4E8"> ({ </span><span style="color:#FFAB70">event</span><span style="color:#E1E4E8"> }) </span><span style="color:#F97583">=&gt;</span><span style="color:#E1E4E8"> {</span></span>
<span class="line"><span style="color:#F97583">      if</span><span style="color:#E1E4E8"> (process.platform </span><span style="color:#F97583">!==</span><span style="color:#9ECBFF"> "darwin"</span><span style="color:#E1E4E8">) </span><span style="color:#F97583">return</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">      if</span><span style="color:#E1E4E8"> (event.type </span><span style="color:#F97583">===</span><span style="color:#9ECBFF"> "session.idle"</span><span style="color:#E1E4E8">) {</span></span>
<span class="line"><span style="color:#F97583">        await</span><span style="color:#B392F0"> $</span><span style="color:#9ECBFF">`bash ~/scripts/mac/notify-agent-stop.sh OpenCode`</span></span>
<span class="line"><span style="color:#E1E4E8">      }</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">      if</span><span style="color:#E1E4E8"> (event.type </span><span style="color:#F97583">===</span><span style="color:#9ECBFF"> "permission.asked"</span><span style="color:#E1E4E8">) {</span></span>
<span class="line"><span style="color:#F97583">        await</span><span style="color:#B392F0"> $</span><span style="color:#9ECBFF">`bash ~/scripts/mac/notify-agent-permission-request.sh OpenCode`</span></span>
<span class="line"><span style="color:#E1E4E8">      }</span></span>
<span class="line"><span style="color:#E1E4E8">    }</span></span>
<span class="line"><span style="color:#E1E4E8">  }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre>
<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 target="_blank" rel="noopener" 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>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="json"><code><span class="line"><span style="color:#E1E4E8">{</span></span>
<span class="line"><span style="color:#79B8FF">  "notify-stop"</span><span style="color:#E1E4E8">: {</span></span>
<span class="line"><span style="color:#79B8FF">    "Stop"</span><span style="color:#E1E4E8">: [</span></span>
<span class="line"><span style="color:#E1E4E8">      {</span></span>
<span class="line"><span style="color:#79B8FF">        "type"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"command"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">        "command"</span><span style="color:#E1E4E8">: </span><span style="color:#9ECBFF">"bash /Users/kyo/scripts/mac/notify-agent-stop.sh Antigravity; echo '{}'"</span><span style="color:#E1E4E8">,</span></span>
<span class="line"><span style="color:#79B8FF">        "timeout"</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">30</span></span>
<span class="line"><span style="color:#E1E4E8">      }</span></span>
<span class="line"><span style="color:#E1E4E8">    ]</span></span>
<span class="line"><span style="color:#E1E4E8">  }</span></span>
<span class="line"><span style="color:#E1E4E8">}</span></span></code></pre>
<p>幾個注意事項：</p>
<ol>
<li><strong>必須用絕對路徑</strong>：Antigravity 在 <code>-p</code> 模式下，相對路徑會失敗</li>
<li><strong>腳本必須輸出合法 JSON</strong>：Antigravity 會檢查 stdout，所以結尾補上 <code>; echo '{}'</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-stopsh"><a href="#notify-agent-stopsh" class="headerlink" title="notify-agent-stop.sh"></a>notify-agent-stop.sh</h3>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">agent_name</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"</span><span style="color:#79B8FF">${1</span><span style="color:#F97583">:-</span><span style="color:#E1E4E8">Agent</span><span style="color:#79B8FF">}</span><span style="color:#9ECBFF">"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># 播放 Glass 音效</span></span>
<span class="line"><span style="color:#B392F0">afplay</span><span style="color:#9ECBFF"> /System/Library/Sounds/Glass.aiff</span><span style="color:#E1E4E8"> &amp;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># 顯示 Notification Center 通知</span></span>
<span class="line"><span style="color:#B392F0">osascript</span><span style="color:#79B8FF"> -e</span><span style="color:#9ECBFF"> "display notification </span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF">${</span><span style="color:#E1E4E8">agent_name</span><span style="color:#9ECBFF">} 已回覆</span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF"> with title </span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF">Agent Stop</span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF">"</span><span style="color:#E1E4E8"> &amp;</span></span></code></pre>
<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-requestsh"><a href="#notify-agent-permission-requestsh" class="headerlink" title="notify-agent-permission-request.sh"></a>notify-agent-permission-request.sh</h3>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#6A737D">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">agent_name</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"</span><span style="color:#79B8FF">${1</span><span style="color:#F97583">:-</span><span style="color:#E1E4E8">Agent</span><span style="color:#79B8FF">}</span><span style="color:#9ECBFF">"</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># 播放 Funk 音效</span></span>
<span class="line"><span style="color:#B392F0">afplay</span><span style="color:#9ECBFF"> /System/Library/Sounds/Funk.aiff</span><span style="color:#E1E4E8"> &amp;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D"># 顯示 Notification Center 通知</span></span>
<span class="line"><span style="color:#B392F0">osascript</span><span style="color:#79B8FF"> -e</span><span style="color:#9ECBFF"> "display notification </span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF">${</span><span style="color:#E1E4E8">agent_name</span><span style="color:#9ECBFF">} 需要權限確認</span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF"> with title </span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF">Agent Permission Request</span><span style="color:#79B8FF">\"</span><span style="color:#9ECBFF">"</span><span style="color:#E1E4E8"> &amp;</span></span></code></pre>
<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%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; alt=&quot;&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-05T14:29:12+08:00</published>
    <updated>2026-10-01T00:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png" alt=""></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 target="_blank" rel="noopener" href="https://github.com/kyomind/weamind-infra/tree/main/manifests">manifests</a>），皆已公開在這個 GitHub 專案：<a target="_blank" rel="noopener" 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/8GB）</td>
<td>資料層 + SSH 跳板</td>
</tr>
<tr>
<td>Control Plane</td>
<td>CX23（x86，2C/4GB）</td>
<td>K8s API Server</td>
</tr>
<tr>
<td>Worker × 2</td>
<td>CX23（x86，2C/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 target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Bastion_host">Bastion host</a>）用 <code>kubectl</code> 控制 cluster。這也是常見的小型 K8s 部署架構。</p>
<blockquote>
<p>延伸閱讀：<a target="_blank" rel="noopener" href="https://blog.yangjerry.tw/posts/it2022-day02/">《關於我怎麼把一年內學到的新手 IT/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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://wakapi.dev/">Wakapi</a>。當然，一定少不了負責流量轉發與 TLS 憑證申請的 Nginx 與 Certbot。</p>
<p>儘管如此，它們總共也只佔了 1.2 GB 的 RAM，對於這台有 8 GB RAM 的機器，顯然還是浪費了！</p>
<p>之後預計會把 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://k3s.io/">K3s</a>，配置為 1 Control Plane + 2 Worker。</p>
<p>三台都是 <a target="_blank" rel="noopener" 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>
<blockquote>
<p>延伸閱讀：<a target="_blank" rel="noopener" href="https://digest.kyomind.tw/hetzner-business-philosophy/#%E4%BA%942026-%E5%B9%B4%E7%9A%84%E9%82%8A%E7%95%8C%E8%80%83%E9%A9%97%E7%95%B6%E5%83%B9%E6%A0%BC%E7%B4%80%E5%BE%8B%E9%81%87%E4%B8%8A-dram-%E5%8D%B1%E6%A9%9F">Hetzner 的三十年經營哲學：一家德國公司如何拒絕矽谷劇本</a></p>
</blockquote>
<p>我的機器是今年年初建立的，目前適用 4 月調整後的「舊」價格。如果你現在要開新機器，則會是 6/15 後的新價格。</p>
<p><a target="_blank" rel="noopener" href="https://docs.hetzner.com/general/infrastructure-and-availability/price-adjustment/">價格對照</a>：</p>
<table>
<thead>
<tr>
<th>元件</th>
<th>舊價格（4 月後）</th>
<th>新價格（6/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; alt=&quot;&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 target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/kyomind/weamind-infra/tree/main/manifests&quot;&gt;manifests&lt;/a&gt;），皆已公開在這個 GitHub 專案：&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; 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-18T15:30:36+08:00</published>
    <updated>2026-07-14T00:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/code-and-me.png" alt=""></p>
<p>AI 輔助程式設計工具 <a target="_blank" rel="noopener" href="https://github.com/features/copilot">GitHub Copilot</a> 在今年 6 月 1 號全面改制為 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://x.com/SemiAnalysis_/status/2064815042374074396">貼文</a>可知，ChatGPT Plus 月費 20 美元，如果週週用滿，實測大約可以達到 700 美元等值的 API token（指 <a target="_blank" rel="noopener" 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 / 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://www.threads.com/@kyomind.tw/post/DWvOTmIAZZS">為了教女友用，結果自己反而用最多</a>。</p>
<p>隨著 Codex app 的流行，讓 Google 也忍不住<a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://x.com/sama/status/2050357911915028689">宣布</a>，ChatGPT 訂閱可以直接接入 OpenClaw 使用。</p>
<p><a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://vscode.com.tw/docs/copilot/agents/memory">記憶</a>」功能，會在 repo 底下建一個 <code>memories</code> 資料夾。問題是，這個資料夾只有 GitHub Copilot 會用，其他 agent 根本不認識。</p>
<p>什麼爛東西XD（好啦，<a target="_blank" rel="noopener" href="https://docs.github.com/en/copilot/tutorials/customization-library/prompt-files">prompt files</a> 就是我覺得很成功的設計，我幾乎每個 repo 都有使用）</p>
<p>相較之下，我更偏好<strong>通用的機制</strong>，像是 <a target="_blank" rel="noopener" href="https://agents.md/">AGENTS.md</a>、<a target="_blank" rel="noopener" href="https://code.claude.com/docs/zh-TW/hooks-guide">hooks</a>（現在各家都有了，只是設定略有不同）、<a target="_blank" rel="noopener" href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a>、<a target="_blank" rel="noopener" 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; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;AI 輔助程式設計工具 &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; href=&quot;https://github.com/features/copilot&quot;&gt;GitHub Copilot&lt;/a&gt; 在今年 6 月 1 號全面改制為 &lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; 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 target=&quot;_blank&quot; rel=&quot;noopener&quot; 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-14T13:03:31+08:00</published>
    <updated>2026-10-03T00:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20260614-143640.jpg" alt=""></p>
<p>2018 年夏，我剛從資策會結訓不久，參加了一場同為「<a target="_blank" rel="noopener" href="https://www.ispan.com.tw/longterm/JJBDSET/">大數據班</a>」學長姐們的聚餐。想當然耳，只有還繼續留在軟體這個領域的人才會想出席吧！</p>
<p>那時正處於「<strong>人生的暑假</strong>」——結訓後不知道該何去何從，對程式的興趣普通，不清楚自己能做什麼，所以就去了，聽聽前輩們的意見也好。</p>
<p>會上遇到了一個正在當 DevOps 的學長，和他聊了許多，幾天後我才重新振作，繼續自學程式，隔年終於找到工作，開始了我的軟體開發之路。</p>
<hr>
<p>從資料工程師到 Python 後端，隨著時間的推移，我自認對程式充滿熱情。</p>
<p>幾年前和女友介紹什麼是 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://kubernetes.io/">Kubernetes</a> 部署與維運。雖然分工明確，但後端也需要透過 Jenkins 觸發部署、登入 <a target="_blank" rel="noopener" href="https://www.rancher.com/">Rancher</a> 查看 Pod log 來排查問題。這讓我逐漸意識到：application 寫好，<strong>不代表</strong>服務就會穩定運作。</p>
<p>有些時候不一定是程式邏輯出錯，而是環境、部署、微服務之間的<strong>協調</strong>問題。有時則是 <a target="_blank" rel="noopener" href="https://ai.azure.com/">AI Foundry</a> 或其他 infra 組件出了狀況。</p>
<p>這些東西——<strong>尤其是 Kubernetes</strong>——我開始接觸，但理解仍然有限。</p>
<p>以前都是 VM 部署，然後 <a target="_blank" rel="noopener" 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/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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://ithelp.ithome.com.tw/articles/10267454">db 主從複製</a>，雲端早就服務化了！不得不說，有一種「已知用火」的興奮感🤩</p>
<p>一邊工作一邊準備，總計花了 105 小時，終於在 12 月 15 日<a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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>
<blockquote>
<p>相關文章：<a href="/stumbling-on-cka/">一波三折的 CKA 之旅</a></p>
</blockquote>
<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; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;2018 年夏，我剛從資策會結訓不久，參加了一場同為「&lt;a target=&quot;_blank&quot; rel=&quot;noopener&quot; 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 target=&quot;_blank&quot; rel=&quot;noopener&quot; 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-12T17:30:22+08:00</published>
    <updated>2026-06-20T00:00:00+08:00</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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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="headlampdashboard-接班人"><a href="#headlampdashboard-接班人" class="headerlink" title="Headlamp：Dashboard 接班人"></a>Headlamp：Dashboard 接班人</h2>
<p>Kubernetes Dashboard 被封存後，官方在 repo 中建議改用 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 / 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="k9stui-的首選"><a href="#k9stui-的首選" class="headerlink" title="K9s：TUI 的首選"></a>K9s：TUI 的首選</h2>
<p><a target="_blank" rel="noopener" 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 target=&quot;_blank&quot; rel=&quot;noopener&quot; 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-29T12:54:39+08:00</published>
    <updated>2026-10-03T00:00:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png" alt=""></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 target="_blank" rel="noopener" href="https://minikube.sigs.k8s.io/">Minikube</a> 或 <a target="_blank" rel="noopener" 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 / 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 / GKE：適合想「省事」的人"></a>EKS / GKE：適合想「省事」的人</h2>
<p><a target="_blank" rel="noopener" href="https://aws.amazon.com/eks/">EKS</a> / <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://aws.amazon.com/eks/">EKS</a> 或 <a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" href="https://traefik.io/">Traefik</a>、<a target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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>
<blockquote>
<p>延伸閱讀：<a target="_blank" rel="noopener" href="https://digest.kyomind.tw/kubernetes-history-part1/">Kubernetes 演進史（上）：Borg、編排之戰與 Docker</a></p>
</blockquote>
<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>相關文章：</p>
<ul>
<li><a href="/weamind-infra/">WeaMind Infra 介紹：VM、Load Balancer 與雲端架構</a></li>
<li><a href="/stumbling-on-cka/">一波三折的 CKA 之旅</a></li>
</ul>
</blockquote>
<hr>
<blockquote>
<p><strong>如果這篇文章對你有幫助，歡迎到 <a target="_blank" rel="noopener" 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" alt=""></p>
]]></content>
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot; alt=&quot;&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-21T12:13:05+08:00</published>
    <updated>2026-06-18T11:30:00+08:00</updated>
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/weekly-review.png" alt=""></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 target="_blank" rel="noopener" href="https://digest.kyomind.tw/taiwan-court-clerks-crisis/">案件量暴增</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 target="_blank" rel="noopener" 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 target="_blank" rel="noopener" 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; alt=&quot;&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>
</feed>
