<?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-04-14T08:55:08.644Z</updated>
  <id>https://blog.kyomind.tw/</id>
  
  <author>
    <name>Kyo Huang</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Kubernetes 視覺化工具怎麼選？初學者的 GUI、TUI 指南</title>
    <link href="https://blog.kyomind.tw/kubernetes-gui-tui-guide/"/>
    <id>https://blog.kyomind.tw/kubernetes-gui-tui-guide/</id>
    <published>2026-04-12T09:30:22.000Z</published>
    <updated>2026-04-14T08:55:08.644Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20260412-174100.png" alt="圖片來源：Headlamp GitHub"><span class="cap">圖片來源：Headlamp GitHub</span></p><p>前陣子讀《<a href="https://readmoo.com/book/210309079000101">從異世界歸來發現只剩自己不會 Kubernetes</a>》時，作者在開篇不久就推薦了 Kubernetes Dashboard。</p><p>我立刻燃起了興趣！畢竟我本來就是 GUI 愛好者。</p><p>尤其 Kubernetes 這種東西，一開始光是名詞就夠多了。Pod、Deployment、Service、Node、Namespace，還沒開始排查問題，光是先建立畫面感就已經很吃力。</p><p>如果有個視覺化工具，對初學者想必會很有幫助，本書作者也是這麼想的。</p><p>本文想回答的問題是：「現在如果想用視覺化方式看 Kubernetes 叢集，該選什麼？」</p><span id="more"></span><p>討論範圍只限用來看叢集狀態的 GUI 和 TUI。像 Prometheus、Grafana、stern 這類不同範疇的工具，就先不展開。</p><hr><h2 id="Kubernetes-Dashboard：時代的眼淚"><a href="#Kubernetes-Dashboard：時代的眼淚" class="headerlink" title="Kubernetes Dashboard：時代的眼淚"></a>Kubernetes Dashboard：時代的眼淚</h2><p><a href="https://github.com/kubernetes-retired/dashboard">Kubernetes Dashboard</a> 是官方推出的 Web UI，由 Kubernetes 社群維護，部署在 cluster 內，並透過瀏覽器存取。</p><p>我照著書中的說明去裝了，也實際把它跑起來了，如下圖：</p><p><img src="https://img.kyomind.tw/img-20260410-151325.png" alt="Kubernetes Dashboard"><span class="cap">Kubernetes Dashboard</span></p><p>然而，這個專案已經在 2026 年 1 月 21 日被官方<strong>封存</strong>了。</p><p>實際裝過一次之後，我也必須承認，它真的<strong>不算友好</strong>。</p><h3 id="麻煩一：自己部署進-cluster"><a href="#麻煩一：自己部署進-cluster" class="headerlink" title="麻煩一：自己部署進 cluster"></a>麻煩一：自己部署進 cluster</h3><p>首先，它不是下載即用。你得把一整套元件<strong>手動部署到自己的 cluster</strong>，即便用 Helm 這種最簡單的方式，也需要一連串步驟才能裝好。</p><p>而且這不只是「多做幾步」那麼簡單——它會<strong>持續佔用</strong> cluster 的資源。</p><h3 id="麻煩二：每次連線都要重來一輪"><a href="#麻煩二：每次連線都要重來一輪" class="headerlink" title="麻煩二：每次連線都要重來一輪"></a>麻煩二：每次連線都要重來一輪</h3><p>更煩的是後續使用。每次要開 Dashboard，你得先跑一次 port-forward，然後透過指令產生 token。</p><p>而且 token 的效期很短——用 <code>kubectl create token</code> 產生的話，預設只有一小時，過了就得重拿。長效 token 則要用另一套流程來產生。</p><p>相較之下，像 Headlamp 這種直接吃 kubeconfig 的桌面 App，進入門檻明顯低得多。</p><h3 id="舊時代的退場"><a href="#舊時代的退場" class="headerlink" title="舊時代的退場"></a>舊時代的退場</h3><p>只能說，Dashboard 這種 browser-based、in-cluster 的思路，確實愈來愈不符合現在大家使用 Kubernetes 的方式。</p><p>也難怪它會被官方封存了。</p><hr><h2 id="現役選項一覽"><a href="#現役選項一覽" class="headerlink" title="現役選項一覽"></a>現役選項一覽</h2><p>講完退場的，接下來進入現役選項。本文要介紹的工具如下：</p><table><thead><tr><th>工具</th><th>類型</th><th>特色</th><th>適合情境</th></tr></thead><tbody><tr><td>Headlamp</td><td>GUI</td><td>輕量、直接吃 kubeconfig、由 Kubernetes SIG 維護</td><td>個人學習、單叢集、想要 GUI 輔助</td></tr><tr><td>Lens</td><td>GUI</td><td>功能完整、整合度高、視覺化強</td><td>想要 all-in-one 體驗、不介意工具較重</td></tr><tr><td>Rancher</td><td>GUI</td><td>多叢集管理、權限與平台治理</td><td>企業、平台團隊、多叢集場景</td></tr><tr><td>K9s</td><td>TUI</td><td>快、輕、排查導向</td><td>日常巡檢、快速觀察、鍵盤工作流</td></tr></tbody></table><hr><h2 id="Headlamp：Dashboard-接班人"><a href="#Headlamp：Dashboard-接班人" class="headerlink" title="Headlamp：Dashboard 接班人"></a>Headlamp：Dashboard 接班人</h2><p>Kubernetes Dashboard 被封存後，官方在 repo 中建議改用 <a href="https://headlamp.dev/">Headlamp</a> 作為替代方案。它目前由 Kubernetes SIG 維護，是一條有延續性的路線。</p><p>實際用過之後，不難理解它為什麼會被指定為替代選項。</p><p><img src="https://img.kyomind.tw/img-20260410-191937.png" alt="Headlamp UI"><span class="cap">Headlamp UI</span></p><p>Headlamp 一樣支援透過 Helm 以 <a href="https://headlamp.dev/docs/latest/installation/in-cluster/">in-cluster</a> 的方式部署成 Web UI。</p><p>不過對大多數人而言，最直覺的用法還是桌面版 app：可直接讀取本機的 kubeconfig 連線資訊，不需要先往 cluster 裡裝一套東西，有效降低了使用門檻。</p><p>對「<strong>我只是想看懂叢集裡有什麼</strong>」這個需求來說，這條路明顯簡單得多。</p><p>更別說它一樣能夠操作資源，但通常我不會這麼做😅。操作資源我會乖乖使用 <code>kubectl</code>。</p><p>我未必認為它的畫面呈現有全方位超越 Dashboard，但它至少把安裝與登入的摩擦感降了很多。</p><p>有了 Headlamp，你可以很快地點進 Pod、Deployment、Node，看資源關係、事件、YAML，先把整個 cluster 的結構感建立起來。對還在學 Kubernetes 的人來說，這種畫面感很有價值。</p><p>所以如果你的需求是：單人、單叢集、學習導向、想保留 GUI 輔助，那 Headlamp 幾乎就是目前最合理的起點。</p><hr><h2 id="Lens：完整，但更重"><a href="#Lens：完整，但更重" class="headerlink" title="Lens：完整，但更重"></a>Lens：完整，但更重</h2><p><a href="https://lenshq.io/">Lens</a> 是由 Mirantis 維護的 Kubernetes 桌面客戶端，也是目前功能最完整的選項之一。</p><p>比起 Headlamp，Lens 的整合度與周邊都更完整：內建的 metrics 視覺化、整合式 terminal、多 cluster workspace，以及比較成熟的 extension 生態，這些都是它長年累積下來的優勢。</p><p>對於想用一個工具滿足多種需求的人來說，這種體驗是有吸引力的。</p><p>但它的缺點也很明顯，就是比較「<strong>重</strong>」。不只是執行層面的重，也包括整個工具帶有比較強的<strong>商業產品感</strong>。雖然有免費版可以用，但你打開它的時候，感受上比較像是進入一個完整產品的生態，而不只是開了一個輕量工具。</p><p>更多關於 Lens 的介紹，可參考以下文章：</p><blockquote><p>延伸閱讀：<a href="https://ithelp.ithome.com.tw/articles/10325689">可觀測性宇宙的第八天 - Kubernetes Lens 推坑 K8S GUI 神器介紹</a></p></blockquote><hr><h2 id="Rancher：不只是-cluster-viewer"><a href="#Rancher：不只是-cluster-viewer" class="headerlink" title="Rancher：不只是 cluster viewer"></a>Rancher：不只是 cluster viewer</h2><p><a href="https://www.rancher.com/">Rancher</a> 是由 SUSE 維護的開源平台，跟我<a href="/k3s-for-weamind/">之前文章</a>介紹過的 K3s 是同一家出品。</p><p>它的定位跟前面兩個桌面工具不太一樣。如果只是把它跟 Headlamp、Lens 一起當成「看叢集狀態的工具」，就有點小看它了。</p><p>先用一張表看清楚差異：</p><table><thead><tr><th></th><th>Headlamp &#x2F; Lens</th><th>Rancher</th></tr></thead><tbody><tr><td>定位</td><td>桌面客戶端</td><td>平台級管理介面</td></tr><tr><td>部署方式</td><td>本機安裝，直接吃 kubeconfig</td><td>需要部署到 cluster 或獨立主機上</td></tr><tr><td>使用對象</td><td>個人開發者、學習者</td><td>平台團隊、多叢集管理者</td></tr><tr><td>核心能力</td><td>查看與操作叢集資源</td><td>多叢集治理、權限控管、應用發佈、團隊協作</td></tr></tbody></table><p>Rancher 真正的主場，是平台團隊、多叢集、權限控管這些工作。它解決的是<strong>治理</strong>，而不僅僅是「看懂叢集」這樣的需求。</p><p>Lens 和 Rancher 我在工作上都用過。就個人使用感受來說，Rancher 的 UI 我比較能接受；Lens 那種一看就知道是用 Electron 寫的笨重感，如果可以，我真的不想用XD</p><hr><h2 id="K9s：TUI-的首選"><a href="#K9s：TUI-的首選" class="headerlink" title="K9s：TUI 的首選"></a>K9s：TUI 的首選</h2><p><a href="https://k9scli.io/">K9s</a> 是一個開源的 Kubernetes TUI 工具。所謂 TUI，就是「<strong>Terminal UI</strong>」——在終端機裡提供類似 GUI 的視覺化介面，但以鍵盤操作為主。像 htop（系統監控）、lazygit（Git 操作），都是經典的 TUI 工具。</p><p>如果說 GUI 比較像是幫你<strong>建立畫面感</strong>，那 TUI 更像是幫你<strong>建立操作節奏</strong>——K9s 的價值就在這裡。它快、輕，而且非常排查導向。</p><p>你可以透過它快速切換 namespace、查看 Pod 的狀態、進入容器的 terminal，甚至直接在裡面編輯資源的 YAML。</p><p>跟 Headlamp、Lens 一樣，它也是本機安裝、直接吃 kubeconfig，不需要在 cluster 裡部署任何東西。</p><p>對已經有一點 Kubernetes 手感、也不排斥終端機的人來說，K9s 很容易變成日常主力，因為它剛好補上了 GUI 不擅長的那一面。</p><hr><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p><code>kubectl</code>當然是最重要的，這點無庸置疑。</p><p>GUI 和 TUI 的價值在於，它們讓初學者可以先透過比較友善的介面建立全局感，以更低的認知負擔熟悉 Kubernetes。</p><p>所以如果你問我，Kubernetes 視覺化工具，該從哪個開始？</p><p>那就是 <strong>Headlamp</strong>！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/img-20260412-174100.png&quot; alt=&quot;圖片來源：Headlamp GitHub&quot;&gt;&lt;/p&gt;
