<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Peter Lee - Blog</title><link>https://blog.peterlee.app/zh-hant/</link><description>Recent content on Peter Lee - Blog</description><generator>Hugo</generator><language>zh-hant</language><managingEditor>peterlee0127@gmail.com (peterlee)</managingEditor><webMaster>peterlee0127@gmail.com (peterlee)</webMaster><lastBuildDate>Mon, 14 Sep 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://blog.peterlee.app/zh-hant/index.xml" rel="self" type="application/rss+xml"/><item><title>家用 Kubernetes 的內部 DNS：從 router 到 CoreDNS 排查查詢迴圈</title><link>https://blog.peterlee.app/cloud/kubernetes-local-dns-coredns-loop/</link><pubDate>Mon, 14 Sep 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/kubernetes-local-dns-coredns-loop/</guid><description>&lt;p>GitLab 的網頁能開，不代表 Argo CD 能 clone repository；NUC 上能解析 Registry，也不代表 Pod 或 container runtime 走相同的 DNS 路徑。把家中服務分成公開瀏覽器入口與內部機器入口後，這幾個差異就不能再靠同一個「DNS 正常」概括。&lt;/p>
&lt;p>我的內部 DNS 設定由 router 的 dnsmasq 管理，NUC 使用 router 作為 upstream，RKE2 裡的 CoreDNS 再替 Pods 解析名稱。這裡的分流使用不同的公開與內部名稱，不是讓同一個 hostname 在內外網回傳不同 IP 的 split-horizon 設定。&lt;/p></description></item><item><title>將 Vault audit log 保存到 host：權限、HUP 與 90 天輪替</title><link>https://blog.peterlee.app/cloud/vault-audit-log-persistence-rotation/</link><pubDate>Wed, 09 Sep 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/vault-audit-log-persistence-rotation/</guid><description>&lt;p>Vault 能正常提供 secret，不代表事後能回答「誰做了哪個 API 操作」。Container 的 server logs 主要記錄 process 狀態與錯誤；audit device 才負責 API request／response 的稽核資料。兩者用途不同，也不會因為 &lt;code>docker logs vault&lt;/code> 有輸出就自動同時存在。&lt;/p>
&lt;p>我的 Vault 在 Kubernetes 外以 Docker Compose 執行。Repository 已記錄把 host 的 &lt;code>/var/log/vault&lt;/code> 掛到 container 的 &lt;code>/vault/logs&lt;/code>，並以 logrotate 管理 &lt;code>audit.jsonl&lt;/code>。這篇集中在保存與輪替，不重複 &lt;a href="https://blog.peterlee.app/cloud/vault-kubernetes-external-secrets/">Vault 與 External Secrets&lt;/a>裡的 secret delivery 流程。&lt;/p></description></item><item><title>在 M5 Pro 上用 LM Studio 執行 Qwen3.6 與 Qwen3.8</title><link>https://blog.peterlee.app/ai/lm-studio-qwen-m5-pro/</link><pubDate>Fri, 04 Sep 2026 01:05:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/ai/lm-studio-qwen-m5-pro/</guid><description>&lt;p>在 M5 Pro 上跑本機大型語言模型，安裝本身並不複雜，真正需要留意的是模型格式與 unified memory。這次我在 LM Studio 裡使用兩個 MLX 4-bit 模型：Qwen3.6 35B A3B 與 Qwen3.8 27B。前者的模型檔約 20.43 GB，後者約 16.08 GB；兩個都能處理文字、圖片與 reasoning，但架構和適合的使用方式不完全相同。&lt;/p>
&lt;h2 id="先準備-lm-studio-與-mlx-runtime">先準備 LM Studio 與 MLX runtime&lt;/h2>
&lt;p>先安裝最新版 &lt;a href="https://lmstudio.ai/download">LM Studio&lt;/a>，再從左下角的 &lt;strong>Settings&lt;/strong> 開啟 Runtime 管理頁面。Apple Silicon 可以使用 &lt;code>llama.cpp&lt;/code> 或 Apple 的 MLX；這次下載的是 MLX 版本，因此 Runtime selections 也要選 LM Studio MLX。&lt;/p></description></item><item><title>用 ClusterExternalSecret 將 Registry 登入資訊分發到多個 namespace</title><link>https://blog.peterlee.app/cloud/clusterexternalsecret-registry-credentials/</link><pubDate>Wed, 02 Sep 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/clusterexternalsecret-registry-credentials/</guid><description>&lt;p>新增一個 namespace 後，Deployment 看起來沒有問題，Pod 卻停在 &lt;code>ImagePullBackOff&lt;/code>。檢查才發現 &lt;code>imagePullSecrets&lt;/code> 指向 &lt;code>regcred&lt;/code>，但這份 Secret 只存在另一個 namespace。手動複製一次很快；每增加一個 workload、每輪替一次 credential 都要再複製，才是後續的負擔。&lt;/p>
&lt;p>我的 GitOps 設定用 Vault 保存 Registry 登入資料，再由 &lt;code>ClusterExternalSecret&lt;/code> 在選中的 namespaces 建立 &lt;code>ExternalSecret&lt;/code>。各個 ExternalSecret 負責產生當地的 &lt;code>regcred&lt;/code>，workload 仍然使用 Kubernetes 原生的 &lt;code>imagePullSecrets&lt;/code>。&lt;/p></description></item><item><title>做一個只能看、不能動的 Kubernetes MCP tool</title><link>https://blog.peterlee.app/cloud/read-only-mcp-for-kubernetes-triage/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/read-only-mcp-for-kubernetes-triage/</guid><description>&lt;p>我最近在 &lt;code>k8s_infra/plugins/infra-observer&lt;/code> 做了一個給 AI 用的 MCP tool。它不是遠端終端機的包裝，也不是把 &lt;code>kubectl&lt;/code> 直接交給模型；它只做一件事：在不讓 AI 動到環境的前提下，給它排查問題需要的資訊。&lt;/p>
&lt;p>若 SSH 工具接受任意指令，AI 取得的能力就超過了排查所需。就算名義上說是 read-only，也可能讀到 Secret、進 Pod 執行命令，或被 log 裡的內容引導去跑不該跑的東西。我想要的是讓它看得到 Pod 是否不健康、rollout 卡在哪裡、Argo CD 有沒有同步、Service 有沒有 endpoint，以及服務在 OTel 裡有沒有錯誤；除此之外的能力就不要有。&lt;/p></description></item><item><title>讓 AI 讀懂我的 Kubernetes 基礎設施</title><link>https://blog.peterlee.app/cloud/ai-gitops-kubernetes-infrastructure/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/ai-gitops-kubernetes-infrastructure/</guid><description>&lt;p>剛開始把 AI 放進 Kubernetes 的工作流程時，我最常遇到的問題不是它不會寫 YAML，而是它太容易只看眼前那一份 YAML。它可以很快補出一個 Deployment，卻不一定知道這個服務要不要經過 Argo CD、它的 Secret 從哪裡來，或是公開入口是否也需要處理叢集外的設定。&lt;/p>
&lt;p>後來我沒有再把需求和幾段設定直接貼進對話，而是讓 AI 從 GitOps repository 開始讀。那個 repository 本來就是我維護叢集的地方；裡面的目錄、README 和設定檔，剛好也能讓 AI 補上我平常放在腦中的脈絡。&lt;/p>
&lt;h2 id="我先給-ai-一張地圖">我先給 AI 一張地圖&lt;/h2>
&lt;p>Repository 將 bootstrap、Applications、服務設定與叢集外資源分開：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">gitops/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── bootstrap/ # 初始安裝時才需要的東西
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── clusters/apps/ # Argo CD Applications
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── apps/ # 各服務的 manifests 與 values
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── terraform/ # 叢集外的雲端資源
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── docs/ # 架構與操作筆記
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有了這張地圖，「新增一個服務」就不再只是多一個 Deployment。AI 可以先找出這個服務會碰到的 Application、Kustomization、values、Secret reference 和 Terraform，而不是猜一份看起來合理、實際上接不起來的設定。&lt;/p></description></item><item><title>以 GitOps 管理的 values 在 Kubernetes 執行 Airflow</title><link>https://blog.peterlee.app/cloud/airflow-on-kubernetes-with-gitops-values/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/airflow-on-kubernetes-with-gitops-values/</guid><description>&lt;p>我的家用 Kubernetes 叢集將 Apache Airflow 作為以 GitOps 管理的平台服務。它負責編排定時執行的資料工作與維運流程；Kubernetes 則為 scheduler、API server、Celery worker、triggerer 與支援服務提供隔離的執行環境。&lt;/p>
&lt;p>部署分成兩部分：可公開審查的 Helm values 放在 Git，憑證與產生的金鑰則放在 Vault。Argo CD 負責依正確順序同步這兩部分。&lt;/p>
&lt;h2 id="部署結構">部署結構&lt;/h2>
&lt;p>這個 repository 採用 app-of-apps 模式。根 Argo CD Application 從 &lt;code>clusters/apps/&lt;/code> 同步子 Application；Airflow 的資源則分成以下幾個部分：&lt;/p></description></item><item><title>以 cloudflared 取代 Caddy：不開放 80、443 連接埠也能公開 Kubernetes</title><link>https://blog.peterlee.app/cloud/cloudflare-tunnel-kubernetes-without-open-ports/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/cloudflare-tunnel-kubernetes-without-open-ports/</guid><description>&lt;p>我的 &lt;code>k8s_infra&lt;/code> 原本由 Caddy 接收公開流量。請求先到 Cloudflare，再經過 router 上的 HTTP／HTTPS port forwarding 進入家用網路，抵達 Caddy 後才轉送到 Kubernetes。&lt;/p>
&lt;p>這套設計可以運作，卻代表來源端仍要接受 Internet 的入站連線。我除了維護 Cloudflare DNS 與 Access policy，還要同時管理 router、host firewall、Caddy route，以及 Kubernetes 的 NodePort 或 Ingress。任何一層設定錯誤，都可能留下繞過預期驗證路徑的入口。&lt;/p></description></item><item><title>從本機與遠端 Git 歷史移除誤提交的 secret</title><link>https://blog.peterlee.app/cloud/remove-committed-secret-from-git-history/</link><pubDate>Thu, 30 Jul 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/remove-committed-secret-from-git-history/</guid><description>&lt;p>這次事件發生在一個使用外部 CSV 的 side project。我整理資料時，誤把其中一份含有機密內容的 CSV 加進 Git。發現後，即使再提交一次刪除檔案的變更，也只會讓它從最新版本消失；舊 Git object 仍可能在本機或遠端被取回。&lt;/p>
&lt;p>需要處理的是兩件事：已暴露的資料，以及仍可存取的 Git 歷史。若資料是 token、密碼或憑證，要先撤銷或輪替；若是無法撤銷的機密內容，則要限制存取、檢查稽核紀錄與副本，並依事件需求處理通知。刪除歷史無法收回別人已取得的資料。&lt;/p>
&lt;p>以下以 &lt;code>data/external/private-source.csv&lt;/code> 示範。操作前須確認 repository 的 refs、branch protection 與協作方式。&lt;/p>
&lt;h2 id="刪除檔案會留下什麼">刪除檔案會留下什麼&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rm data/external/private-source.csv
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git commit -m &lt;span class="s2">&amp;#34;remove committed confidential CSV&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>目前 branch 不再包含檔案，但早期 commit 仍有原始內容。把值換成 &lt;code>REDACTED&lt;/code> 也一樣，Git 會保存前一個 blob。&lt;/p></description></item><item><title>用 AI Coding 打造原生 macOS 加密 DNS App：DNS Security Pro</title><link>https://blog.peterlee.app/ios/dns-security-pro-native-macos-ai-coding/</link><pubDate>Sat, 18 Jul 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/ios/dns-security-pro-native-macos-ai-coding/</guid><description>&lt;p>&lt;a href="https://github.com/peterlee0127/DNS-Security-Pro-macOS">DNS Security Pro for macOS&lt;/a> 可以切換 DNS over HTTPS（DoH）與 DNS over TLS（DoT）profiles，並顯示目前啟用的設定。我以 SwiftUI、AppKit lifecycle 與 Apple NetworkExtension APIs 建立獨立的 macOS App，沒有透過 Mac Catalyst 移植 iOS 介面。&lt;/p>
&lt;p>需求來自我開發與維護 iOS 版 DNS Security 的經驗。AI 協助整理需求、實作與修訂文件；其中最需要處理的是系統 DNS 狀態是否正確，以及 profile 套用前的驗證。&lt;/p></description></item><item><title>在 GitOps 使用 Mozilla SOPS 加密 Kubernetes Secret</title><link>https://blog.peterlee.app/cloud/gitops-sops-encrypted-secrets/</link><pubDate>Tue, 09 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/gitops-sops-encrypted-secrets/</guid><description>&lt;p>SOPS 可以讓加密後的 Kubernetes Secret 值保存在 Git，部署時再由 GitOps controller 解密。它與 Vault 的差別在於資料來源：Vault 提供 runtime 值，SOPS 則以 Git 裡的加密檔為 source of truth。&lt;/p>
&lt;p>&lt;code>encrypted Secret in Git → GitOps controller 解密 → Kubernetes Secret → Pod&lt;/code>&lt;/p></description></item><item><title>使用 waypoint proxy 執行 Istio ambient mode</title><link>https://blog.peterlee.app/cloud/istio-ambient-waypoint-proxies/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/istio-ambient-waypoint-proxies/</guid><description>&lt;p>我用 Istio ambient mode 將 namespace 納入 mesh，不必為每個 Pod 加入 sidecar。Ztunnel 處理 L4 安全通訊；需要 L7 路由、授權或遙測的服務，再加入 waypoint。&lt;/p>
&lt;p>這裡讓公開 API &lt;code>example-api&lt;/code> 使用 service-scoped waypoint；&lt;code>example-worker&lt;/code> 先使用 ambient L4。&lt;code>example-admin&lt;/code> 維持內部存取，之後也可以納入 ambient。&lt;/p>
&lt;aside class="my-8 border-y border-line py-6">

 &lt;strong class="text-ink">家用 Kubernetes GitOps 系列&lt;/strong>
 &lt;ol class="mt-4 list-decimal space-y-2 pl-5">
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/bootstrap-rke-cluster-for-gitops/">為 GitOps 啟動新的 RKE 叢集&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/argocd-gitops-for-home-kubernetes/">用 Argo CD 管理我的家用 Kubernetes 叢集&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/vault-kubernetes-external-secrets/">在 Kubernetes 使用 Vault 與 External Secrets&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/istio-ambient-waypoint-proxies/">使用 waypoint proxy 執行 Istio ambient mode&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/istio-gateway-api-ingress/">使用 Istio Gateway API 對外公開 Kubernetes 服務&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/opentelemetry-stack-for-kubernetes-apps/">為 Kubernetes 應用程式建立 OpenTelemetry 堆疊&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/airflow-on-kubernetes-with-gitops-values/">以 GitOps 管理的 values 在 Kubernetes 執行 Airflow&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/gitops-sops-encrypted-secrets/">在 GitOps 使用 Mozilla SOPS 加密 Kubernetes Secret&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/cloudflare-tunnel-kubernetes-without-open-ports/">以 cloudflared 取代 Caddy&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/kubernetes-local-dns-coredns-loop/">從 router 到 CoreDNS 排查內部 DNS&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/clusterexternalsecret-registry-credentials/">以 ClusterExternalSecret 分發 Registry 登入資訊&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/vault-audit-log-persistence-rotation/">保存與輪替 Vault audit log&lt;/a>&lt;/li>
 &lt;/ol>