&lt;p&gt;前陣子讀《&lt;a href=&quot;https://readmoo.com/book/210309079000101&quot;&gt;從異世界歸來發現只剩自己不會 Kubernetes&lt;/a&gt;》時，作者在開篇不久就推薦了 Kubernetes Dashboard。&lt;/p&gt;
&lt;p&gt;我立刻燃起了興趣！畢竟我本來就是 GUI 愛好者。&lt;/p&gt;
&lt;p&gt;尤其 Kubernetes 這種東西，一開始光是名詞就夠多了。Pod、Deployment、Service、Node、Namespace，還沒開始排查問題，光是先建立畫面感就已經很吃力。&lt;/p&gt;
&lt;p&gt;如果有個視覺化工具，對初學者想必會很有幫助，本書作者也是這麼想的。&lt;/p&gt;
&lt;p&gt;本文想回答的問題是：「現在如果想用視覺化方式看 Kubernetes 叢集，該選什麼？」&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/img-20260412-174100.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="開箱評論" scheme="https://blog.kyomind.tw/tags/%E9%96%8B%E7%AE%B1%E8%A9%95%E8%AB%96/"/>
    
  </entry>
  
  <entry>
    <title>K3s 是什麼？為什麼我選擇用 K3s 部署 WeaMind</title>
    <link href="https://blog.kyomind.tw/k3s-for-weamind/"/>
    <id>https://blog.kyomind.tw/k3s-for-weamind/</id>
    <published>2026-03-29T04:54:39.000Z</published>
    <updated>2026-03-29T14:50:16.812Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png"></p><blockquote><p>📌 這是 <a href="https://github.com/kyomind/WeaMind/blob/main/blogs/README.md">WeaMind 系列</a> 的第 6 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p>「<strong>想學 Kubernetes，要用什麼工具？</strong>」這是我在轉向 DevOps 時，必須回答的問題。</p><p>你可能拿到的標準答案是：「<strong>用 Minikube 或 Kind 在本機開個環境，先跑起來再說</strong>」。這當然沒錯，對多數人來說是合理的起點。但對我而言，問題則複雜一些。</p><p>這篇文章針對「<strong>想自己建 Kubernetes 叢集，但又不想搞得太複雜</strong>」的情境，說明 K3s 是什麼、適合誰，以及我為什麼最後選擇它。</p><span id="more"></span><hr><h2 id="Minikube-和-Kind：合理的工具，但不是我要的"><a href="#Minikube-和-Kind：合理的工具，但不是我要的" class="headerlink" title="Minikube 和 Kind：合理的工具，但不是我要的"></a>Minikube 和 Kind：合理的工具，但不是我要的</h2><p>學習 Kubernetes 的最佳起手式，無疑就是 <a href="https://minikube.sigs.k8s.io/">Minikube</a> 或 <a href="https://kind.sigs.k8s.io/">Kind</a> 這兩個工具。</p><p>它們都是專為在本機快速建立 Kubernetes 環境而設計的，安裝簡單、資源需求低，很適合初學者。</p><p>如果你只是想練習 <code>kubectl</code> 的指令、跑幾個 Deployment 看看效果，這兩個工具已經足夠。可謂進入門檻低、環境乾淨、不用花錢，一台電腦就能搞定。</p><h3 id="方便的代價"><a href="#方便的代價" class="headerlink" title="方便的代價"></a>方便的代價</h3><p>但為了<strong>方便與降低門檻</strong>，它們在架構上都存在著<strong>一定程度的簡化</strong>：網路行為、多節點環境、儲存層，這些都和真實 production 環境有差距。</p><p>這並非缺點，只是<strong>設計上的取捨</strong>——為了在本機好用，犧牲了一些真實性。</p><h3 id="我需要更多真實感"><a href="#我需要更多真實感" class="headerlink" title="我需要更多真實感"></a>我需要更多真實感</h3><p>但對我來說，這個取捨剛好<strong>與我的學習目標衝突</strong>。我準備轉職 DevOps，想多了解建置過程本身：節點怎麼加入叢集、網路介面怎麼配置、Ingress 怎麼和 Load Balancer 串起來等等。</p><p>用真實的 VM 學習，這些議題會<strong>更具體些</strong>，不被環境提前幫你簡化掉。</p><p>剛好我也已經在用 <a href="/hetzner/">Hetzner Cloud</a>，開一台最小規格的 VM 只需一個月數歐元。有這樣的條件，用真實環境學習似乎是<strong>更自然的選擇</strong>。</p><p>簡言之，不是因為 Minikube 或 Kind 不好，而是對我的目標而言，這樣的做法能得到<strong>更接近現實</strong>的學習效果。</p><hr><h2 id="三條-K8s-叢集建置路線"><a href="#三條-K8s-叢集建置路線" class="headerlink" title="三條 K8s 叢集建置路線"></a>三條 K8s 叢集建置路線</h2><p>決定用真實 VM 之後，問題就從「<strong>用哪個工具模擬</strong>」變成「<strong>用哪種方式建立叢集</strong>」。這是另一層選擇，面向的是想認真接觸真實環境的人。此時有三條路可以選：</p><table><thead><tr><th>路線</th><th>control plane 誰管</th><th>維運成本</th><th>適合情境</th></tr></thead><tbody><tr><td>EKS &#x2F; GKE</td><td>雲端供應商</td><td>低</td><td>想專注把服務跑起來、不要自己維護底層</td></tr><tr><td>kubeadm</td><td>自己</td><td>高</td><td>想完整掌握 Kubernetes 底層，或企業需要高度控制</td></tr><tr><td>K3s</td><td>自己</td><td>中</td><td>想自己建叢集，但不想從零組裝每個元件</td></tr></tbody></table><p>這三條路代表三種不同的假設，選哪條取決於你的目標是什麼。以下我們依序來看。</p><h2 id="EKS-GKE：適合想「省事」的人"><a href="#EKS-GKE：適合想「省事」的人" class="headerlink" title="EKS &#x2F; GKE：適合想「省事」的人"></a>EKS &#x2F; GKE：適合想「省事」的人</h2><p><a href="https://aws.amazon.com/eks/">EKS</a> &#x2F; <a href="https://cloud.google.com/kubernetes-engine">GKE</a> 這類服務屬於<strong>託管式 Kubernetes</strong>（managed K8s），也就是<strong>由雲端供應商代管 control plane</strong> 的 Kubernetes。對想把服務跑起來、不想維護基礎設施的情境來說，這是最省事的選擇。</p><p>但「<strong>省事</strong>」只是表面。</p><p>它真正的價值在於<strong>高可用與穩定性</strong>——control plane 的多副本、自動修復、SLA 保證，都不是自己建叢集能輕易複製的——甚至大部分的公司也無法做到這一點。</p><p>這是為什麼大部分 production 環境的首選還是 <a href="https://aws.amazon.com/eks/">EKS</a> 或 <a href="https://cloud.google.com/kubernetes-engine">GKE</a>，而不是自建叢集。</p><p>對企業來說尤其合理——工程師的時間比 VM 費用貴，沒有必要把人力花在 Kubernetes 底層維護上。它的存在價值，就是讓團隊專注在應用層。</p><p>代價是：你幾乎碰不到底層。Control plane 的建置、節點的加入、網路設定大多由雲端處理好，因此你的學習重心會更偏向操作，而不是從頭建置。</p><h2 id="kubeadm：適合想掌控底層的人"><a href="#kubeadm：適合想掌控底層的人" class="headerlink" title="kubeadm：適合想掌控底層的人"></a>kubeadm：適合想掌控底層的人</h2><p><a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/">kubeadm</a> 是 Kubernetes 官方的叢集建置工具，需要你<strong>從頭開始，手動組裝</strong>：安裝 kubelet、設定 API server、用 token 讓 worker node 加入。</p><p>它讓你最直接碰到 Kubernetes 的原生建置流程。這條路適合 platform team，或需要對底層有完整掌控的企業環境。</p><p>其代價是<strong>複雜</strong>——網路套件、憑證管理、etcd 備份，每個環節都要自己處理。</p><p>對我這種單人維運的小型專案來說，這樣的複雜度<strong>很難換來相應的回報</strong>。</p><h2 id="K3s：我的選擇"><a href="#K3s：我的選擇" class="headerlink" title="K3s：我的選擇"></a>K3s：我的選擇</h2><p><a href="https://k3s.io/">K3s</a> <strong>介於兩者之間</strong>。它不像 EKS 那樣把底層全部藏起來，也不像 kubeadm 那樣把所有複雜度都攤在你面前。</p><p>對我來說，這正是我需要的<strong>平衡</strong>。</p><p>我選 K3s 的核心原因很簡單：我不只是想把 Kubernetes 用起來，還想理解它是<strong>怎麼被建起來的</strong>。它的價值不在於「比較輕」，而在於保留了<strong>恰到好處</strong>的建置細節，同時又不會把維運成本一下子拉得太高。</p><p>這是採用 K3s 的幾個實際考量：</p><ul><li><strong>整合度高</strong>：<a href="https://traefik.io/">Traefik</a>、<a href="https://github.com/flannel-io/flannel">Flannel</a> 等網路套件開箱即用，不需要像 kubeadm 一樣逐一自己安裝。</li><li><strong>夠真實</strong>：節點加入、kubeconfig 管理、網路介面綁定這些事還是要自行處理。</li><li><strong>不適合大型叢集</strong>：高度客製化底層或企業級規模的需求，kubeadm 或託管式 K8s 才是更好的選擇。</li></ul><hr><h2 id="K3s-是什麼"><a href="#K3s-是什麼" class="headerlink" title="K3s 是什麼"></a>K3s 是什麼</h2><p><a href="https://k3s.io/">K3s</a> 不是另一套系統，它是 Kubernetes 的一個<strong>發行版</strong>（distribution）。</p><p>「distribution」這個詞，用過 Linux 的人應該不陌生。Linux kernel 是基礎，Ubuntu、Fedora、Arch Linux 則是不同的發行版（distribution）——它們都是 Linux，但各自做了不同的<strong>打包與整合</strong>。</p><p>K3s 和 Kubernetes 的關係類似：它不是另一套不同的系統，而是建立在 <strong>Kubernetes 標準安裝</strong>之上的一個<strong>輕量發行版</strong>，由 Rancher Labs 開發，現由 SUSE（2020 年收購 Rancher Labs）維護，並通過 CNCF 認證。</p><p>這裡說的 Kubernetes 標準安裝，就是 Kubernetes 專案原本提供的元件與安裝方式，不會先幫你把常用元件整合成開箱即用的發行版。</p><p>和標準安裝相比，K3s 的核心差異是：單一執行檔、更精簡的依賴、預設內建 Traefik Ingress Controller，資料儲存則改用 SQLite 這類較輕量的方案，而非原生的 etcd。</p><p>你不需要自己從無到有，把這些零件組裝起來，就能快速擁有一個能跑的叢集。</p><table><thead><tr><th></th><th>Kubernetes 標準安裝</th><th>K3s</th></tr></thead><tbody><tr><td>安裝方式</td><td>多元件分開安裝</td><td>單一執行檔</td></tr><tr><td>預設 Ingress Controller</td><td>無</td><td>Traefik（內建）</td></tr><tr><td>預設網路套件</td><td>無</td><td>Flannel（內建）</td></tr><tr><td>資料儲存</td><td>etcd</td><td>SQLite（預設，可切換）</td></tr><tr><td>記憶體需求</td><td>較高</td><td>較低（適合小型 VM）</td></tr><tr><td>CNCF 認證</td><td>✓</td><td>✓</td></tr></tbody></table><hr><h2 id="WeaMind-的-K3s-叢集長什麼樣"><a href="#WeaMind-的-K3s-叢集長什麼樣" class="headerlink" title="WeaMind 的 K3s 叢集長什麼樣"></a>WeaMind 的 K3s 叢集長什麼樣</h2><p>叢集是 1 個控制平面節點 + 2 個工作節點，跑在 Hetzner 私有網路內。</p><p>可以把這個架構簡單理解成：應用層放進 K3s 叢集，資料層則獨立留在叢集外。</p><p><img src="https://img.kyomind.tw/img-20260329-223939.png" alt="WeaMind K3s 叢集架構圖，使用 Obsidian 渲染"><span class="cap">WeaMind K3s 叢集架構圖，使用 Obsidian 渲染</span></p><p>K3s 預設以 DaemonSet 方式部署 Traefik，所以每台 worker 都會有一個實例。</p><p>外部流量先經過 Hetzner Load Balancer 的 TCP 443 passthrough，再在 Traefik 這一層完成 TLS 終止，憑證則由 cert-manager 向 Let’s Encrypt 取得。</p><p>資料層沒有放進叢集，而是保留在叢集外的堡壘機，透過 Hetzner 私有網路連接。</p><hr><h2 id="結語：剛剛好的複雜"><a href="#結語：剛剛好的複雜" class="headerlink" title="結語：剛剛好的複雜"></a>結語：剛剛好的複雜</h2><p>回到最初的問題：想學 Kubernetes，要用什麼工具？</p><p>如果你的情境和我類似——個人專案或作品集、目標是理解建置過程、不想花大錢——那 K3s + 雲端 VM 是目前我覺得最務實的起點。</p><p>不在 Minikube 和 Kind 之間糾結，也不需要一開始就上託管式 K8s 或硬啃 kubeadm。選一個夠真實、又不會把你淹沒的環境，先跑起來再說。</p><hr><blockquote><p><strong>如果這篇文章對你有幫助，歡迎到 <a href="https://github.com/kyomind/WeaMind">WeaMind GitHub 首頁</a> 給我一個星星</strong><br>想試用 WeaMind，可掃描下方 QR Code 或搜尋 LINE ID <code>@370ndhmf</code> 加入好友<br>你的支持是我持續分享的動力</p></blockquote><p><img src="https://img.kyomind.tw/wea-qrcode-min-20250929-223022.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;https://github.com/kyomind/WeaMind/blob/main/blogs/README.md&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="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="Linux" scheme="https://blog.kyomind.tw/tags/Linux/"/>
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
  </entry>
  
  <entry>
    <title>細數我過去的待業時光（二）律師國考與告別法律</title>
    <link href="https://blog.kyomind.tw/orange-days-02/"/>
    <id>https://blog.kyomind.tw/orange-days-02/</id>
    <published>2026-03-21T04:13:05.000Z</published>
    <updated>2026-03-22T15:42:06.666Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/weekly-review.png"></p><p>〈<a href="/weekly-review-38/">Kyo 待業中！細數我過去的待業時光</a>〉寫到，我在 2011 年底考上書記官，展開人生的第一段職涯。</p><p>再回顧那段待業時光，大概就是從「不知人生為何物」到「好吧，我要努力上榜！」的過程。</p><p>無論如何，最終總算是上榜了，雖然不是律師，但也算是個不錯的結果。</p><p>然而，這樣就可以了嗎？</p><span id="more"></span><hr><h2 id="五年公務員的內心掙扎"><a href="#五年公務員的內心掙扎" class="headerlink" title="五年公務員的內心掙扎"></a>五年公務員的內心掙扎</h2><p>我在法務行政執行署宜蘭分署當了五年多的書記官。</p><p>任職的前兩年，每天早上起床時，<strong>總有個聲音一直在耳邊迴盪</strong>：「法律系畢業，不去考律師、司法官，就這樣當個書記官，是不是有點太沒有志氣了？」</p><p>法律系的「正確答案」，好像不是這個。</p><p>而且我相信有一天，我會突然醒悟，然後就會去考律師了。</p><p>第三、四年，我開始自我說服：「穩定是有價值的，這份工作也沒有什麼不好。薪水夠用，而且我的物欲也不高，還有什麼好嫌的？」也許我就是一個不適合冒險的人，這樣也好。</p><p>到了第五年，滿 30 歲之後，我突然意識到：「<strong>靠！原來我一直在騙自己！</strong>」</p><p>當資深同事不時在討論退休，而年紀相仿的同事對公職的<strong>穩定感</strong>表現出高度的自我認同時，我感受到的是一種「強烈的<strong>孤獨</strong>」——我打從心底<strong>不認同</strong>這些價值觀。</p><blockquote><p>我必須離開。</p></blockquote><hr><h2 id="一邊工作一邊準備的半年"><a href="#一邊工作一邊準備的半年" class="headerlink" title="一邊工作一邊準備的半年"></a>一邊工作一邊準備的半年</h2><p>發現自己在自欺欺人之後，我暗暗決定了方向：先考律師，如果上了，再衝一波名校的法律研究所——遵循著「功能名就法律人」的既定路線往前走。</p><p>只是這個決定，執行起來比想像中難熬。</p><p>法律系都知道，律師國考是一場<strong>長期消耗戰</strong>——題目廣、難度高。至少在我那個年代，能邊工作邊準備並上榜的人，可謂少之又少。</p><p>大多數上榜者不是全職準備，就是在讀研究所的期間通過考試——因為那時候才有足夠充裕的時間。</p><p>但我還在上班。</p><p>於是，我那時的生活就是：6 點下班，先吃飯，吃完往往會很睏XD。只好倒頭就睡，睡到晚上 8、9 點才醒來，才有一點精神開始讀書，讀到 10、11 點。</p><p>就這樣過了半年。</p><p>在相對疲憊的日子裡醒來時，盯著書桌發呆，會不禁思索：「這樣到底是在準備，還是在安慰自己『<strong>有在準備</strong>』？」</p><p>我覺得這樣下去<strong>很可能會考不上</strong>，然後也無法離開這個環境。30 歲的時候還有迴旋的餘地，如果 35 歲我還是一個公務員，那我就真的<strong>哪裡都去不了</strong>了。</p><p>2017 年 4 月，我離職了。</p><hr><h2 id="六個月的全職備考"><a href="#六個月的全職備考" class="headerlink" title="六個月的全職備考"></a>六個月的全職備考</h2><p>離職的時候，我沒有任何「離開法律」的念頭。只覺得自己又「回到正軌」了XD</p><p>但老實說，我也<strong>並不真的很想當律師</strong>——但我只會考試！</p><p>還好，經過書記官考試的「鍛練」，哪怕沒那麼喜歡，我也能全力以赴地準備隨之而來的律師考試。</p><p>有一點值得釐清：律師雖然不是我想要的，但<strong>學習法律</strong>這件事，我還是很樂在其中的。</p><p>法律的邏輯性、系統性，還有對<strong>制度與秩序</strong>的追求，很符合我的價值觀——這大概也解釋了為什麼我會想走 DevOps。</p><p>總之，那六個月，就是讀書。</p><hr><h2 id="考場上的十五分鐘"><a href="#考場上的十五分鐘" class="headerlink" title="考場上的十五分鐘"></a>考場上的十五分鐘</h2><p>律師考試分為一試和二試，一試是選擇題，二試是申論題。</p><p>8 月的一試我最終以「前 3%」的成績通過了，10 月的二試則是決勝負的關鍵。</p><p>而結果就如同〈<a href="https://medium.com/code-and-me/datalog-%E5%91%8A%E5%88%A5%E6%B3%95%E5%BE%8B-ccec58db9acb">告別法律</a>〉裡寫的，我不只沒有考上，還在刑事法那一科的考場上足足哭了 15 分鐘😂</p><p>這就是最終的結果——我<strong>沒有辦法</strong>繼續我的法律之路。所謂的「正軌」，就在要過橋的時候直接斷了。</p><p>沒有「上榜」這座橋梁作為銜接，你是無法再往前一步的。</p><hr><h2 id="等待放榜的兩個月"><a href="#等待放榜的兩個月" class="headerlink" title="等待放榜的兩個月"></a>等待放榜的兩個月</h2><p>考完到放榜，中間有兩個月。</p><p>這兩個月，我什麼也做不了。</p><p>畢竟結果還沒出來，後面的路就沒辦法決定。要繼續準備研究所嗎？如果律師沒上，那準備研究所豈不是一個笑話？</p><blockquote><p>那要不要考其他的東西？畢竟法律人很擅長考試。</p></blockquote><p>但仔細想想，所謂的「其他考試」，基本上全都是公職考試，這又回到了原點——而我已經回不去了。</p><p>那段時間唯一記得的事，是去了在實踐大學舉辦的<a href="https://pansci.asia/archives/author/panfest">泛知識節</a>。聽了一些和 AI、大數據有關的東西，畢竟那時 AlphaGo 已經大紅，感覺一切都要 Data Driven 了。</p><hr><h2 id="Facebook-廣告"><a href="#Facebook-廣告" class="headerlink" title="Facebook 廣告"></a>Facebook 廣告</h2><p>現在說起來或許輕描淡寫，但那個時候的我，真的不知道自己該何去何從，頗有世界觀即將崩潰的絕望感。</p><p>畢竟，從大學一年級開始，到律師落榜為止，我已在法律這條<strong>單一且漫長</strong>的路上，走了超過十年了。</p><p><strong>我只會法律，也只會考試</strong>——原來我的結構竟是如此<strong>脆弱</strong>XD</p><p>想著未來的迷茫時，我在 Facebook 上看到一則廣告，是新竹自強基金會的大數據班的招生廣告。</p><p>這好像是一個方向？</p><p>最後我沒去新竹上課，畢竟太遠了！而是選擇報名台北的資策會大數據班。</p><p>以為要成為很潮的資料分析師，結果並非如此，不過這是下一篇的故事了。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/weekly-review.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;〈&lt;a href=&quot;/weekly-review-38/&quot;&gt;Kyo 待業中！細數我過去的待業時光&lt;/a&gt;〉寫到，我在 2011 年底考上書記官，展開人生的第一段職涯。&lt;/p&gt;