&lt;/aside>

&lt;h2 id="用-namespace-label-啟用-ambient">用 namespace label 啟用 ambient&lt;/h2>
&lt;p>Sidecar mode 在各個 Pod 加入 Envoy；ambient 的第一層則由 Istio CNI 與 node 上的 ztunnel 處理流量。Namespace 的設定如下：&lt;/p></description></item><item><title>用 Argo CD 管理我的家用 Kubernetes 叢集</title><link>https://blog.peterlee.app/cloud/argocd-gitops-for-home-kubernetes/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/argocd-gitops-for-home-kubernetes/</guid><description>&lt;p>我用 Argo CD 讓家用 Kubernetes 叢集持續和 Git 裡的設定一致。叢集規模還小時，手動執行 &lt;code>kubectl apply&lt;/code> 並不難；加入 application workloads、Redis、Longhorn、Istio、monitoring 與 ingress 後，真正麻煩的是重建時要記得每個元件的來源、順序與前置條件。&lt;/p>
&lt;p>現在由 Argo CD 同步 Git 裡的 manifests，Vault 保存 secret 值。新的 RKE 叢集仍須先完成下面的 bootstrap 步驟，才能讀取 repository 並取得這些值。&lt;/p></description></item><item><title>在 Kubernetes 使用 Vault 與 External Secrets</title><link>https://blog.peterlee.app/cloud/vault-kubernetes-external-secrets/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/vault-kubernetes-external-secrets/</guid><description>&lt;p>我的家用 Kubernetes 叢集以 Vault 保存 secret 值，External Secrets Operator（ESO）負責讀取並建立一般的 Kubernetes Secrets，Deployment 再照常引用。Git 保存 manifests 與來源對應關係，不保存明文值。&lt;/p>
&lt;p>&lt;code>Vault KV v2 → ClusterSecretStore → ExternalSecret → Kubernetes Secret → Pod&lt;/code>&lt;/p>
&lt;p>這樣重建叢集時，就不必逐一手動複製 Secrets。以下以 &lt;code>example-api&lt;/code>、&lt;code>example-worker&lt;/code> 與內部使用的 &lt;code>example-admin&lt;/code> 示範。&lt;/p></description></item><item><title>使用 Istio Gateway API 對外公開 Kubernetes 服務</title><link>https://blog.peterlee.app/cloud/istio-gateway-api-ingress/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/istio-gateway-api-ingress/</guid><description>&lt;p>我用 Istio Gateway API 將公開 hostname 導向 Kubernetes Services。叢集外的 reverse proxy 終結 HTTPS，再將 HTTP 送到共用的 Gateway：&lt;/p>
&lt;p>&lt;code>external TLS reverse proxy → Istio Gateway Service → HTTPRoute → Kubernetes Service → Pod&lt;/code>&lt;/p></description></item><item><title>為 GitOps 啟動新的 RKE 叢集</title><link>https://blog.peterlee.app/cloud/bootstrap-rke-cluster-for-gitops/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/bootstrap-rke-cluster-for-gitops/</guid><description>&lt;p>Argo CD 接手新的 RKE 叢集前，要先完成 Git 存取、Vault 驗證與節點前置設定。少了這些條件，第一次同步就可能出現 ExternalSecret 讀不到 Vault、workload 缺少 Secret，或 PVC 等不到儲存空間的情況。&lt;/p>
&lt;p>範例使用 Git repository &lt;code>ssh://git@git.example.com/platform/k8s-infra.git&lt;/code>、API server &lt;code>https://rke-api.example.internal:6443&lt;/code> 與 Vault &lt;code>https://vault.example.internal:8200&lt;/code>。&lt;code>example-api&lt;/code> 和 &lt;code>example-worker&lt;/code> 有公開入口，&lt;code>example-admin&lt;/code> 維持內部使用。&lt;/p>
&lt;aside class="my-8 border-y border-line py-6">

 &lt;strong class="text-ink">家用 Kubernetes GitOps 系列&lt;/strong>
 &lt;ol class="mt-4 list-decimal space-y-2 pl-5">
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/bootstrap-rke-cluster-for-gitops/">為 GitOps 啟動新的 RKE 叢集&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/argocd-gitops-for-home-kubernetes/">用 Argo CD 管理我的家用 Kubernetes 叢集&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/vault-kubernetes-external-secrets/">在 Kubernetes 使用 Vault 與 External Secrets&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/istio-ambient-waypoint-proxies/">使用 waypoint proxy 執行 Istio ambient mode&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/istio-gateway-api-ingress/">使用 Istio Gateway API 對外公開 Kubernetes 服務&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/opentelemetry-stack-for-kubernetes-apps/">為 Kubernetes 應用程式建立 OpenTelemetry 堆疊&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/airflow-on-kubernetes-with-gitops-values/">以 GitOps 管理的 values 在 Kubernetes 執行 Airflow&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/gitops-sops-encrypted-secrets/">在 GitOps 使用 Mozilla SOPS 加密 Kubernetes Secret&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/cloudflare-tunnel-kubernetes-without-open-ports/">以 cloudflared 取代 Caddy&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/kubernetes-local-dns-coredns-loop/">從 router 到 CoreDNS 排查內部 DNS&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/clusterexternalsecret-registry-credentials/">以 ClusterExternalSecret 分發 Registry 登入資訊&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://blog.peterlee.app/cloud/vault-audit-log-persistence-rotation/">保存與輪替 Vault audit log&lt;/a>&lt;/li>
 &lt;/ol>