&lt;p&gt;再回顧那段待業時光，大概就是從「不知人生為何物」到「好吧，我要努力上榜！」的過程。&lt;/p&gt;
&lt;p&gt;無論如何，最終總算是上榜了，雖然不是律師，但也算是個不錯的結果。&lt;/p&gt;
&lt;p&gt;然而，這樣就可以了嗎？&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/weekly-review.png" type="image"/>
    
    
    <category term="Self" scheme="https://blog.kyomind.tw/categories/Self/"/>
    
    
    <category term="人生思考" scheme="https://blog.kyomind.tw/tags/%E4%BA%BA%E7%94%9F%E6%80%9D%E8%80%83/"/>
    
  </entry>
  
  <entry>
    <title>WeaMind 專案解析：從單機 LINE Bot 到 K8s 叢集</title>
    <link href="https://blog.kyomind.tw/weamind/"/>
    <id>https://blog.kyomind.tw/weamind/</id>
    <published>2026-03-16T08:02:49.000Z</published>
    <updated>2026-03-29T14:50:16.812Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png"></p><blockquote><p>📌 這是 <a href="https://github.com/kyomind/WeaMind/blob/main/blogs/README.md">WeaMind 系列</a> 的第 5 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p><a href="https://github.com/kyomind/WeaMind">WeaMind</a> 是一個查詢台灣天氣的 LINE Bot——<strong>點擊選單或輸入地名</strong>就能查天氣，是我花了數個月共 150+ 小時催生的 Side Project。</p><p>以下會從<strong>兩個層面</strong>介紹這個專案：</p><ul><li>第一部分是<strong>應用層</strong>（你直接看到、用到的那一面），聊聊這個 Bot 本身的技術設計和工程品質追求。</li><li>第二部分是<strong>基礎設施層</strong>（支撐 Bot 在雲端運行的底層環境），談談為什麼我要把它部署到 K8s 叢集上。</li></ul><p>從本文開始，這個寫了近 5 年的 Python 後端部落格，寫作重心將逐漸從<strong>後端開發</strong>轉向<strong>雲端與 DevOps</strong>。</p><p>這是一個全新的開始。</p><span id="more"></span><hr><h2 id="第一部分：一個天氣-Bot-的誕生"><a href="#第一部分：一個天氣-Bot-的誕生" class="headerlink" title="第一部分：一個天氣 Bot 的誕生"></a>第一部分：一個天氣 Bot 的誕生</h2><blockquote><p>最好的 side project 往往來自於<strong>自己的痛點</strong>。</p></blockquote><p>我個人是中央氣象局「<a href="https://www.cwa.gov.tw/V8/C/S/eservice/app/app_w.html">生活氣象 App</a> 」的<strong>重度使用者</strong>，但每次要在<strong>不同行政區之間</strong>切換查天氣，操作都很麻煩。</p><p>這個痛點存在很久了，一直希望有更好的手機查詢體驗。考慮到氣象資料有<a href="https://opendata.cwa.gov.tw/index">公開資料與 API</a>，我就想說：「乾脆自己做一個 LINE Bot 吧！」</p><p>除此之外，它必須是一個能展示我<strong>真實 Infra 能力</strong>的作品——不只是把 Bot 寫好，而是從程式碼到雲端部署，都<strong>有真實工程水準</strong>的那種。</p><p>多年前，從法律公務員轉職軟體工程師，我正是花了兩個月做了這個「<a href="https://medium.com/code-and-me/my-python-flask-web-service-2844b8b2f7b0">給嗜讀者的 Python Flask 網頁服務</a>」才順利找到工作。</p><h3 id="三個第一次"><a href="#三個第一次" class="headerlink" title="三個第一次"></a>三個第一次</h3><p>這是我<strong>第一次</strong>做 LINE Bot——要學習令人痛苦的 <a href="https://github.com/line/line-bot-sdk-python">LINE Bot SDK - Python</a>😂——強烈懷疑它就是 <strong>Java 版本直接「翻譯」過來</strong>，程式碼非常不 Pythonic！</p><p><strong>第一次</strong>用 FastAPI（工作上都是 Django）、<strong>第一次</strong>大量使用 AI（GitHub Copilot）輔助開發。</p><p>三個「第一次」疊在一起，學習曲線並不低。但正因為有 Copilot 全程參與，一個人也能在合理時間內把這些東西做出來——還做得<strong>有模有樣</strong>！</p><p>老實說，如果沒有 AI 輔助，我大概不會想一口氣挑戰「三個第一次」。</p><p>這大概就是 AI 時代的開發樣貌。</p><hr><h2 id="功能介紹"><a href="#功能介紹" class="headerlink" title="功能介紹"></a>功能介紹</h2><p>WeaMind 的核心功能很直覺：直接輸入行政區名稱就能查天氣，像是「大安區」、「中壢」；也可以<strong>設定住家和公司地址</strong>，之後<strong>一鍵查詢</strong>——<strong>後者</strong>才是重點，因為它真正解決了我切換行政區的難題。</p><p>還有地圖查詢功能，在 LINE 地圖上選任意位置就能查。系統也會記錄最近查過的 5 個地點，方便快速重複查詢。</p><p><img src="https://img.kyomind.tw/2352352we-min-20250929-222126.png" alt="WeaMind UI"><span class="cap">WeaMind UI</span></p><p>我相信這就是一個好的 Bot 該做的事：<strong>簡單易用、直指痛點</strong>。</p><hr><h2 id="應用層架構設計"><a href="#應用層架構設計" class="headerlink" title="應用層架構設計"></a>應用層架構設計</h2><p>做過 LINE Bot 的人都知道，它有幾個<strong>特別的「坑」</strong>：</p><ul><li>webhook <strong>必須在時限內回應</strong>（具體要多久之內是<strong>動態</strong>的，官方不會告訴你），否則 LINE Platform 會重送請求——用戶此時會收到<strong>重複的回覆</strong>，影響體驗。</li><li>無論有心還是無意，少部分用戶可能會<strong>瘋狂連點按鈕</strong>XD。而 LINE Platform 並未提供類似 rate limit 的機制，後端對每個請求都要處理——你的 db 正在燃燒🔥</li><li>webhook handler 邏輯不同於<strong>一般 API 開發</strong>，天然容易變成一團大泥球——解析、查詢、回覆全擠在一起，功能一多就很難看懂與維護。</li></ul><p>WeaMind 對這三個問題都有明確的解法：</p><ul><li><strong>Fast ACK Webhook</strong>：花數十毫秒先回應 LINE Platform，業務邏輯交給 FastAPI 的<code>BackgroundTasks</code>非同步運行，用戶感受到的回應在 <strong>2 秒以內</strong>——實際只需要<strong>幾百毫秒</strong>，但 Hetzner 主機對台灣的延遲很高😂</li><li><strong>Redis 分散式鎖</strong>：按鈕操作有 2 秒鎖定以防止連點，文字查詢則不受影響。</li><li><strong>DDD 模組劃分</strong>：<code>core</code>、<code>user</code>、<code>line</code>、<code>weather</code>四個領域，並以 router → service → model 三層分離，邊界清晰不互相污染。</li></ul><p>更多細節可參考 WeaMind 專案 README 的「<a href="https://github.com/kyomind/WeaMind?tab=readme-ov-file#%E9%96%8B%E7%99%BC%E8%80%85%E6%8A%80%E8%A1%93%E4%BA%AE%E9%BB%9E">開發者技術亮點</a>」。</p><hr><h2 id="工程品質的「刻意」追求"><a href="#工程品質的「刻意」追求" class="headerlink" title="工程品質的「刻意」追求"></a>工程品質的「刻意」追求</h2><p>自己的專案，可以用<strong>自己的標準</strong>。</p><h3 id="我親愛的偏執狂"><a href="#我親愛的偏執狂" class="headerlink" title="我親愛的偏執狂"></a>我親愛的偏執狂</h3><p><strong>100% 的 type hints 覆蓋</strong>——使用 Pyright、<strong>94% 的單元測試覆蓋率</strong>、pre-commit 強制檢查、完整的 CI pipeline。</p><blockquote><p>相關文章：</p><ul><li><a href="/robust-python-01/">《強健的 Python》筆記：如何有效導入 Type Hints</a></li><li><a href="/django-ninja-29/">單元測試——使用 Test Client 與 pytest 測試 API</a></li><li><a href="/pre-commit/">Python 開發：pre-commit 設定 Git Hooks 教學</a></li></ul></blockquote><p>這些都不是偶然，而是<strong>刻意選擇</strong>的結果。在自己的專案裡，終於沒有人會說「這個可以之後再補」。</p><p>你可能會好奇「為什麼測試覆蓋率不是 100%？現在不是有 AI 了嗎？讓它一口氣寫完不就好了？」</p><p>我的看法是，覆蓋率畢竟只是測試品質的其中一個面向而已。為了讓覆蓋率達到百分之百，而寫一大堆不好讀、不好維護的<strong>機械性測試邏輯</strong>，這不符合我的開發價值觀。</p><p>哪怕是在 AI 時代，凡事也宜<strong>適可而止</strong>。</p><h3 id="偏執狂的工具鏈與-CI"><a href="#偏執狂的工具鏈與-CI" class="headerlink" title="偏執狂的工具鏈與 CI"></a>偏執狂的工具鏈與 CI</h3><p>工具鏈基本上是，想的到的一口氣全上了——說好的適可而止呢XD</p><p><a href="https://docs.astral.sh/uv/">uv</a> 管理 Python 虛擬環境；<a href="https://docs.astral.sh/ruff/">Ruff</a> 一個工具取代了 Flake8、Black、isort 三個；<a href="https://github.com/microsoft/pyright">Pyright</a> 做型別檢查。</p><blockquote><p>相關文章：</p><ul><li><a href="/introducing-uv/">Python 套件管理器 uv 介紹——與 Poetry 比較</a></li><li><a href="/ruff/">Python 開發：Ruff Linter、Formatter 介紹 + 設定教學</a></li><li><a href="/pyright/">Pyright 上手指南：Python 型別檢查的新選擇</a></li></ul></blockquote><p>安全掃描建了三層，角色不同：Bandit（靜態分析）、pip-audit（CVE 檢查）、detect-secrets（敏感資料防護）。這是我以前比較生疏的部分，這次特別加強。</p><p>每次 push 都會跑完 Ruff → Pyright → Bandit → pip-audit → pytest + Codecov 的完整流程。</p><blockquote><p>相關文章：<a href="/weamind-ci/">用 Side Project 學 CI：WeaMind 的 CI 實作策略</a></p></blockquote><p>第一階段 CI 通過後，最後會<strong>自動推送</strong>新版 image 到 <a href="https://github.com/kyomind/WeaMind/pkgs/container/weamind">GHCR</a>。</p><hr><h2 id="第二部分：從單機到叢集"><a href="#第二部分：從單機到叢集" class="headerlink" title="第二部分：從單機到叢集"></a>第二部分：從單機到叢集</h2><p>講完應用層，你可能會想：</p><blockquote><p>這個 LINE Bot 跑在單機 VM 上就能正常運作了，幹嘛還要搞 K8s？</p></blockquote><p>原因很簡單：因為這個專案從一開始就「不只是」為了做一個 LINE Bot——它是我為了 DevOps 轉職所做的<strong>刻意練習</strong>。</p><h3 id="K3s-on-Hetzner"><a href="#K3s-on-Hetzner" class="headerlink" title="K3s on Hetzner"></a>K3s on Hetzner</h3><p>我在 <a href="https://www.hetzner.com/">Hetzner</a> 上另外開了三台 VM 組成 K3s 叢集，加上一台付費的 Load Balancer——<strong>都是錢啊啊啊</strong>！🤯</p><p>原本那台跑 Docker Compose 的 VM，在叢集建成後角色順勢轉變為<a href="https://en.wikipedia.org/wiki/Bastion_host">堡壘機</a><strong>兼資料層</strong>，負責跑 PostgreSQL 和 Redis，同時作為 SSH 跳板與管理叢集——雖然我大部分時候都是在本機透過<code>ProxyJump</code>連到 Control Plane 上的 API Server。</p><h3 id="持續演進的平台"><a href="#持續演進的平台" class="headerlink" title="持續演進的平台"></a>持續演進的平台</h3><p>對我來說，這套 Kubernetes 部署不是做完就收工的作品。接下來，我還想在上面實作<a href="https://zh.wikipedia.org/zh-tw/%E5%8F%AF%E8%A7%80%E6%B8%AC%E6%80%A7">可觀測性</a>、<a href="https://helm.sh/">Helm</a> 等 DevOps 必修課題。</p><p>任何我想學的 DevOps 技能，都可以在這上面繼續疊加。它顯然比任何線上課附的 lab 都<strong>有趣且真實</strong>多了——想想就有點小興奮🤩</p><hr><h2 id="Infra-關鍵架構決策"><a href="#Infra-關鍵架構決策" class="headerlink" title="Infra 關鍵架構決策"></a>Infra 關鍵架構決策</h2><p>叢集是 <strong>K3s 三節點</strong>（1 控制平面 + 2 工作節點），跑在 Hetzner 私有網路內；資料層（PostgreSQL + Redis）留在堡壘機，透過內網連接。</p><p><strong>流量路徑</strong>：LINE Platform 的 webhook 請求會先到 Hetzner Load Balancer（TCP 443 passthrough），再由 Traefik Ingress Controller 完成 TLS 終止，最後轉送到 line-bot Service 與 line-bot Pod。</p><h3 id="為什麼選-K3s？"><a href="#為什麼選-K3s？" class="headerlink" title="為什麼選 K3s？"></a>為什麼選 K3s？</h3><p><a href="https://k3s.io/">K3s</a> 是由 <a href="https://www.rancher.com/">Rancher</a>（現為 SUSE）推出的<strong>輕量級 Kubernetes 發行版</strong>，專為<strong>資源受限</strong>的環境設計。</p><p>K3s 這個名稱意味「<strong>比 K8s 少 5 個字元的複雜度</strong>」——本質上就是一個<strong>更精簡、更易部署</strong>的 Kubernetes。</p><p>採單一 binary 檔、內建 Traefik Ingress Controller，並通過 <strong>CNCF 認證</strong>。</p><p>對於單人維運的小型叢集，它可能是<strong>最接近真實環境</strong>（相比於 <a href="https://minikube.sigs.k8s.io/">Minikube</a>、<a href="https://kind.sigs.k8s.io/">Kind</a>）而且<strong>最務實</strong>的選擇。</p><h3 id="為什麼選-Hetzner？"><a href="#為什麼選-Hetzner？" class="headerlink" title="為什麼選 Hetzner？"></a>為什麼選 Hetzner？</h3><blockquote><p>相關文章：<a href="/hetzner/">Hetzner VPS 實測：比 DigitalOcean 更劃算的選擇？</a></p></blockquote><p>當然是因為<strong>便宜</strong>！雖然它在今年 4 月就要<a href="https://www.hetzner.com/pressroom/statement-price-adjustment/">漲價</a>了🥲</p><p>表格是整個架構的所有成本（每月&#x2F;歐元，漲價前、稅前）：</p><table><thead><tr><th>節點</th><th>規格</th><th>月費</th></tr></thead><tbody><tr><td>原 VM（堡壘機兼資料層）</td><td>4C&#x2F;8GB</td><td>€6.5</td></tr><tr><td>K8s 控制平面</td><td>2C&#x2F;4GB</td><td>€3.5</td></tr><tr><td>K8s 工作節點 × 2</td><td>2C&#x2F;4GB</td><td>€7</td></tr><tr><td>Hetzner Load Balancer</td><td>—</td><td>€5</td></tr><tr><td><strong>合計</strong></td><td></td><td><strong>€22&#x2F;月</strong></td></tr></tbody></table><p>總體開銷，差不多等於訂閱一個 ChatGPT Plus 的月費。</p><p>但同樣的機器若要部署在 DigitalOcean 或者 GCP 上，所需的價格大概是 4 到 6 倍。（即使 Hetzner 漲價後也要 3 到 5 倍）</p><p>總之，我愛 Hetzner，德國人萬歲！</p><h3 id="資料層為什麼留在-VM？"><a href="#資料層為什麼留在-VM？" class="headerlink" title="資料層為什麼留在 VM？"></a>資料層為什麼留在 VM？</h3><p>簡潔與穩定性優先。</p><p>PostgreSQL 和 Redis 現階段不需要水平擴展——以後大概也不需要XD，放進 K8s 反而要處理 StatefulSet 和 PV 的管理複雜度。</p><p>而且用內網連接，延遲幾乎可以忽略不計。</p><h3 id="LINE-Webhook-URL-切換"><a href="#LINE-Webhook-URL-切換" class="headerlink" title="LINE Webhook URL 切換"></a>LINE Webhook URL 切換</h3><p>這是一個<strong>意外好用</strong>的設計！</p><p>我原本的想法是：LINE webhook 固定打 <a href="https://api.kyomind.tw/">api.kyomind.tw</a>（你直接點擊網址，會回應<code>&#123;&quot;message&quot;:&quot;Welcome to WeaMind API&quot;&#125;</code>）上的 webhook endpoint，平常 DNS 的 A record 指向 Hetzner Load Balancer。</p><p>若叢集出問題需要 rollback，就<strong>手動把 A record 改回舊 VM 的 IP 地址</strong>，這樣就能快速切換回單機環境。</p><p>但這樣的問題是 <strong>DNS 傳播有延遲</strong>，少則幾分鐘、多則數小時，rollback 並不即時。</p><p>後來發現一個更簡單的做法：保留 <a href="https://api.kyomind.tw/">api.kyomind.tw</a> 指向舊 VM，另外新建一個 <a href="https://k8s.kyomind.tw/">k8s.kyomind.tw</a> 指向 Hetzner Load Balancer——兩個環境各自有固定網址。</p><p>切換時，只要在 LINE Platform 後台<strong>把 webhook URL 從一個換成另一個</strong>，秒級生效，不需要動 DNS。</p><p>這讓 K8s 環境和原本的單機環境可以並行運行，測試和 rollback 都很方便。</p><hr><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p>WeaMind 對我來說不只是一個天氣 Bot。</p><p>應用層是五年後端經驗的集大成之作——終於有機會按自己的標準，從頭到尾做一次。基礎設施則是跨入 DevOps 的第一步，用真金白銀搭出來的練兵場🐥</p><p>如同我在自己的 <a href="https://kyomind.tw/">Landing Page</a> 說的：</p><blockquote><p>AI 與 Infra 是開發者的未來。</p></blockquote><p>而 WeaMind，則是未來的開端。</p><hr><p>想看程式碼的讀者，歡迎逛逛 GitHub，並給我一個 ⭐️ 唷！</p><ul><li>應用層：<a href="https://github.com/kyomind/WeaMind">WeaMind</a></li><li>基礎設施：<a href="https://github.com/kyomind/weamind-infra">weamind-infra</a></li></ul><blockquote><p>想試用 WeaMind，可掃描下方 QR Code 或搜尋 LINE ID <code>@370ndhmf</code> 加入好友<br>你的支持是我持續分享的動力</p></blockquote><p><img src="https://img.kyomind.tw/wea-qrcode-min-20250929-223022.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;https://github.com/kyomind/WeaMind/blob/main/blogs/README.md&quot;&gt;WeaMind 系列&lt;/a&gt; 的第 5 篇。&lt;br&gt;本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/kyomind/WeaMind&quot;&gt;WeaMind&lt;/a&gt; 是一個查詢台灣天氣的 LINE Bot——&lt;strong&gt;點擊選單或輸入地名&lt;/strong&gt;就能查天氣，是我花了數個月共 150+ 小時催生的 Side Project。&lt;/p&gt;