&lt;/aside>

&lt;h2 id="argo-cd-接手後的同步順序">Argo CD 接手後的同步順序&lt;/h2>
&lt;p>手動套用 &lt;code>clusters/root-app.yaml&lt;/code> 後，Argo CD 從 &lt;code>clusters/apps&lt;/code> 建立 child Applications，再管理 &lt;code>apps/&lt;/code> 與基礎設施設定。&lt;/p></description></item><item><title>為 Kubernetes 應用程式建立 OpenTelemetry 堆疊</title><link>https://blog.peterlee.app/cloud/opentelemetry-stack-for-kubernetes-apps/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/opentelemetry-stack-for-kubernetes-apps/</guid><description>&lt;p>我的應用程式在 Kubernetes 裡執行，可觀測性後端則留在叢集之外。OpenTelemetry Collector、Prometheus、Loki、Tempo 與 Grafana 都以 Docker Compose 跑在 NUC 上；即使我正在重建叢集，仍然能打開 Grafana 查看已保存的資料。&lt;/p>
&lt;p>Application telemetry、Pod stdout 與 host logs 分別由不同的 collector 收集：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">application OTLP → OpenTelemetry Collector → Prometheus／Loki／Tempo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Pod stdout → Alloy DaemonSet → Loki
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">host file → host Alloy → Loki
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ↓
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> Grafana
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Collector 健康不代表 Pod stdout 已被收集；Loki 顯示 ready，也不代表資料已送達。每條路徑都需要確認實際收到的資料。&lt;/p></description></item><item><title>部署 Rancher Kubernetes Engine</title><link>https://blog.peterlee.app/cloud/deploy-rancher-kubernetes/</link><pubDate>Sun, 10 Oct 2021 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/deploy-rancher-kubernetes/</guid><description>&lt;p>這是我在 2021 年使用 RKE1 與 Kubernetes 1.20.11 的部署筆記。RKE1 已於 2025 年 7 月 31 日結束支援；新建叢集請參考目前的 &lt;a href="https://docs.rke2.io/">RKE2 文件&lt;/a>。支援期限見 &lt;a href="https://ranchermanager.docs.rancher.com/getting-started/installation-and-upgrade/upgrade-kubernetes-without-upgrading-rancher">Rancher 公告&lt;/a>。&lt;/p>
&lt;h3 id="當時為什麼選擇-rke1">當時為什麼選擇 RKE1&lt;/h3>
&lt;p>RKE1 讓我透過一份設定集中管理 cluster 元件。當時的機器混用 Ubuntu 20.04.3 LTS 與 CentOS 7，升級較難協調；RKE1 將 Kubernetes 元件以 Docker 容器執行，能減少部分環境差異。它也透過 SSH 設定各節點，因此不必手動在 control plane 逐一加入 worker。&lt;/p></description></item><item><title>iOS／macOS 的 DNS Security</title><link>https://blog.peterlee.app/ios/dns_security_ios/</link><pubDate>Fri, 20 Nov 2020 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/ios/dns_security_ios/</guid><description>&lt;h1 id="dns-security">DNS Security&lt;/h1>
&lt;div style="text-align:center">&lt;a href='https://apps.apple.com/us/app/id1533938029'>&lt;img src="https://blog.peterlee.app/assets/images/posts/2020-11-20-dns-security-ios/mac-logo.png" width='200px' style='alignment:center'>&lt;/a>&lt;/div>
&lt;p>DNS Security 使用 iOS 14 的加密 DNS profile 保護 DNS 查詢，不必把所有網路流量都改經 VPN。&lt;/p>
&lt;h3 id="什麼是-dns-over-https-與-dns-over-tls">什麼是 DNS over HTTPS 與 DNS over TLS？&lt;/h3>
&lt;p>即使造訪的網站使用 HTTPS，DNS 查詢仍可能經由未加密的連線送出。監看網路的人可能看見你查詢哪些網域；攻擊者也可能竄改 DNS 回應，將訪客導向釣魚、惡意軟體或監控網站。你的 ISP、路由器或網路服務商也可能追蹤這些查詢。DNS over HTTPS 與 DNS over TLS 可協助保護 DNS 查詢，降低這類暴露風險。&lt;/p></description></item><item><title>使用 GitHub Pages 託管網站</title><link>https://blog.peterlee.app/web/host-your-website-on-github-pages/</link><pubDate>Thu, 24 Oct 2019 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/web/host-your-website-on-github-pages/</guid><description>&lt;p>GitHub Pages 可以把靜態網站發布在預設的 &lt;code>github.io&lt;/code> 網址，也可以使用自己擁有的網域。自訂網域要同時完成兩件事：GitHub 要知道哪一個 Pages site 使用這個名稱，DNS 也要把名稱指到 GitHub。&lt;/p>
&lt;p>以下用 &lt;code>www.example.com&lt;/code> 示範，請改成自己能控制的網域。&lt;/p>
&lt;h2 id="先讓-pages-預設網址能正常發布">先讓 Pages 預設網址能正常發布&lt;/h2>
&lt;p>在加 DNS 前，先到 repository 的「Settings → Pages」設定發布來源，並確認預設 Pages URL 能開啟。GitHub Pages 可以從 branch 發布，也可以由 GitHub Actions workflow 發布；應依網站實際的建置方式選擇。&lt;/p></description></item><item><title>為 Kubernetes 部署 NFS StorageClass</title><link>https://blog.peterlee.app/cloud/deploy-storage-class-for-kubernetes/</link><pubDate>Tue, 27 Aug 2019 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/deploy-storage-class-for-kubernetes/</guid><description>&lt;p>這份 2019 年的 lab 筆記使用 NFS-backed StorageClass 與舊版 &lt;code>nfs-client-provisioner&lt;/code>，下方保留當時的 &lt;code>extensions/v1beta1&lt;/code> Deployment。新建叢集請使用 &lt;a href="https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner">NFS subdirectory external provisioner&lt;/a> 的安裝方式。&lt;/p>
&lt;p>在前一篇 &lt;a href="https://blog.peterlee.app/cloud/start_a_kubernetes_with_kubeadm/">kubeadm cluster&lt;/a> 裡，Pods 可能被重新建立到不同節點。我用 NFS 提供共享的持久化儲存，讓 provisioner 依 PVC 建立對應目錄。&lt;/p>
&lt;h2 id="在-centos-安裝-nfs-server">在 CentOS 安裝 NFS server&lt;/h2>
&lt;p>Server 位於同一個 LAN，位址為 &lt;code>192.168.2.104&lt;/code>。安裝 &lt;code>nfs-utils&lt;/code>、建立 &lt;code>/opt/nfs&lt;/code>，再設定 &lt;code>/etc/exports&lt;/code>：&lt;/p></description></item><item><title>使用 kubeadm 建立 Kubernetes 叢集</title><link>https://blog.peterlee.app/cloud/start_a_kubernetes_with_kubeadm/</link><pubDate>Sun, 25 Aug 2019 00:00:00 +0800</pubDate><author>peterlee0127@gmail.com (peterlee)</author><guid>https://blog.peterlee.app/cloud/start_a_kubernetes_with_kubeadm/</guid><description>&lt;p>這是我在 2019 年建立的 lab：Kubernetes 1.15.3、Docker 19.3.1、Ubuntu 18.04 與 CentOS 7。下列指令保留當時環境；新建叢集請參考&lt;a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/">目前的 kubeadm 安裝文件&lt;/a>，套件來源與 Docker 整合方式已有變更。&lt;/p>
&lt;p>&lt;img src="https://blog.peterlee.app/assets/images/posts/2019-08-25-start-a-kubernetes-cluster-with-kubeadm/kube-dashboard.jpg" alt="Kubernetes dashboard">&lt;/p>
&lt;h2 id="硬體與節點配置">硬體與節點配置&lt;/h2>
&lt;p>我以一台實體主機執行整個多節點環境，配置是 Intel Core i7-8700（6 cores／12 threads）、32 GB RAM 與 512 GB SSD，另有供 GPU workloads 使用的 NVIDIA RTX 2070 O8G。這是當時的實機配置，不是 Kubernetes 最低需求。&lt;/p></description></item></channel></rss>