&lt;p&gt;以下會從&lt;strong&gt;兩個層面&lt;/strong&gt;介紹這個專案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一部分是&lt;strong&gt;應用層&lt;/strong&gt;（你直接看到、用到的那一面），聊聊這個 Bot 本身的技術設計和工程品質追求。&lt;/li&gt;
&lt;li&gt;第二部分是&lt;strong&gt;基礎設施層&lt;/strong&gt;（支撐 Bot 在雲端運行的底層環境），談談為什麼我要把它部署到 K8s 叢集上。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;從本文開始，這個寫了近 5 年的 Python 後端部落格，寫作重心將逐漸從&lt;strong&gt;後端開發&lt;/strong&gt;轉向&lt;strong&gt;雲端與 DevOps&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;這是一個全新的開始。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/WeaMind-logo-min.png" type="image"/>
    
    
    <category term="DevOps" scheme="https://blog.kyomind.tw/categories/DevOps/"/>
    
    
    <category term="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="Kubernetes" scheme="https://blog.kyomind.tw/tags/Kubernetes/"/>
    
    <category term="GitHub Actions" scheme="https://blog.kyomind.tw/tags/GitHub-Actions/"/>
    
    <category term="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
  </entry>
  
  <entry>
    <title>我可能「不會」付費 Perplexity</title>
    <link href="https://blog.kyomind.tw/perplexity/"/>
    <id>https://blog.kyomind.tw/perplexity/</id>
    <published>2025-12-28T14:29:52.000Z</published>
    <updated>2026-03-04T16:31:27.732Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/img-20251221-160338.jpeg" alt="from Pixabay"><span class="cap">from Pixabay</span></p><blockquote><p><code>2026/02/08</code>新增段落：<a href="/perplexity/#2026-02-%E6%9B%B4%E6%96%B0%EF%BC%9AResearch-%E4%BD%BF%E7%94%A8%E9%A1%8D%E5%BA%A6%E5%A4%A7%E5%9C%B0%E9%9C%87">2026-02 更新：Research 使用額度大地震</a>。</p></blockquote><blockquote><p><code>2026/02/05</code>更新：今年 2 月初，<a href="/perplexity/#%E6%88%91%E6%9C%80%E5%96%9C%E6%AD%A1%E7%9A%84-Research-%E5%8A%9F%E8%83%BD">Research</a> 功能的使用次數被<a href="https://www.reddit.com/r/perplexity_ai/comments/1qwhej3/9989_reduction_in_research_quota_over_night/">大幅削減</a>——從<strong>每天數百次</strong>降至每月僅 <strong>20 次</strong>（Pro 方案用戶）。這樣的額度對我來說幾乎<strong>不可用</strong>，如果該政策持續，我<strong>必不會考慮付費</strong>。</p></blockquote><p>我從來沒想有過自己會考慮為 Perplexity 付費。</p><p>畢竟，我已經訂閱了好幾個 AI 聊天服務，對「又一個 AI 工具」著實沒有太多期待。</p><p>但用了三個多禮拜之後，這個想法有點動搖了。</p><h2 id="Perplexity-是什麼"><a href="#Perplexity-是什麼" class="headerlink" title="Perplexity 是什麼"></a>Perplexity 是什麼</h2><p>如果你還沒聽過 <a href="https://www.perplexity.ai/">Perplexity</a>，簡單說，它是一個主打「<strong>AI 搜尋</strong>」的服務。當你丟出一個問題時，它會幫你搜尋網路上的大量資料，整理重點，給出給答案。同時把來源清楚列出來。</p><p>它更像是一個<strong>被 AI 強化過的搜尋引擎</strong>，而不是單純的聊天機器人。</p><p>有了這東西，你可以用自然語言問問題，然後它會幫你找出相關資訊，並且用 AI 幫你整理成一個流暢易讀的答案。</p><span id="more"></span><hr><h2 id="原本不看好"><a href="#原本不看好" class="headerlink" title="原本不看好"></a>原本不看好</h2><p>大概半年前，我有用過 Perplexity 的免費版（主要是衝著它的 Research 功能），然而我對它的評價並不算高。</p><p>在我眼中，它就是一個「做得還不錯的 AI 搜尋工具」，重點放在 RAG、資料整理與引用來源。</p><p>這些東西確實有用，但我一直覺得，像 Google、OpenAI 這些大公司，只要認真做，應該很快就能追上，甚至直接輾壓過去。</p><h2 id="每月-20-美元的高級-RAG？"><a href="#每月-20-美元的高級-RAG？" class="headerlink" title="每月 20 美元的高級 RAG？"></a>每月 20 美元的高級 RAG？</h2><p>更具體來說，Perplexity 常被質疑的核心在於：AI 搜尋本質上是一種「高階 RAG」（<a href="https://aws.amazon.com/tw/what-is/retrieval-augmented-generation/">Retrieval-Augmented Generation</a>）——透過搜尋引擎抓取資料，再用 LLM 整理成答案。</p><p>這種技術路線的問題在於，它似乎<strong>沒有真正的護城河</strong>。只要你有搜尋能力、有 LLM，理論上就能做出類似的產品。</p><p>而 OpenAI、Google 這些科技巨頭，不僅有更強的模型訓練能力、更多的資料，還有近乎無限的資源可以燒。</p><p>一旦上述巨頭們決定將 AI 搜尋做得更好、更整合，Perplexity 這種夾層服務的價值就可能迅速歸零。</p><p>這也是為什麼在許多開發者眼裡，它是一個隨時可能被取代的產品。</p><hr><h2 id="免費你送一年-Pro-方案，要不要？"><a href="#免費你送一年-Pro-方案，要不要？" class="headerlink" title="免費你送一年 Pro 方案，要不要？"></a>免費你送一年 Pro 方案，要不要？</h2><p>今年——2025 年，Perplexity 官方非常積極地在推廣，透過各種管道送出免費一年的 Pro 方案。</p><p>可以想見，這種大規模的免費推廣策略，明顯就是想快速累積用戶，讓更多人真正用過之後，願意在一年後續費。</p><p>我自己的資格來源則是 PayPal：只要是 PayPal 會員，就能<a href="https://www.bnext.com.tw/article/84386/perplexity-pro-free">免費兌換</a> Perplexity 一年的 Pro 方案。</p><hr><h2 id="付費太多-AI-服務"><a href="#付費太多-AI-服務" class="headerlink" title="付費太多 AI 服務"></a>付費太多 AI 服務</h2><p>上一篇〈<a href="/essential-subscriptions-2025/">2025 我離不開的 8 項付費訂閱</a>〉提到我有訂閱  ChatGPT Plus、Claude Pro，最近還訂了 Google AI Pro。</p><p>三個聊天機器人了！</p><p>因此，對於這個免費送上門的大禮，不禁有點「用不過來」的感覺。</p><h3 id="一開始根本懶得兌換"><a href="#一開始根本懶得兌換" class="headerlink" title="一開始根本懶得兌換"></a>一開始根本懶得兌換</h3><p>當我知道 Perplexity 有送免費一年的付費方案時，我的第一個反應不是興奮，而是懶。</p><p>心裡想的是：「我現在已經有好幾個在付費使用的 AI 聊天服務了，根本沒有多餘的精力再認真用一個新的服務。」</p><h3 id="不拿白不拿"><a href="#不拿白不拿" class="headerlink" title="不拿白不拿"></a>不拿白不拿</h3><p>接近兌換的截止期限（今年年底），我心裡還是冒出那個很經典的念頭：「反正是免費的，不拿白不拿！」</p><p>我甚至很清楚，這大概就是 Perplexity 預期中的使用者心理——它就是篤定你會抱著這種「先拿再說」的心情兌換，然後在某個時刻真的願意為它付費。</p><p>我不覺得我會，但我還是兌換了。</p><hr><h2 id="好像有點意思"><a href="#好像有點意思" class="headerlink" title="好像有點意思"></a>好像有點意思</h2><p>從 12&#x2F;5 開始用，到現在差不多快一個月。</p><p>我發現，我愛上它了。</p><p>倒不是 Perplexity 有什麼特別炫的功能，而是我用它的頻率確實很高。</p><p>想想原因也不難理解，因為它解決了一個我很常遇到的需求：<strong>快速搜尋並整理資訊</strong>。</p><h2 id="AI-搜尋是一個明確的使用場景"><a href="#AI-搜尋是一個明確的使用場景" class="headerlink" title="AI 搜尋是一個明確的使用場景"></a>AI 搜尋是一個明確的使用場景</h2><p>這讓我重新意識到：AI 搜尋其實是一個<strong>非常明確的使用場景</strong>。</p><p>當我想用 AI 來搜尋資料時，我期待的不是陪我聊天、也不是幫我發揮創意——這是我對 ChatGPT、Claude 的用法。</p><p>而是快速蒐集大量資訊，幫我整理、過濾，讓我更快抓到重點。</p><p>關鍵是，我知道，這些資訊<strong>「必須」透過網路搜尋</strong>才能更加完整、正確。</p><h2 id="真的沒有護城河？"><a href="#真的沒有護城河？" class="headerlink" title="真的沒有護城河？"></a>真的沒有護城河？</h2><p>問題不在於 ChatGPT 或 Gemini 做不到這件事，而是它們沒有——未來可能也不會——把重心放在這裡。</p><p>Google：網路搜尋就是它的核心業務，怎麼可能希望你僅僅透過聊天機器人來搜尋？</p><p>OpenAI：競爭激烈，搞模型都來不及了，哪有時間優化 AI 搜尋品質？（話說回來 o3 時期曾讓我非常驚艷，但已成追憶）</p><p>Claude：<strong>AI 輔助程式設計</strong>才是它的絕對主場XD。</p><p>簡單來說，這些大公司<strong>沒有動機</strong>把 AI 搜尋做得很好，因為它們的核心業務不在這裡。</p><hr><p>講講我覺得 Perplexity 好用的地方。</p><p>附帶一提，Pro 和免費的搜尋品質有一定差距，難怪以前我並不覺得它好用。</p><h2 id="具體有用在哪？"><a href="#具體有用在哪？" class="headerlink" title="具體有用在哪？"></a>具體有用在哪？</h2><p>舉例來說，如果我想和 ChatGPT 聊聊《<a href="https://zh.wikipedia.org/zh-tw/%E5%A4%A7%E6%98%8E%E7%8E%8B%E6%9C%9D1566">大明王朝 1566</a>》的劇情，或討論「日本高度人才簽證」的細節，它肯定答不好。</p><p>要嘛是訓練的語料不夠多，要嘛就是資訊不夠新。</p><p>以前遇到這種情況，我可能會自己去搜尋資料。但坦白說，絕大部分的事，都沒有重要到需要我親自去搜尋、整理。</p><p>現在有了 Perplexity，交給它就好。這就是我最常用它的場景。</p><h2 id="我最喜歡的-Research-功能"><a href="#我最喜歡的-Research-功能" class="headerlink" title="我最喜歡的 Research 功能"></a>我最喜歡的 Research 功能</h2><p>自從 OpenAI 率先推出「<a href="https://openai.com/zh-Hant/index/introducing-deep-research/">Deep Research</a>」後，許多 AI 服務都跟進了類似的功能。</p><p>目前評價最高的是 OpenAI 和 Google。雖然搜尋用時往往比較久，但搜尋深度和品質都很好。</p><p>但是！我要說「<strong>但是</strong>」。</p><p>上述服務我都有訂，但我最常用的，還是 Perplexity 的 <a href="https://www.perplexity.ai/hub/blog/introducing-perplexity-deep-research">Research</a> 功能。</p><p>原因有三：</p><ol><li>它的搜尋深度普通，但速度較快，大概 30 秒到 2 分鐘之間就能出結果。唉！時間很重要，而且大部分的主題，也不值得我花上 5 分鐘等待😅</li><li>產出報告的排版很美！我真的很受不了 ChatGPT 那亂七八糟的排版XD</li><li>有 AI 產生的圖表支援！</li></ol><p><img src="https://img.kyomind.tw/img-20251228-223520.png" alt="附圖表的研究報告"><span class="cap">附圖表的研究報告</span></p><p>簡而言之，和「AI 搜尋」的情況類似，Perplexity 的 Research 功能，被認真視為產品的重要一環，擁有良好的使用者體驗——至少對我來說如此。</p><p>至於 AI 巨頭們，顯然暫時不會有時間、心力把這些邊緣功能做得很好。</p><hr><h2 id="2026-02-更新：Research-使用額度大地震"><a href="#2026-02-更新：Research-使用額度大地震" class="headerlink" title="2026-02 更新：Research 使用額度大地震"></a>2026-02 更新：Research 使用額度大地震</h2><p>然而，就在 2026 年 2 月初，一切都變了。</p><p>我突然發現，我的 Research 額度從原本的每月幾百次，<strong>直接變成了 20 次</strong>。</p><p>一開始我以為是系統出錯，但看到 <a href="https://www.reddit.com/r/perplexity_ai/comments/1qwhej3/9989_reduction_in_research_quota_over_night/">Reddit 這串討論</a>後才發現，這是 Perplexity 針對所有付費用戶進行的<strong>無預警大規模削減</strong>。</p><h3 id="滾動式更新的惡夢"><a href="#滾動式更新的惡夢" class="headerlink" title="滾動式更新的惡夢"></a>滾動式更新的惡夢</h3><p>這 20 次額度採用的仍是 Perplexity 最常見的「滾動式視窗」（Rolling Window）更新機制。</p><p>簡單說，如果你在 1 月 10 日用了 2 次，這 2 次要等到 2 月 9 日（滿 30 天）才會釋放回來。</p><p>這意味著，如果你在某天為了研究一個複雜問題連續用了 10 次，接下來可能有兩週的時間幾乎無法使用這個功能。</p><p>我自己的經驗就是：過了兩天，只恢復了 2 次。</p><h3 id="每月-20-次就是個笑話"><a href="#每月-20-次就是個笑話" class="headerlink" title="每月 20 次就是個笑話"></a>每月 20 次就是個笑話</h3><p>老實說，對於任何認真使用 AI 工具的人來說，<strong>每月 20 次幾乎等於不可用</strong>。</p><p>這功能最大的價值在於可以<strong>隨意搜尋</strong>，對特定主題有著多一些的理解，但現在每用一次都要斤斤計較、小心翼翼，深怕浪費了「珍貴」的額度。</p><p>Reddit 上的討論串充滿了憤怒與失望，許多人表示會立即取消訂閱。我完全理解這種情緒——雖然我還沒有真的付費辣😅</p><p>但如果這樣的額度限制持續下去，Perplexity 將從我的「可能付費」清單中直接除名。</p><p>因為 Research 對我的實用價值真的很高，如果它變得不可用，那麼僅僅是它方便的一般搜尋，並不足以說服我付出每月 20 美元的訂閱費。</p><hr><h2 id="結語：可能會付費"><a href="#結語：可能會付費" class="headerlink" title="結語：可能會付費"></a>結語：可能會付費</h2><p>現在才用了 Perplexity 快一個月，距離真正需要掏錢續費，還有很長一段時間。</p><p>即便如此，我已經可以很誠實地說：我可能會付費。</p><p>不是因為我特別喜歡這個產品，也不是因為它有多厲害的黑科技，而是在「AI 搜尋」這個情境下，它確實解決了我的需求。</p><p>此外，它的 UI 也得到我的高度贊賞——這讓我更願意花時間使用它。</p><p>至於一年後會不會真的續費，我還不知道。但至少現在，我已經不會輕易地說「它只是一個隨時可能被取代的產品」了。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/img-20251221-160338.jpeg&quot; alt=&quot;from Pixabay&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/02/08&lt;/code&gt;新增段落：&lt;a href=&quot;/perplexity/#2026-02-%E6%9B%B4%E6%96%B0%EF%BC%9AResearch-%E4%BD%BF%E7%94%A8%E9%A1%8D%E5%BA%A6%E5%A4%A7%E5%9C%B0%E9%9C%87&quot;&gt;2026-02 更新：Research 使用額度大地震&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;2026/02/05&lt;/code&gt;更新：今年 2 月初，&lt;a href=&quot;/perplexity/#%E6%88%91%E6%9C%80%E5%96%9C%E6%AD%A1%E7%9A%84-Research-%E5%8A%9F%E8%83%BD&quot;&gt;Research&lt;/a&gt; 功能的使用次數被&lt;a href=&quot;https://www.reddit.com/r/perplexity_ai/comments/1qwhej3/9989_reduction_in_research_quota_over_night/&quot;&gt;大幅削減&lt;/a&gt;——從&lt;strong&gt;每天數百次&lt;/strong&gt;降至每月僅 &lt;strong&gt;20 次&lt;/strong&gt;（Pro 方案用戶）。這樣的額度對我來說幾乎&lt;strong&gt;不可用&lt;/strong&gt;，如果該政策持續，我&lt;strong&gt;必不會考慮付費&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我從來沒想有過自己會考慮為 Perplexity 付費。&lt;/p&gt;
&lt;p&gt;畢竟，我已經訂閱了好幾個 AI 聊天服務，對「又一個 AI 工具」著實沒有太多期待。&lt;/p&gt;
&lt;p&gt;但用了三個多禮拜之後，這個想法有點動搖了。&lt;/p&gt;
&lt;h2 id=&quot;Perplexity-是什麼&quot;&gt;&lt;a href=&quot;#Perplexity-是什麼&quot; class=&quot;headerlink&quot; title=&quot;Perplexity 是什麼&quot;&gt;&lt;/a&gt;Perplexity 是什麼&lt;/h2&gt;&lt;p&gt;如果你還沒聽過 &lt;a href=&quot;https://www.perplexity.ai/&quot;&gt;Perplexity&lt;/a&gt;，簡單說，它是一個主打「&lt;strong&gt;AI 搜尋&lt;/strong&gt;」的服務。當你丟出一個問題時，它會幫你搜尋網路上的大量資料，整理重點，給出給答案。同時把來源清楚列出來。&lt;/p&gt;
&lt;p&gt;它更像是一個&lt;strong&gt;被 AI 強化過的搜尋引擎&lt;/strong&gt;，而不是單純的聊天機器人。&lt;/p&gt;
&lt;p&gt;有了這東西，你可以用自然語言問問題，然後它會幫你找出相關資訊，並且用 AI 幫你整理成一個流暢易讀的答案。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/img-20251221-160338.jpeg" 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="付費訂閱" scheme="https://blog.kyomind.tw/tags/%E4%BB%98%E8%B2%BB%E8%A8%82%E9%96%B1/"/>
    
  </entry>
  
  <entry>
    <title>2025 我離不開的 8 項付費訂閱</title>
    <link href="https://blog.kyomind.tw/essential-subscriptions-2025/"/>
    <id>https://blog.kyomind.tw/essential-subscriptions-2025/</id>
    <published>2025-09-20T00:42:48.000Z</published>
    <updated>2026-03-20T01:13:20.597Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/weekly-review.png"></p><p>2 年前，我寫下這篇〈<a href="/essential-subscriptions-2023/">2023 那些我已不可或缺的「付費訂閱」推薦</a>〉，分享了當時對我而言最重要的 12 項付費訂閱。</p><p>並說明了「不可或缺」的定義：</p><blockquote><p>所謂的「不可或缺」，意思是一旦我停止訂閱，我的工作和生活都會出現挑戰。而挑戰的大小，就是這些訂閱項目對我的影響力與價值。</p></blockquote><p>但回頭再看，有些其實<strong>沒那麼重要</strong>啦😅</p><p>所以這個 2025 年版本，要認真檢視，只列出那些「真的無法取消」的訂閱。</p><p>本文所列出的 8 項，即使多數和 2 年前相同，我也會補充它們對我的「<strong>重要性變化</strong>」與現況。</p><p>它們都很重要，很難說哪個更優先，以下排名<strong>不分先後</strong>。</p><p>此外，和 2023 版重複的基本使用情境介紹，就不再贅述，請參考前文。</p><span id="more"></span><hr><h2 id="一、Setapp"><a href="#一、Setapp" class="headerlink" title="一、Setapp"></a>一、Setapp</h2><p>像 Cleanshot X、Paste、PopClip、TablePlus、TextSniper 這些工具，早已是我每日必備——沒有一天不用的！</p><p>和 2 年前相比，我從每個月 10 美元的單機訂閱，變成 15 美元的 Power User 方案（4 台機器），因為我開始需要<strong>多裝置使用</strong>。</p><p>無論是 10 美元或 15 美元，都不能算是便宜。我個人訂閱它的核心判斷標準，是裡面只要有 3-4 個你每天都會用到的 app，就算值得了。</p><blockquote><p>有興趣可以使用<a href="https://go.setapp.com/invite/ga4xxrhb">我的邀請連結</a>註冊，你、我皆可<strong>額外獲得一個月訂閱</strong>。</p></blockquote><hr><h2 id="二、ChatGPT-Plus"><a href="#二、ChatGPT-Plus" class="headerlink" title="二、ChatGPT Plus"></a>二、ChatGPT Plus</h2><p>前文提到：</p><blockquote><p>如果你問我，我對這個服務目前為止的定價接受度上限為何？我可能會說是每月 40 美元——可見我確實離不開它。</p></blockquote><p>兩年前的 ChatGPT，對我而言猶如神一般的存在，重要性無可比擬。</p><p>兩年過去，AI 聊天服務的選擇越來越多，有力的競爭對手也更多了。</p><p>現在的我，確確實實「<strong>只願意</strong>」花 20 美元訂閱 ChatGPT Plus。</p><p>但平心而論，目前 AI 服務付費主流多是 20 美元一個月，而 OpenAI 給的運算資源與使用量，還是很慷慨的——畢竟它很有錢！</p><hr><h2 id="三、Claude-Pro"><a href="#三、Claude-Pro" class="headerlink" title="三、Claude Pro"></a>三、Claude Pro</h2><p>Claude Pro 方案一樣是每月 20 美元，因日前的「<a href="https://www.threads.com/@code.me.maybe/post/DONWdBWgJq_/">前 3 個月半價優惠</a>」吸引而訂閱；不過另一方面，也是為了使用 <a href="https://claude.com/product/claude-code">Claude Code</a>。</p><p>Claude Pro 和 ChatGPT Plus 對我而言，存在一定程度上的<strong>互補關係</strong>。雖然兩者疊加起來的費用實在不便宜😅</p><h3 id="Claude-的專案功能（Projects）"><a href="#Claude-的專案功能（Projects）" class="headerlink" title="Claude 的專案功能（Projects）"></a>Claude 的專案功能（Projects）</h3><p>簡單來說，<a href="https://www.ithome.com.tw/news/163666">專案功能</a>是我持續訂閱 Claude Pro 的主要原因。</p><p>雖然這功能 ChatGPT 也有（或者說大家都有XD），但我個人覺得 Claude 版的 UI&#x2F;UX 設計較佳，所以我都用它的專案。</p><p>我主要用它來建立關於個人的「知識庫」，附上 10 份精心準備的個人背景資料，和 AI 一起討論人生與職涯——這需求對我來說很重要。</p><p>而且，每家 AI 的「個性」不同，我覺得 Claude 模型對 prompt 的遵守程度較高，尤其是我要求 AI 必須<strong>直白回應</strong>時。</p><p>ChatGPT 基於某種「<strong>偶像包袱</strong>」，預設的口吻往往偏溫和。但你要求它直白又容易矯枉過正。</p><p>像職涯規劃這種關鍵議題，我需要 AI 先「電」我，然後再提供適量的<strong>情緒價值</strong>（自我 PUA！——你該不會也好這口吧？）。</p><p>我目前還未大量使用 Claude Code，習慣問題！還在學習中。</p><hr><h2 id="四、GitHub-Copilot-Pro"><a href="#四、GitHub-Copilot-Pro" class="headerlink" title="四、GitHub Copilot Pro+"></a>四、GitHub Copilot Pro+</h2><p>便宜又大碗的 AI 程式開發助理。</p><p>上個月<a href="https://www.threads.com/@kyomind.tw/post/DN9hbl1gU8m">我從 Pro 升級到 Pro+</a>，每月 39 美元，年付則為 390 美元。</p><p>GitHub Copilot 仗著微軟爸爸的 Azure 算力資源作為靠山，在 LLM token 成本上就與其它競爭對手——比如 Cursor 更具優勢。</p><p>去年此時，Cursor 正火，很多人擔心 GitHub Copilot 地位不保，連我自己都<a href="https://blog.kyomind.tw/cursor/#%E7%B5%90%E8%AA%9E%EF%BC%9A%E7%AB%B6%E7%88%AD%E6%98%AF%E5%A5%BD%E4%BA%8B">不禁有此疑慮</a>。</p><p>現在看來，GitHub Copilot 仍是我最常用的 AI 開發助理。而且此刻的我，對於任何其它「IDE 型態」的 AI 開發助手，<strong>都已顯得興趣缺缺</strong>。</p><hr><h2 id="五、Bear：反璞歸真的筆記軟體"><a href="#五、Bear：反璞歸真的筆記軟體" class="headerlink" title="五、Bear：反璞歸真的筆記軟體"></a>五、Bear：反璞歸真的筆記軟體</h2><p>在〈<a href="/noteless/">逐漸被我遺忘的卡片筆記</a>〉發表後，Bear 逐漸成為我筆記的主力。</p><p>在歷經 Notion、Logseq 等「全能型」筆記軟體的洗禮後，我回到了 Bear。</p><p>唉，事情真的<strong>不用那麼複雜</strong>，筆記甚至也<strong>不是</strong>學習的神兵利器——實作才是。雖然有人說自己「<a href="https://github.com/kyomind#%E7%B0%A1%E4%BB%8B">不做筆記便不會學習</a>」，但這八成是個誤解啦！</p><p>我該放下了。</p><blockquote><p>相關文章：<a href="/bear/">Evernote 替代方案——筆記軟體 Bear 2 升級心得</a></p></blockquote><hr><h2 id="六、YouTube-Premium：內容沉迷的稅金"><a href="#六、YouTube-Premium：內容沉迷的稅金" class="headerlink" title="六、YouTube Premium：內容沉迷的稅金"></a>六、YouTube Premium：內容沉迷的稅金</h2><p>我仍然是 YouTube 的重度使用者，尤其在限制自己少碰社群平台後，YouTube 幾乎成為我獲取資訊的主要來源。</p><p>我知道看多了不健康啦！我有控制少看短影片。</p><blockquote><p>相關文章：<a href="/weekly-review-19/">AI 時代的生存指南（二）數位斷捨離</a></p></blockquote><p>恩……顯然還不夠。</p><hr><h2 id="七、TPASS：城市移動的自由感"><a href="#七、TPASS：城市移動的自由感" class="headerlink" title="七、TPASS：城市移動的自由感"></a>七、TPASS：城市移動的自由感</h2><p>TPASS 依然是我最喜歡的「物理型訂閱」，它給我的不只是通勤折扣，而是一種<strong>城市間游走的機動性與自由感</strong>。</p><p>無需計算轉乘、無需考慮里程、無需遲疑是否要改搭捷運，它讓我更像是這座城市的使用者，而不只是過客。</p><p>我酷愛這種感覺。</p><hr><h2 id="八、Hetzner：你需要一台機器"><a href="#八、Hetzner：你需要一台機器" class="headerlink" title="八、Hetzner：你需要一台機器"></a>八、Hetzner：你需要一台機器</h2><p>我從 DigitalOcean 轉向 Hetzner，單純是因為——<strong>太便宜了</strong>。</p><p>之前已經寫過兩篇文章介紹 Hetzner：</p><ul><li><a href="/hetzner/">Hetzner VPS 實測：比 DigitalOcean 更划算的選擇？</a></li><li><a href="/hetzner-vm/">在 Hetzner 開新 VM 指南：選機房、SSH 連線、設定防火牆</a></li></ul><p>Hetzner 以相同的價格，提供更好的性能與資源，<strong>這無疑是一種自由</strong>。除了延遲較高，已然無可挑剔。</p><p>我目前在 VM 上部署了：</p><ul><li><a href="https://www.usememos.com/">Memos</a>：輕量級筆記系統，參考〈<a href="/memos/">開源工具 Memos 介紹：寫日記的好選擇</a>〉</li><li><a href="https://umami.is/">Umami</a>：網站分析工具、GA4 替代品，參考〈<a href="/weekly-review-21/">在 VM 上部署 Umami 替代 GA4</a>〉</li><li><a href="https://wakapi.dev/">Wakapi</a>：開發時間統計工具、<a href="https://medium.com/code-and-me/%E7%94%A8-wakatime-%E8%87%AA%E6%88%91%E7%9B%A3%E6%8E%A7-f59599144e28">Wakatime</a> 替代品</li><li><a href="https://github.com/kyomind/WeaMind">WeaMind</a>：個人專案</li><li>Nginx、Certbot、<a href="https://www.portainer.io/">Portainer</a> 等等</li></ul><p>上述服務總共才用了 1 GB RAM，我還有 7 GB 的餘裕。</p><p>這樣 4 CPU、8GB RAM 規格的 VM，每月竟然只要 6.5 歐元，實在太划算了。</p><p>對開發者而言，用來部署工具、服務的<strong>基礎設施</strong>顯然不可或缺。而 Hetzner，就是我最喜歡的選擇，沒有之一。</p><blockquote><p>歡迎使用<a href="https://hetzner.cloud/?ref=gD26JqrE8c9t">我的推薦連結</a>註冊，你可以直接獲得 20 歐元的使用額度。</p></blockquote><hr><h2 id="結語：那些留下來的"><a href="#結語：那些留下來的" class="headerlink" title="結語：那些留下來的"></a>結語：那些留下來的</h2><p>這篇文章不算推薦文，比較像是一份選擇紀錄。</p><p>這些訂閱不一定是「最潮」、「最便宜」或「最多功能」，而是經過時間淘選後，我仍願意花錢留下來的服務。</p><p>它們對我來說，有的是生產力的延伸、有的是生活的潤滑、有的是創作的媒介。</p><p>希望這份清單對你有用。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/weekly-review.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;2 年前，我寫下這篇〈&lt;a href=&quot;/essential-subscriptions-2023/&quot;&gt;2023 那些我已不可或缺的「付費訂閱」推薦&lt;/a&gt;〉，分享了當時對我而言最重要的 12 項付費訂閱。&lt;/p&gt;
&lt;p&gt;並說明了「不可或缺」的定義：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;所謂的「不可或缺」，意思是一旦我停止訂閱，我的工作和生活都會出現挑戰。而挑戰的大小，就是這些訂閱項目對我的影響力與價值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但回頭再看，有些其實&lt;strong&gt;沒那麼重要&lt;/strong&gt;啦😅&lt;/p&gt;
&lt;p&gt;所以這個 2025 年版本，要認真檢視，只列出那些「真的無法取消」的訂閱。&lt;/p&gt;
&lt;p&gt;本文所列出的 8 項，即使多數和 2 年前相同，我也會補充它們對我的「&lt;strong&gt;重要性變化&lt;/strong&gt;」與現況。&lt;/p&gt;
&lt;p&gt;它們都很重要，很難說哪個更優先，以下排名&lt;strong&gt;不分先後&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;此外，和 2023 版重複的基本使用情境介紹，就不再贅述，請參考前文。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/weekly-review.png" type="image"/>
    
    
    <category term="心得" scheme="https://blog.kyomind.tw/categories/%E5%BF%83%E5%BE%97/"/>
    
    
    <category term="GitHub Copilot" scheme="https://blog.kyomind.tw/tags/GitHub-Copilot/"/>
    
    <category term="筆記軟體" scheme="https://blog.kyomind.tw/tags/%E7%AD%86%E8%A8%98%E8%BB%9F%E9%AB%94/"/>
    
    <category term="付費訂閱" scheme="https://blog.kyomind.tw/tags/%E4%BB%98%E8%B2%BB%E8%A8%82%E9%96%B1/"/>
    
    <category term="Setapp" scheme="https://blog.kyomind.tw/tags/Setapp/"/>
    
  </entry>
  
  <entry>
    <title>用 Side Project 學 CI：WeaMind 的 CI 實作策略</title>
    <link href="https://blog.kyomind.tw/weamind-ci/"/>
    <id>https://blog.kyomind.tw/weamind-ci/</id>
    <published>2025-08-31T06:56:59.000Z</published>
    <updated>2026-03-20T01:04:44.010Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/WeaMind-logo-min.png"></p><blockquote><p>📌 這是 <a href="https://github.com/kyomind/WeaMind/blob/main/blogs/README.md">WeaMind 系列</a> 的第 4 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p>〈<a href="/github-actions">GitHub Actions 入門：自動化 Lint、Format 與 Type Check</a>〉一文中，我們使用了 GitHub Actions 作為 CI（<a href="https://zh.wikipedia.org/zh-tw/%E6%8C%81%E7%BA%8C%E6%95%B4%E5%90%88">持續整合</a>）的入門工具。</p><p>同時建立了軟體開發專案中最基本且常見的 CI 流程。</p><p>接下來，我將繼續介紹，WeaMind 專案中<strong>所有實作的 CI 項目</strong>，並說明我選擇它們的原因與設計原則。</p><p>本文依據的專案程式碼版本為 <a href="https://github.com/kyomind/WeaMind/tree/v0.5.1">v0.5.1</a>。</p><span id="more"></span><hr><h2 id="從-CRUD-到-CI-CD"><a href="#從-CRUD-到-CI-CD" class="headerlink" title="從 CRUD 到 CI&#x2F;CD"></a>從 CRUD 到 CI&#x2F;CD</h2><p>當我們剛開始軟體開發職涯時，確保功能與邏輯的正確，無疑是工作上的第一要務。</p><p>我們專注於「<strong>寫出正確的程式碼</strong>」（這時可能連「優雅」都還稱不上），而不太關心整個開發流程的健全度——或者說「還沒有能力」去關心。</p><p>我們忙著學習框架、查資料、確認 API response 是否符合 spec、debug 各種問題。</p><p>隨著年資增長，我們會發現一個殘酷現實：<strong>即使程式碼寫得再好，若部署流程設計不當，系統的穩定性仍然會大打折扣</strong>。</p><p>而 CI 正是<strong>連接開發與部署的關鍵橋樑</strong>，是守護程式碼品質與服務穩定的核心機制。</p><hr><p>那麼，一個專案的 CI 應該包含哪些項目？如何在「實用」與「簡潔」之間取得平衡？</p><p>這個答案自然得因地制宜——但也有一些<strong>共通原則</strong>。</p><p>這裡我以 WeaMind 專案為例，說明我在 CI 設計上的實作與考慮。</p><h2 id="WeaMind-CI-項目一覽"><a href="#WeaMind-CI-項目一覽" class="headerlink" title="WeaMind CI 項目一覽"></a>WeaMind CI 項目一覽</h2><p>我不會在這裡提供詳細的設定教學，因為每個專案的需求不同，而且<strong>只有在自己的專案中實際操作，才能真正理解每個設定的意義</strong>。</p><p>所以我們<strong>點到為止</strong>，但仍會提供一些基本的指引與參考。比起做法（問 AI 就足夠了），更重要的是其中的<strong>思路</strong>。</p><p>WeaMind 專案目前整合的 CI 項目如下，每一項都會說明實作方式與用途。</p><p>不過，一到五才是<strong>嚴格意義上的 CI</strong>；六、七則屬於<strong>自動化流程</strong>的一部分。</p><hr><h2 id="一、程式碼品質檢查：Lint、Format、Type-Check"><a href="#一、程式碼品質檢查：Lint、Format、Type-Check" class="headerlink" title="一、程式碼品質檢查：Lint、Format、Type Check"></a>一、程式碼品質檢查：Lint、Format、Type Check</h2><p>實作概要：</p><ul><li>使用<code>ruff check</code>、<code>ruff format</code>、<code>pyright</code>等指令檢查程式碼品質</li><li>全部定義在 <a href="https://github.com/kyomind/WeaMind/blob/v0.5.1/.github/workflows/ci.yml">ci.yml</a> 中，執行環境使用 uv 官方容器</li><li>檢查會在 PR 或 push 到 main 時自動執行，避免髒 commit 混入 main</li></ul><p>這些是上述文章的介紹重點，屬於<strong>基本中的基本</strong>。</p><h2 id="二、覆蓋率分析報告：Codecov"><a href="#二、覆蓋率分析報告：Codecov" class="headerlink" title="二、覆蓋率分析報告：Codecov"></a>二、覆蓋率分析報告：Codecov</h2><p>實作概要：</p><ul><li>使用<code>pytest</code>搭配<code>pytest-cov</code>收集測試覆蓋率，產生<code>coverage.xml</code></li><li>在<code>ci.yml</code>中設定資料自動上傳至 Codecov，產出覆蓋率分析報告</li><li>使用  <a href="https://github.com/kyomind/WeaMind/blob/v0.5.1/.github/codecov.yml">codecov.yml</a> 對 GitHub App 的行為進行客製化——主要是關閉成功留言、比對 patch 覆蓋率</li></ul><p><strong>單元測試</strong>無疑是 CI 中最重要的環節之一。</p><p>做<strong>覆蓋率分析報告</strong>的工具有很多，我選擇 <a href="https://about.codecov.io/">Codecov</a> 因為它與 GitHub 整合度高，且對開源專案來說非常友善。</p><p>不過，測試函式和覆蓋率報告<strong>仍需要你在 CI 流程中預先準備好</strong>。分析報告只是提供了一個<strong>視覺化結果</strong>，幫助你快速了解測試覆蓋的情況。</p><p>你可以透過 GitHub Actions 執行（需要定義自己的 YAML 檔） Codecov，或連接官方提供的 <a href="https://github.com/marketplace/codecov">GitHub App</a>，直接在 CI 流程中上傳覆蓋率報告即可。</p><p>我選擇後者。因為它更簡單，且已能夠自動處理許多細節。</p><h2 id="三、Docker-Build-驗證"><a href="#三、Docker-Build-驗證" class="headerlink" title="三、Docker Build 驗證"></a>三、Docker Build 驗證</h2><p>實作概要：</p><ul><li>使用<code>docker/setup-buildx-action</code>建立建置環境，執行<code>docker buildx build</code>驗證 Dockerfile</li><li>這項檢查對我來說是一種「部署預演」，能在尚未正式上線前提早發現問題</li><li>定義在<code>ci.yml</code>，<strong>平行執行</strong>，不影響主流程速度</li></ul><p>雖然尚未導入 CD，但透過建構 Image 的預演流程，能及早發現 Dockerfile 中潛在的錯誤，有助於減少部署時的風險。</p><hr><h2 id="四、安全掃描：GitHub-CodeQL"><a href="#四、安全掃描：GitHub-CodeQL" class="headerlink" title="四、安全掃描：GitHub CodeQL"></a>四、安全掃描：GitHub CodeQL</h2><blockquote><p><code>2025/09/16</code>補充：請留意，只有<strong>公開專案</strong>才能<strong>免費</strong>使用 CodeQL 功能。私有專案則須付費 <a href="https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security">GitHub Advanced Security</a> 才行。</p></blockquote><p>實作概要：</p><ul><li>採用 GitHub 官方 <a href="https://github.com/kyomind/WeaMind/blob/v0.5.1/.github/workflows/codeql.yml">codeql.yml</a> 設定，支援 Python 與 GitHub Actions 安全分析</li><li>push 到 main、PR 時觸發，另外每週日也會<strong>定期執行</strong></li><li><strong>排除</strong>資料庫 migrations 等目錄（需要自行額外撰寫 <a href="https://github.com/kyomind/WeaMind/blob/v0.5.1/.github/codeql/codeql-config.yml">codeql-config.yml</a> 控制）</li></ul><p>安全掃描或許不是必須，但我認為它是一種對「<strong>技術成熟度</strong>」追求的象徵。</p><p>要建立這份 YAML 檔很簡單，只要去 GitHub 倉庫設定那邊開啟該功能，系統就會自動幫你產生一份 template。</p><p>不過我還是有進行一些客製化，這部分就跟 AI 討論吧！</p><h2 id="五、程式碼品質分析：SonarCloud"><a href="#五、程式碼品質分析：SonarCloud" class="headerlink" title="五、程式碼品質分析：SonarCloud"></a>五、程式碼品質分析：SonarCloud</h2><p>實作概要：</p><ul><li>使用 <a href="https://github.com/marketplace/sonarcloud">SonarQube Cloud GitHub App</a>，透過官方整合自動執行程式碼品質分析</li><li>分析專案中包括 code smells、bugs、security hotspots、technical debt 等事項</li><li>每次 PR 都會產生品質報告，幫助維持程式碼健康度</li></ul><p>老牌的<strong>程式碼品質分析工具</strong>——<a href="https://www.sonarsource.com/products/sonarqube/">SonarQube</a>，提供比基本 lint 更深入的程式碼分析，包括複雜度、重複程度、潛在安全風險等。</p><p>對於想提升程式碼品質的專案來說，是很好的工具，且不限程式語言。</p><p>我同樣選擇使用 GitHub App 而非自己定義 Action，因為我比較懶。</p><p>自定義的話，可以更靈活地控制分析條件與操作細節。</p><hr><p>以下兩項不算嚴格意義上的 CI，而屬於<strong>專案自動化流程</strong>的一部分。</p><h2 id="六、相依套件更新：Dependabot"><a href="#六、相依套件更新：Dependabot" class="headerlink" title="六、相依套件更新：Dependabot"></a>六、相依套件更新：Dependabot</h2><p>實作概要：</p><ul><li>使用<code>dependabot.yml</code>設定 uv 與 GitHub Actions 的週期性更新</li><li>設定 commit message 格式與自動 rebase，減少手動維護成本</li><li>每週自動檢查並<strong>自動建立 PR</strong>（如果有新版），讓套件更新變得可控且透明</li></ul><p><strong>套件的管理</strong>是專案維護中容易被忽略的環節之一。套件版本過舊可能帶來安全風險，但手動更新又容易忘記。</p><p>Dependabot 讓這個過程自動化，同時透過 PR 機制讓每次更新都經過 CI 驗證。</p><p>更重要的是，<strong>它讓「更新」這件事變得可見、可追蹤</strong>，而不是藏在某個角落的技術債。</p><h2 id="七、自動-GitHub-Release"><a href="#七、自動-GitHub-Release" class="headerlink" title="七、自動 GitHub Release"></a>七、自動 GitHub Release</h2><p>實作概要：</p><ul><li>使用<code>softprops/action-gh-release</code>，當 tag 以<code>v*</code>命名時自動建立 release 並附上 notes</li><li>定義在<code>auto-release.yml</code>，適合小型專案做版本整理</li></ul><p>其實就是<strong>取代手動發布 Release</strong>的流程。</p><p>主要是受到 Will 保哥的《<a href="https://github.com/doggy8088/ask-page-extension">頁問 AskPage</a>》和其它開源專案的啟發。</p><p>先是實作了<a href="https://www.threads.com/@kyomind.tw/post/DN5rYhNge8x">半自動的 CHANGELOG 更新機制</a>，後來乾脆連 <a href="https://github.com/kyomind/WeaMind/releases">Release Notes</a> 都一起自動產生。</p><p>實際的效果就是：每次 push 帶有<code>v*</code>的 tag 時，會自動建立對應的 GitHub release。</p><p>雖然格式稍嫌呆板，但感覺就是兩個字——愉悅！</p><hr><h2 id="流程概覽"><a href="#流程概覽" class="headerlink" title="流程概覽"></a>流程概覽</h2><p>為方便回顧，再次整理 WeaMind 專案中各 CI 流程的關鍵步驟。</p><h3 id="核心-CI-流程（每次程式碼時變更觸發）"><a href="#核心-CI-流程（每次程式碼時變更觸發）" class="headerlink" title="核心 CI 流程（每次程式碼時變更觸發）"></a>核心 CI 流程（每次程式碼時變更觸發）</h3><ol><li><strong>程式碼品質檢查</strong>：使用 Lint、Format、Type Check 確保程式碼風格一致性</li><li><strong>測試與覆蓋率上傳</strong>：執行單元測試並上傳覆蓋率報告至 Codecov</li><li><strong>Docker Build 驗證</strong>：驗證 Dockerfile 的正確性，確保容器化部署不出錯</li><li><strong>安全掃描</strong>：GitHub CodeQL 掃描，檢查潛在安全風險（push + 週期性觸發）</li><li><strong>程式碼品質分析</strong>：使用 SonarCloud 進行深入的程式碼品質分析</li></ol><h3 id="輔助自動化工具"><a href="#輔助自動化工具" class="headerlink" title="輔助自動化工具"></a>輔助自動化工具</h3><ol><li><strong>相依套件更新</strong>：透過 Dependabot 自動更新相依套件，減少手動維護成本</li><li><strong>自動發布</strong>：使用 GitHub Release 自動建立版本釋出</li></ol><p>最後附上 CI 流程的示意圖：</p><p><img src="https://img.kyomind.tw/20250831-160911-ci-min.png" alt="WeaMind CI 流程圖"><span class="cap">WeaMind CI 流程圖</span></p><hr><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p>以上就是 WeaMind 專案目前的 CI 設計全貌。</p><p>這套設計不是為了炫技，而是出於對品質的堅持，讓一個產品型 Side Project 能在成長過程中<strong>穩定運作——並累積信任</strong>。</p><p>如果你也有在開發 Side Project，不妨參考本文實作幾項 CI 流程，建立屬於自己的品質防線。</p><p>CI 不必一次到位，但每一步都在為未來的穩定與信任打底。</p><hr><blockquote><p><strong>如果這篇文章對你有幫助，歡迎到 <a href="https://github.com/kyomind/WeaMind">WeaMind GitHub 首頁</a> 給我一個星星</strong><br>想試用 WeaMind，可掃描下方 QR Code 或搜尋 LINE ID <code>@370ndhmf</code> 加入好友<br>你的支持是我持續分享的動力</p></blockquote><p><img src="https://img.kyomind.tw/wea-qrcode-min-20250929-223022.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/WeaMind-logo-min.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;https://github.com/kyomind/WeaMind/blob/main/blogs/README.md&quot;&gt;WeaMind 系列&lt;/a&gt; 的第 4 篇。&lt;br&gt;本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;〈&lt;a href=&quot;/github-actions&quot;&gt;GitHub Actions 入門：自動化 Lint、Format 與 Type Check&lt;/a&gt;〉一文中，我們使用了 GitHub Actions 作為 CI（&lt;a href=&quot;https://zh.wikipedia.org/zh-tw/%E6%8C%81%E7%BA%8C%E6%95%B4%E5%90%88&quot;&gt;持續整合&lt;/a&gt;）的入門工具。&lt;/p&gt;
&lt;p&gt;同時建立了軟體開發專案中最基本且常見的 CI 流程。&lt;/p&gt;
&lt;p&gt;接下來，我將繼續介紹，WeaMind 專案中&lt;strong&gt;所有實作的 CI 項目&lt;/strong&gt;，並說明我選擇它們的原因與設計原則。&lt;/p&gt;
&lt;p&gt;本文依據的專案程式碼版本為 &lt;a href=&quot;https://github.com/kyomind/WeaMind/tree/v0.5.1&quot;&gt;v0.5.1&lt;/a&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/%E8%BB%9F%E9%AB%94%E9%96%8B%E7%99%BC/"/>
    
    
    <category term="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="GitHub Actions" scheme="https://blog.kyomind.tw/tags/GitHub-Actions/"/>
    
  </entry>
  
  <entry>
    <title>在 Hetzner 開新 VM 指南：選機房、SSH 連線、設定防火牆</title>
    <link href="https://blog.kyomind.tw/hetzner-vm/"/>
    <id>https://blog.kyomind.tw/hetzner-vm/</id>
    <published>2025-07-27T15:03:31.000Z</published>
    <updated>2026-03-29T14:50:16.807Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://i.imgur.com/GhElIMy.jpeg" alt="from Pixabay"><span class="cap">from Pixabay</span></p><p>〈<a href="/hetzner/">Hetzner VPS 實測：比 DigitalOcean 更划算的選擇？</a>〉介紹了 Hetzner 這個來自德國的 VPS 供應商，該篇文章在 VM 價格與規格上，與 DigitalOcean 進行比較。</p><p>使用下來已超過 3 個月，除了台灣連歐洲的延遲較高，以這樣的價格，整體表現仍讓我十分滿意。</p><p>我之後絕大部分的服務，都會部署在目前租用的 Hetzner VM 上。</p><p>上一篇是介紹與推廣，本篇則是進一步教你怎麼在 Hetzner 平台上建立新 VM，簡單實用。</p><p>話不多說，直接開始。</p><span id="more"></span><hr><p>登入後，先打開 Hetzner 的 <a href="https://console.hetzner.com/">Console 頁面</a>。</p><p><img src="https://img.kyomind.tw/20250727-230712-hz1-min.png" alt="Hetzner Console"><span class="cap">Hetzner Console</span></p><p>新增專案並點擊「Create Server」後，我們會在該頁面完成全部流程。</p><p>大部分步驟都不難理解，以下只針對其中幾步進行重點解說。</p><hr><h2 id="一、資料中心選擇"><a href="#一、資料中心選擇" class="headerlink" title="一、資料中心選擇"></a>一、資料中心選擇</h2><p>如圖，全世界有 6 處資料中心可供選擇，3 個在歐洲，2 個在美國，1 個在新加坡。</p><p><img src="https://img.kyomind.tw/20250727-230936-hz2-min.png" alt="機房選擇"><span class="cap">機房選擇</span></p><p>但如果你和我一樣選 ARM 版的 CPU，那就只剩下歐洲的 3 個可選。</p><p>這部分請參考上一篇的「<a href="/hetzner/#%E5%AF%A6%E9%9A%9B%E6%B8%AC%E8%A9%A6%EF%BC%9ALatency-%E6%AF%94%E8%BC%83">實際測試：Latency 比較</a>」（包含我的測試結果），並用你的電腦、網路進行實際測試。</p><p>令人遺憾的是，即使選擇最接近台灣的新加坡機房，我測試的 ping 值也達到 400 毫秒。</p><p>雖然比歐洲機房的 600-800 毫秒快，但相比 DigitalOcean 新加坡機房僅 130 毫秒，仍屬太慢。</p><p>而且價格是歐洲機房的 2 倍左右，個人是覺得不太划算啦！</p><h3 id="歐洲優先"><a href="#歐洲優先" class="headerlink" title="歐洲優先"></a>歐洲優先</h3><p>所以強烈建議，如果對延遲速度有要求，還是不要選它們家的 VM。</p><p>如果可以接受延遲，那選擇歐洲機房與 ARM 處理器，就是最高 CP 值的組合！</p><p><img src="https://img.kyomind.tw/20250727-231130-hz3-min.png" alt="我選擇 CAX21 機型"><span class="cap">我選擇 CAX21 機型</span></p><p>以上都是以 Shared vCPU 為準。</p><p>ARM CPU 的 VM，CP 值都極高！此外，以上價格不含稅——還有 5% 的營業稅。</p><h2 id="二、SSH-連線設定"><a href="#二、SSH-連線設定" class="headerlink" title="二、SSH 連線設定"></a>二、SSH 連線設定</h2><p>我們在〈<a href="/vm-ssh-setup/">為 e2-micro VM 建立 SSH 連線：本機與 GitHub</a>〉提過，新 VM 設定 SSH 連線的方式不外乎這兩種：</p><ol><li>Web Console 登入後自行設定。</li><li>建立 VM 時直接上傳公鑰。</li></ol><p>Hetzner 屬於第二種，上傳一組後，可以設為「預設」，讓全專案都可以使用。這樣一來，開第 2 台、第 3 台時就不必再重新上傳了。</p><p>所以，請先準備好你的公鑰。指令可參考「<a href="/vm-ssh-setup/#%E6%9C%AC%E6%A9%9F%E5%BB%BA%E7%AB%8B-SSH-%E9%87%91%E9%91%B0">本機建立 SSH 金鑰</a>」。</p><p>建立完成後，用 terminal 測試 SSH 連線：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh root@&lt;你的 VM IP&gt;</span><br></pre></td></tr></table></figure><h3 id="SSH-補充建議"><a href="#SSH-補充建議" class="headerlink" title="SSH 補充建議"></a>SSH 補充建議</h3><ol><li>使用 config 檔管理 SSH 連線。</li><li>在<code>root</code>帳號登入後，建立一個普通使用者與獨立的 SSH 連線，並加入 sudo 群組。然後沒事不要再用<code>root</code>登入XD</li></ol><p>保持好習慣，可以省去不必要的麻煩。</p><h2 id="三、防火牆"><a href="#三、防火牆" class="headerlink" title="三、防火牆"></a>三、防火牆</h2><p>Hetzner 的設計是：</p><ul><li>防火牆綁在「專案」層級</li><li>VM 建立時，從現有的防火牆中選擇套用</li></ul><p>如果你尚未建立防火牆，系統會提示你先設定一個，然後再繼續 VM 建立流程。</p><h3 id="Port-開放原則"><a href="#Port-開放原則" class="headerlink" title="Port 開放原則"></a>Port 開放原則</h3><p>建議只開放 22（SSH）、80（HTTP）、443（HTTPS），其餘一律不開。</p><p>其實就是預設值啦！具體設定如下：</p><p><img src="https://img.kyomind.tw/20250727-231422-hz4-min.png" alt="基本防火牆設定"><span class="cap">基本防火牆設定</span></p><p>你可以針對不同用途建立多個防火牆設定檔，或直接共用同一個即可。</p><h2 id="四、雜項"><a href="#四、雜項" class="headerlink" title="四、雜項"></a>四、雜項</h2><p>以下是建立 VM 流程中，我對於雜項的選擇：</p><ol><li>作業系統：當然是 <a href="https://ubuntu.com/blog/tag/ubuntu-24-04-lts">Ubuntu 24.04 LTS</a>。（純個人偏好）</li><li>網路：IPv4（需要一點點費用：€0.0008&#x2F;h）、IPv6（免費）勾選。</li><li>Volumes：預設的 80 GB，很夠用，先不選，真的不夠再加。</li><li>Backups：看需求，我沒選。</li></ol><hr><h2 id="結語：Hetzner-就是香！"><a href="#結語：Hetzner-就是香！" class="headerlink" title="結語：Hetzner 就是香！"></a>結語：Hetzner 就是香！</h2><p>不同需求有不同的選擇，不過在多數情況下，Hetzner 提供的產品服務，對我而言就是絕佳選擇！</p><p>我目前已經在上面部署了（皆以 Docker 容器部署）：</p><ol><li>2 個 <a href="/memos/">memos</a> 服務。</li><li>1 個 <a href="/weekly-review-21/">Umami</a> 服務（GA4 替代品）。</li><li>Nginx、Certbot、<a href="https://www.portainer.io/">Portainer</a> 等等。</li><li>我自己的 <a href="https://github.com/kyomind/WeaMind">side project</a>。</li></ol><p>未來還有很大空間可以發擇，預計還要再部署 <a href="https://n8n.io/">n8n</a>。</p><p>這樣的彈性與餘裕，一個月竟然只要 6.5 歐元，真是非常美妙☺️</p><p>這也是為什麼我願意為 Hetzner 寫下兩篇文章介紹並推廣。</p><hr><h2 id="使用我的推薦連結，享受-20-歐元免費額度"><a href="#使用我的推薦連結，享受-20-歐元免費額度" class="headerlink" title="使用我的推薦連結，享受 20 歐元免費額度"></a>使用我的推薦連結，享受 20 歐元免費額度</h2><p>最後，如果你想試試 Hetzner，歡迎使用<a href="https://hetzner.cloud/?ref=gD26JqrE8c9t"><strong>我的推薦連結</strong></a>註冊，你可以直接獲得 <strong>20 歐元的使用額度</strong>。</p><p>而我在<strong>一定條件</strong>下（用戶使用連結註冊並付費達 10 歐元），可以獲得 10 歐元的回饋。<strong>這是贊助本站最有效的方式。</strong></p><p>希望這篇分享能幫助你，在選擇 VPS 的路上，多一個可靠的選擇。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/GhElIMy.jpeg&quot; alt=&quot;from Pixabay&quot;&gt;&lt;/p&gt;
&lt;p&gt;〈&lt;a href=&quot;/hetzner/&quot;&gt;Hetzner VPS 實測：比 DigitalOcean 更划算的選擇？&lt;/a&gt;〉介紹了 Hetzner 這個來自德國的 VPS 供應商，該篇文章在 VM 價格與規格上，與 DigitalOcean 進行比較。&lt;/p&gt;
&lt;p&gt;使用下來已超過 3 個月，除了台灣連歐洲的延遲較高，以這樣的價格，整體表現仍讓我十分滿意。&lt;/p&gt;
&lt;p&gt;我之後絕大部分的服務，都會部署在目前租用的 Hetzner VM 上。&lt;/p&gt;
&lt;p&gt;上一篇是介紹與推廣，本篇則是進一步教你怎麼在 Hetzner 平台上建立新 VM，簡單實用。&lt;/p&gt;
&lt;p&gt;話不多說，直接開始。&lt;/p&gt;</summary>
    
    
    <content src="https://i.imgur.com/GhElIMy.jpeg" type="image"/>
    
    
    <category term="軟體開發" scheme="https://blog.kyomind.tw/categories/%E8%BB%9F%E9%AB%94%E9%96%8B%E7%99%BC/"/>
    
    
    <category term="Linux" scheme="https://blog.kyomind.tw/tags/Linux/"/>
    
    <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="Hetzner" scheme="https://blog.kyomind.tw/tags/Hetzner/"/>
    
  </entry>
  
  <entry>
    <title>uv 容器化實作：使用官方 image 建立 Dockerfile</title>
    <link href="https://blog.kyomind.tw/uv-dockerfile/"/>
    <id>https://blog.kyomind.tw/uv-dockerfile/</id>
    <published>2025-07-19T07:15:27.000Z</published>
    <updated>2026-03-29T01:15:33.479Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/introducing-uv-min.jpg" alt="from Pixabay"><span class="cap">from Pixabay</span></p><blockquote><p>📌 這是 <a href="https://github.com/kyomind/WeaMind/blob/main/blogs/README.md">WeaMind 系列</a> 的第 3 篇。<br>本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。</p></blockquote><p><a href="https://docs.astral.sh/uv/">uv</a> 是近年來快速竄起的 Python 套件管理器，憑藉其最關鍵的核心特性——快😎，在 Python 開發圈吸引了不少關注與採用。</p><p>之前我已寫過〈<a href="/introducing-uv/">Python 套件管理器 uv 介紹——與 Poetry 比較</a>〉介紹。有興趣的讀者歡迎參考。</p><p>本文是 uv 系列的第二篇，<strong>聚焦於 Dockerfile</strong>。</p><p>當我要將「使用 uv 的 Python 專案」容器化時，我發現相關的討論與介紹較少，所以花了一些時間摸索。</p><p>本文目標是<strong>大幅減少你的試錯時間</strong>，並提出我的實踐與看法。</p><span id="more"></span><hr><h2 id="從-Poetry-到-uv：Dockerfile-寫法大不同"><a href="#從-Poetry-到-uv：Dockerfile-寫法大不同" class="headerlink" title="從 Poetry 到 uv：Dockerfile 寫法大不同"></a>從 Poetry 到 uv：Dockerfile 寫法大不同</h2><p>不久前，我才寫下了〈<a href="https://blog.kyomind.tw/poetry-multi-stage-build/">Docker 教學：用 Multi-stage build 建立 Poetry 虛擬環境</a>〉，講述如何在 Docker 中，使用 Poetry 建立容器內的 Python 執行環境。</p><p>本文算是該篇文章的「<strong>uv 姐妹作</strong>」，但是，做法非常不同！</p><p>我本以為，只要簡單模仿 Poetry 的 multi-stage build 方式就好，但實際操作後才發現問題多多。</p><p>畢竟兩者的指令不同，尤其對於「全域安裝套件」有著截然不同的做法。</p><p>這裡就不仔細比較差異了，經過一番探索，我們已經得到了最佳解😇</p><p>那就是<strong>使用 uv 團隊推出的官方 Docker image！</strong></p><hr><h2 id="使用-uv-官方-image"><a href="#使用-uv-官方-image" class="headerlink" title="使用 uv 官方 image"></a>使用 uv 官方 image</h2><p>關於 uv 容器化議題，uv 開發團隊直接推出了專用的<a href="https://github.com/astral-sh/uv/pkgs/container/uv">官方 image</a>。</p><p>該 image 已內建 uv，且在體積上進行了最佳化，大概只有 60 MB。（指的是使用 slim 版本的 Linux 基底）</p><p>透過它，你可以省去繁瑣的安裝設定，並且在安全性上更有保障。</p><p>如果習慣從 Docker hub 拉取，則可參考<a href="https://hub.docker.com/r/astral/uv/tags">這裡</a>。</p><p>一般而言，仍建議你使用 GitHub 托管的版本——也就是<code>ghcr.io/</code>開頭的版本。因為它才是「第一手」。</p><p>例如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ghcr.io/astral-sh/uv:python3.12-bookworm-slim</span><br></pre></td></tr></table></figure><p>建議用它作為 Dockerfile 的基底 image。</p><h2 id="如何使用官方-image-撰寫-Dockerfile"><a href="#如何使用官方-image-撰寫-Dockerfile" class="headerlink" title="如何使用官方 image 撰寫 Dockerfile"></a>如何使用官方 image 撰寫 Dockerfile</h2><p>有了 image，那我們要怎麼撰寫 Dockerfile 呢？</p><p>對此，我們也不需要自己苦苦思考了，大部分挑戰都已經有了答案——請直接參考這個<a href="https://github.com/astral-sh/uv-docker-example">官方倉庫</a>中的 <a href="https://github.com/astral-sh/uv-docker-example/blob/main/Dockerfile">Dockerfile</a> 寫法！</p><p><strong>強烈建議你，如果沒有特殊需求，就 follow 它的寫法</strong>，因為 uv 的操作有很多繁瑣的細節，考驗著你對該工具的了解，尤其在 Docker 容器化的場景更是如此。</p><p>官方的 Dockerfile 也非常細心，在多個指令都加上了簡要的註解，讓你知其然又知其所以然。</p><p>其實看過其中一些指令內容就知道，要自己寫肯定很難寫得這麼好。</p><p>所以我們還是盡可能參考甚至遵照這份 Dockerfile 的寫法。</p><p>可以少走很多彎路。</p><hr><h2 id="為什麼不需要-Multi-stage-build？"><a href="#為什麼不需要-Multi-stage-build？" class="headerlink" title="為什麼不需要 Multi-stage build？"></a>為什麼不需要 Multi-stage build？</h2><p>前述〈<a href="https://blog.kyomind.tw/poetry-multi-stage-build/">Docker 教學：用 Multi-stage build 建立 Poetry 虛擬環境</a>〉教你如何用 multi-stage build 建立 Poetry 虛擬環境。</p><p>因為 Poetry 和 uv 這類工具有<strong>各自需要的執行環境與依賴套件</strong>，不那麼適合在 Docker 建構過程中直接安裝並封裝成 image，這會造成<strong>一定程度的空間浪費與冗餘</strong>。</p><p>所以我們選擇用 multi-stage build 來建立 image。省去不必要的依賴，有效減少最終 image 的體積。</p><p>那為什麼這裡就<strong>沒有這麼做</strong>呢？</p><p>原因很簡單，<strong>官方已經提供這份簡單、乾淨的 image，讓你直接開箱即用</strong>。雖然最終的 image 中仍會有 uv，但它的體積佔用已然經過最佳化。</p><p>此時自己再搞個 multi-stage build，也省不了多少空間，還徒增 Dockerfile 的複雜度與出錯可能。</p><h3 id="MCP-時代需要-uv"><a href="#MCP-時代需要-uv" class="headerlink" title="MCP 時代需要 uv"></a>MCP 時代需要 uv</h3><p>附帶一提，在這個 MCP（模型上下文協定，<a href="https://modelcontextprotocol.io/introduction">Model Context Protocol</a>）盛行的時代，我們可以看到 MCP Server 的開發，主要由兩種語言佔多數：</p><ol><li>TypeScript（JavaScript）</li><li>Python</li></ol><p>如果你想用 Python 來開發 MCP 服務，並希望讓使用者執行<code>uv run &lt;你定義的指令&gt;</code>來啟動 MCP Server（這是目前主流做法），那 uv 就需要存在你的最終 image 中。</p><blockquote><p>延伸閱讀（外部）：</p><ul><li><a href="https://blog.miniasp.com/post/2025/04/01/Write-your-own-MCP-server-using-uv-and-Python">使用 uv 輔助開發 MCP 伺服器並安裝到 Claude Desktop 與 VS Code</a></li><li><a href="https://oalieno.tw/posts/mcp">MCP 開發實戰手冊：SSE、STDIO、Tool、Resource 一次搞懂</a>（尤其是「<strong>MCP Server 開發語言與執行方式</strong>」部分）</li></ul></blockquote><p>如此一來，自然也不需要透過 multi-stage build 來移除 uv 了。</p><h3 id="我就是要-Multi-stage-build！"><a href="#我就是要-Multi-stage-build！" class="headerlink" title="我就是要 Multi-stage build！"></a>我就是要 Multi-stage build！</h3><p>不同專案有不同需求，如果你真的需要 multi-stage build 以進一步節省空間的話，同一個倉庫中有<a href="https://github.com/astral-sh/uv-docker-example/blob/main/multistage.Dockerfile">另一個 Dockerfile</a> 可供參考。</p><hr><h2 id="uv-與-pip-requirements-txt-混搭法"><a href="#uv-與-pip-requirements-txt-混搭法" class="headerlink" title="uv 與 pip &#x2F; requirements.txt 混搭法"></a>uv 與 pip &#x2F; requirements.txt 混搭法</h2><p>其實，uv 對 pip 的相容性相當不錯——畢竟它有子命令<code>uv pip</code>。</p><p>因此，你也可以不用官方的 uv image，而是使用一般 Python image，再直接搭配<code>requirements.txt</code>安裝容器中的 Python 虛擬環境就好。</p><p>好處是延續了既有的 pip 開發習慣，降低認知負擔。</p><p>重點是，官方還非常貼心地準備了 <a href="https://docs.astral.sh/uv/guides/integration/pre-commit/">pre-commit hook</a>，來協助你輕鬆同步<code>uv.lock</code>與<code>requirements.txt</code>：</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">repos:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">repo:</span> <span class="string">&lt;https://github.com/astral-sh/uv-pre-commit&gt;</span></span><br><span class="line">    <span class="comment"># uv version.</span></span><br><span class="line">    <span class="attr">rev:</span> <span class="number">0.8</span><span class="number">.0</span></span><br><span class="line">    <span class="attr">hooks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">id:</span> <span class="string">uv-export</span></span><br></pre></td></tr></table></figure><p>如此一來，就不會再發生<a href="/poetry-multi-stage-build/#%E8%88%8A%E6%9C%89%E5%81%9A%E6%B3%95%EF%BC%9Arequirements-txt-%E5%8F%8A%E5%85%B6%E9%99%90%E5%88%B6">前文</a>中提到的「在更新<code>poetry.lock</code>時，常常會忘記同步到<code>requirements.txt</code>」這類問題。</p><blockquote><p>相關文章：<a href="/pre-commit/">Python 開發：pre-commit 設定 Git Hooks 教學</a></p></blockquote><p>此外，你也可以使用官方 image 但保留<code>requirements.txt</code>作為安裝依據，Dockerfile 寫法同樣簡單。</p><p>以上這兩種混搭方式的具體實作，可以參考 <a href="https://jumping-code.com/about-me/">JumpingCode 資料科學手記</a>的這篇〈<a href="https://jumping-code.com/2024/08/23/uv-pip-docker-image/#dockerfile-using-uv">如何使用 Python 套件管理工具「uv」取代 pip 來加速 Docker Image 的建立</a>〉。</p><p>其中的「<a href="https://jumping-code.com/2024/08/23/uv-pip-docker-image/#%E5%AF%A6%E6%B8%AC%E6%AA%94%E6%A1%88">實測檔案</a>」一節就提供了完整的 Dockerfile 範例。</p><hr><h2 id="我的-Dockerfile"><a href="#我的-Dockerfile" class="headerlink" title="我的 Dockerfile"></a>我的 Dockerfile</h2><p>最後附上 WeaMind 專案中，我目前使用的 <a href="https://github.com/kyomind/WeaMind/blob/blog/uv-dockerfile-v1-20250719/Dockerfile">Dockerfile</a>。</p><p>我對官方寫法做了一定的<strong>刪減</strong>，主要是移除專案作為第三方套件的相關設定，並簡化 Dockerfile 的快取策略。</p><p>如果你沒有把握，建議和 AI 討論或者直接 follow 官方的寫法就好。</p><p>此外，我還加上了一些註解，供讀者參考。</p><figure class="highlight dockerfile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ghcr.io/astral-sh/uv:python3.<span class="number">12</span>-bookworm-slim</span><br><span class="line"></span><br><span class="line"><span class="comment"># Use &#x27;code&#x27; to avoid confusion with the &#x27;app&#x27; directory</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="language-bash"> /code</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Compile bytecode and avoid symlinks</span></span><br><span class="line"><span class="keyword">ENV</span> UV_COMPILE_BYTECODE=<span class="number">1</span></span><br><span class="line"><span class="keyword">ENV</span> UV_LINK_MODE=<span class="keyword">copy</span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash"></span></span><br><span class="line"><span class="comment"># ---------- layer 1: heavy dependencies ----------</span></span><br><span class="line"><span class="comment"># Cache only invalidates when these two files change</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> pyproject.toml uv.lock ./</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">RUN</span><span class="language-bash"> --mount=<span class="built_in">type</span>=cache,target=/root/.cache/uv \</span></span><br><span class="line"><span class="language-bash">    uv <span class="built_in">sync</span> --locked --no-dev</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ---------- layer 2: application code ----------</span></span><br><span class="line"><span class="keyword">COPY</span><span class="language-bash"> . /code</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Put the venv at the beginning of PATH</span></span><br><span class="line"><span class="keyword">ENV</span> PATH=<span class="string">&quot;/code/.venv/bin:$PATH&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Do not use uv as the entrypoint</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="language-bash"> []</span></span><br></pre></td></tr></table></figure><hr><blockquote><p><strong>如果這篇文章對你有幫助，歡迎到 <a href="https://github.com/kyomind/WeaMind">WeaMind GitHub 首頁</a> 給我一個星星</strong><br>想試用 WeaMind，可掃描下方 QR Code 或搜尋 LINE ID <code>@370ndhmf</code> 加入好友<br>你的支持是我持續分享的動力</p></blockquote><p><img src="https://img.kyomind.tw/wea-qrcode-min-20250929-223022.png" alt="WeaMind QR Code"><span class="cap">WeaMind QR Code</span></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/introducing-uv-min.jpg&quot; alt=&quot;from Pixabay&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;📌 這是 &lt;a href=&quot;https://github.com/kyomind/WeaMind/blob/main/blogs/README.md&quot;&gt;WeaMind 系列&lt;/a&gt; 的第 3 篇。&lt;br&gt;本系列以真實世界專案為背景，記錄重要技術實作與經驗分享。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.astral.sh/uv/&quot;&gt;uv&lt;/a&gt; 是近年來快速竄起的 Python 套件管理器，憑藉其最關鍵的核心特性——快😎，在 Python 開發圈吸引了不少關注與採用。&lt;/p&gt;
&lt;p&gt;之前我已寫過〈&lt;a href=&quot;/introducing-uv/&quot;&gt;Python 套件管理器 uv 介紹——與 Poetry 比較&lt;/a&gt;〉介紹。有興趣的讀者歡迎參考。&lt;/p&gt;
&lt;p&gt;本文是 uv 系列的第二篇，&lt;strong&gt;聚焦於 Dockerfile&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;當我要將「使用 uv 的 Python 專案」容器化時，我發現相關的討論與介紹較少，所以花了一些時間摸索。&lt;/p&gt;
&lt;p&gt;本文目標是&lt;strong&gt;大幅減少你的試錯時間&lt;/strong&gt;，並提出我的實踐與看法。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/introducing-uv-min.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="WeaMind" scheme="https://blog.kyomind.tw/tags/WeaMind/"/>
    
    <category term="Docker" scheme="https://blog.kyomind.tw/tags/Docker/"/>
    
    <category term="Python" scheme="https://blog.kyomind.tw/tags/Python/"/>
    
    <category term="Poetry" scheme="https://blog.kyomind.tw/tags/Poetry/"/>
    
    <category term="uv" scheme="https://blog.kyomind.tw/tags/uv/"/>
    
  </entry>
  
  <entry>
    <title>Vibe Coding 與人類的時代</title>
    <link href="https://blog.kyomind.tw/vibe-coding/"/>
    <id>https://blog.kyomind.tw/vibe-coding/</id>
    <published>2025-07-10T14:22:29.000Z</published>
    <updated>2026-03-22T16:22:15.883Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://img.kyomind.tw/20250710-223843-city-7625204_1280.jpg" alt="from Pixabay"><span class="cap">from Pixabay</span></p><blockquote><p>任何人類都能使用魔法的時代要到來了——《葬送的芙莉蓮》漫畫第 53 話 | 人類的時代</p></blockquote><p>有了強大的 AI 輔助 ，寫程式再也不是軟體工程師的專屬。</p><p>如此的時代巨變，首先讓我聯想到的，就是「芙莉蓮」中的這段劇情。</p><p>不過把這個比喻與感受表達得最好的，當屬財經作家王伯達的這篇<a href="https://www.facebook.com/share/p/173juCsKre/">臉書文</a>。</p><p>他寫道：</p><blockquote><p>AI 讓更多人，用更容易的方式使用程式語言與複雜軟體。</p><p>這讓我想到芙莉蓮的老師，弗蘭梅。</p><p>她說服了人類的皇帝，讓人類得以開始研究魔法，魔法不再是個禁忌，開啟了人人有魔法可以練的年代。</p></blockquote><p>顯然，在我這個軟體工程師眼中，AI 就像芙蘭梅，把原本高門檻的知識、技術變成大眾能輕易接觸的工具，<strong>讓所有人都有機會參與創造</strong>。</p><p>本文聊聊我作為一個軟體工程師，如何看待這個 AI 普及後的「魔法時代」。</p><span id="more"></span><hr><h2 id="工程師的傲慢：自詡為魔法的守門人"><a href="#工程師的傲慢：自詡為魔法的守門人" class="headerlink" title="工程師的傲慢：自詡為魔法的守門人"></a>工程師的傲慢：自詡為魔法的守門人</h2><p>曾幾何時，軟體工程師就像這個世界的魔法使，掌握著一種魔法般的語言——程式碼。</p><p>我們用它來創造服務、建立平台、構築起一個個廣袤無垠的數位世界。</p><p>然而，AI 的出現，讓一切開始改變。</p><p>ChatGPT 問世後，所有的「文本生成」變得簡單起來——包括程式碼。</p><p>隨著 AI 持續演進、AI Agent 工具日漸成熟，你越來越常聽到這樣的說法：</p><blockquote><p>我不懂程式語言，但我能用 AI 寫程式。</p></blockquote><p>剛開始聽到這類言論時，老實說，我的內心充滿了鄙夷之情😅</p><p>就像師祖賽莉耶說的：「<strong>魔法就應該是特別的。</strong>」</p><p>而我也覺得，程式就應該是「<strong>特別</strong>」的，不是誰都能隨口說自己「會寫程式」。</p><h2 id="因為稀缺，所以傲慢"><a href="#因為稀缺，所以傲慢" class="headerlink" title="因為稀缺，所以傲慢"></a>因為稀缺，所以傲慢</h2><p>這種想法有道理嗎？也許這是人性的一部分。</p><p>作家朱宥勳在《<a href="https://www.books.com.tw/products/0010867642">文壇生態導覽——作家新手村 2 心法篇</a>》一書中提到，如果一位文人既會寫散文又會寫詩，他會希望人們稱他為「詩人」。</p><p>如果既會寫散文又會寫小說呢？當然是小說家！</p><blockquote><p><strong>所以楊牧是詩人，陳映真是小說家——儘管他們散文都寫得很好</strong>。</p></blockquote><p>看起來，身為詩人、小說家，<strong>似乎比身為散文作家更讓人有一種「特別」的感覺</strong>。</p><p>為什麼？或許是因為——散文的門檻比較低吧。</p><p>任何人，只要識字、能表達，都能自稱「<strong>會寫</strong>」散文（文采如何可以另當別論）。</p><p>而寫詩、寫小說這種「<a href="https://dict.idioms.moe.edu.tw/idiomView.jsp?ID=1150&webMd=2&la=0">陽春白雪</a>」，對我等普羅大眾來說，<strong>簡直連想都不敢想</strong>！——就像寫程式一樣。</p><hr><h2 id="心態的轉變"><a href="#心態的轉變" class="headerlink" title="心態的轉變"></a>心態的轉變</h2><p>懷抱著上述的想法（儘管我不是程式界的楊牧），我一直希望自己是特別的。</p><p>直到今年 2 月，當 <a href="https://zh.wikipedia.org/zh-tw/%E5%AE%89%E5%BE%B7%E7%83%88%C2%B7%E5%8D%A1%E5%B8%95%E6%96%AF">Andrej Karpathy</a> 提出 Vibe Coding 一詞時，我心中的這份傲慢被敲響了喪鐘。</p><p>我心想：如果連這種大神級的軟體工程師，都提出並嘗試了這樣有趣的軟體開發方式，那一般人用這種方式來開發自己需要的工具或服務，完全說得通啊！</p><p>加上 <a href="https://www.facebook.com/will.fans/?locale=zh_TW">Will 保哥</a>的各種鼓吹，我對 Vibe Coding 的接納度迅速上升。</p><h2 id="什麼是-Vibe-Coding"><a href="#什麼是-Vibe-Coding" class="headerlink" title="什麼是 Vibe Coding"></a>什麼是 Vibe Coding</h2><p>Vibe Coding 這個新鮮的詞彙已經有了自己的<a href="https://zh.wikipedia.org/zh-tw/Vibe_coding">維基百科條目</a>。</p><p>我簡要摘錄如下（定義來自英文頁面）：</p><blockquote><p>Vibe coding is an artificial intelligence-assisted software development style popularized by Andrej Karpathy in early 2025. It describes a fast, improvisational, collaborative approach to creating software where the developer and a large language model (LLM) tuned for coding is acting rather like pair programmers in a conversational loop.</p></blockquote><p>簡單講，就是開發者透過自然語言與 AI 對話，反覆修正，一步步建立並完善軟體。</p><p>作為一個 Vibe Coder，你不需了解各種開發細節，甚至不用懂程式語言，而是專注於想要達成的目標和功能需求。</p><p>AI 成為了翻譯者，把我們的意圖轉化為可執行的程式碼。</p><hr><p>心態的改變，讓我開始重新看待「寫程式」的價值本身。</p><h2 id="軟體只是手段"><a href="#軟體只是手段" class="headerlink" title="軟體只是手段"></a>軟體只是手段</h2><p>越來越多人開始用 AI 寫程式，解決各種日常問題。</p><p>近期讓我最有感的是〈<a href="https://www.inside.com.tw/feature/2025-generative-ai/38545-ai-coding-ngoer">【Generative AI 年會】人力少但服務不打折！Peggy Lo：AI Coding 是 NGO 工作者最強大靠山</a>〉。</p><p>報導中，Peggy Lo 分享了她在僅有四人編制的基金會秘書處，如何運用 AI Coding 應對龐大的行政庶務與人力緊縮。</p><p>透過 AI，她不僅大幅提升了工作效率，還能讓服務變得更細緻、更深入。</p><p>這豈不是 Vibe Coding 的最佳典範？</p><p>我知道，程式從來只是手段。重要的不是「會不會寫」，而是「能不能用來解決真正的問題」。</p><p>一方面覺得自己的傲慢有些可笑，一方面也<strong>鬆了口氣</strong>。</p><p>我想，我更該在乎的，不是透過 AI 開發到底算不算「會寫程式」。</p><p>而是作為一個軟體工程師，<strong>我能解決什麼樣的問題</strong>。</p><hr><h2 id="「一般人」的優勢"><a href="#「一般人」的優勢" class="headerlink" title="「一般人」的優勢"></a>「一般人」的優勢</h2><p>而且話說回來，我不禁在想，不會程式的人用 AI 來開發，反而有自己的獨特優勢！</p><p>工程師多少知道某些技術的困難度，這反而會成為心理負擔，限制想像——覺得 AI 應該辦不到。</p><p>事實證明，AI 往往超乎人們的想像——在厲害與不厲害兩個方面都是XD</p><p>不懂程式的人沒這層包袱，做事的方式就很簡單：提出要求，請 AI 想辦法實現。</p><blockquote><p>魔法是想像的世界，在魔法世界中，無法想像的事情就無法實現</p></blockquote><p>沒有限制，反而更能天馬行空，專注於達成目標。</p><p>雖然未必每次都這麼順利，但少了這些束縛，有時候我認為是一個巨大的優勢。</p><p>唉，我就是缺乏想像力。</p><hr><h2 id="工程師也要會-Vibe-Coding"><a href="#工程師也要會-Vibe-Coding" class="headerlink" title="工程師也要會 Vibe Coding"></a>工程師也要會 Vibe Coding</h2><p>當然，這不代表工程師就該束手就擒。</p><p>相反地，我們更需要進化。</p><p>直白地說，我認為軟體工程師比一般人更需要學會 Vibe Coding。</p><p>像我這樣一個只熟悉後端的 Python 工程師，面對不熟的技術領域（例如前端），也需要發揮 Vibe Coding 的精神與實踐能力。</p><p>善於與 AI 協作的工程師（再加上一點想像力😎），可能是這個時代最有力的創造者。</p><h3 id="一般人打造工具，工程師打造系統"><a href="#一般人打造工具，工程師打造系統" class="headerlink" title="一般人打造工具，工程師打造系統"></a>一般人打造工具，工程師打造系統</h3><p>我覺得工程師應用 AI 放大軟體開發的能力，理應遠超過一般人。</p><p>這讓人充滿期待。</p><p>有人說，AI 讓工程師從作者變成了編輯者，<a href="https://www.managertoday.com.tw/articles/view/70451">讓寫程式像審稿</a>。好像自降了格調一般。</p><p>我認為這沒錯啊！重點是——<strong>審稿本身就是門技術活</strong>！</p><p>就像我在〈<a href="https://blog.kyomind.tw/myth-of-ai-writing-efficiency/">AI 讓寫作變輕鬆了？我可不這麼認為</a>〉提到的，AI 對我寫作的影響：</p><blockquote><p>為了善用 AI 的力量，我發現自己<strong>變成了 5 分作者、5 分編輯</strong>，而且<strong>經常在兩種身分間游移互換</strong>：一下子自己寫，讓 AI 看；一下子要 AI 寫、我來看。</p></blockquote><blockquote><p>AI 的普及，讓我們不僅僅是創作者，也成了編輯，甚至是策劃者。<strong>這種角色的轉換增加了工作量和難度，但也讓我們對內容的掌控更為精細。</strong></p></blockquote><p>沒有足夠的經驗，不可能成為優秀的編輯。</p><hr><p>總之，我覺得，工程師也好，非工程師也罷，在 AI 面前，我們都是人類，都需要藉由 AI 的輔助，不斷擴展自己的邊界。</p><p>這是個令人興奮的時代。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://img.kyomind.tw/20250710-223843-city-7625204_1280.jpg&quot; alt=&quot;from Pixabay&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;任何人類都能使用魔法的時代要到來了——《葬送的芙莉蓮》漫畫第 53 話 | 人類的時代&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;有了強大的 AI 輔助 ，寫程式再也不是軟體工程師的專屬。&lt;/p&gt;
&lt;p&gt;如此的時代巨變，首先讓我聯想到的，就是「芙莉蓮」中的這段劇情。&lt;/p&gt;
&lt;p&gt;不過把這個比喻與感受表達得最好的，當屬財經作家王伯達的這篇&lt;a href=&quot;https://www.facebook.com/share/p/173juCsKre/&quot;&gt;臉書文&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;他寫道：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI 讓更多人，用更容易的方式使用程式語言與複雜軟體。&lt;/p&gt;
&lt;p&gt;這讓我想到芙莉蓮的老師，弗蘭梅。&lt;/p&gt;
&lt;p&gt;她說服了人類的皇帝，讓人類得以開始研究魔法，魔法不再是個禁忌，開啟了人人有魔法可以練的年代。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;顯然，在我這個軟體工程師眼中，AI 就像芙蘭梅，把原本高門檻的知識、技術變成大眾能輕易接觸的工具，&lt;strong&gt;讓所有人都有機會參與創造&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文聊聊我作為一個軟體工程師，如何看待這個 AI 普及後的「魔法時代」。&lt;/p&gt;</summary>
    
    
    <content src="https://img.kyomind.tw/20250710-223843-city-7625204_1280.jpg" type="image"/>
    
    
    <category term="心得" scheme="https://blog.kyomind.tw/categories/%E5%BF%83%E5%BE%97/"/>
    
    
    <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="Vibe Coding" scheme="https://blog.kyomind.tw/tags/Vibe-Coding/"/>
    
  </entry>
  
</feed>
