星期五, 10月 09, 2026

用 helm-diff 在升級前先看會改到什麼

我管理 Helm chart 的慣例

每個 chart 我會開一個目錄,維護四個檔案:

  • init-repo.sh:加入 repo 的指令,記錄 repo 是怎麼加的。
  • upgrade.sh:安裝與升級的指令,通常是 helm upgrade --install,並用 --version 固定 chart 版本。
  • values.yaml:先用 helm show values <chart> 取得可調整的設定,再改成自己要的。不用 --set 是因為設定只存在指令列裡,事後很難回想當初設了什麼。
  • README.md:說明文件。

這些都是純文字檔,可以直接納入版本管理。

為什麼需要 helm-diff

最近用 Claude 整理自家的 k8s,發現有些 release 是早期直接下指令裝的,沒有照上面的慣例留下 values.yaml。要把它們補回來,得先確認「我補寫的 values.yaml 和叢集裡實際在跑的設定一致」,Claude 建議我裝 helm-diff 這個 plugin 來比對。

helm-diff 會把「chart 加上你的 values」算出來的 manifest,拿去和叢集裡該 release 目前的 manifest 比較,像 git diff 一樣列出差異。它只做比對,不會改動叢集。

安裝

Helm 4:

curl -sL https://github.com/databus23.gpg | gpg --import
gpg --list-keys --with-fingerprint EA17A2A206AFF8CD
# 指紋應為:C5645EF4 7482257A 1F806D2B EA17A2A2 06AFF8CD
helm plugin install https://github.com/databus23/helm-diff/releases/latest/download/helm-diff-linux-amd64.tgz

Helm 4 安裝 plugin 時預設會驗證來源證明(provenance),確認檔案確實由作者簽署、沒有被竄改,所以要先匯入作者的 GPG 公鑰,並核對指紋。只有直接指向 tarball 的網址才支援驗證。檔名裡的 linux-amd64 請依自己的作業系統與架構,到 releases 頁面挑對應的檔案。

Helm 3(需 3.18 以上):

helm plugin install https://github.com/databus23/helm-diff

使用

升級前先看會改什麼。參數和 upgrade.sh 裡的 helm upgrade 保持一致即可:

helm diff upgrade ngf <chart> -n nginx-gateway --version <版本> -f values.yaml -C 3

-C 3 是只顯示差異前後 3 行,不加的話會印出完整 manifest。Secret 的內容預設會遮蔽。

rollback 前先看退回某個 revision 會改什麼:

helm diff rollback ngf 1 -n nginx-gateway

把手動安裝的 release 補回慣例

  1. 取出當初安裝時給的設定:helm get values ngf -n nginx-gateway -o yaml > values.yaml
  2. 用 helm list -n nginx-gateway 確認目前的 chart 版本,寫進 upgrade.sh。
  3. 執行上面的 helm diff upgrade。沒有任何輸出,就代表這份 values.yaml 和線上設定一致,可以放心納入版本管理。

其他常用的子指令

  • upgrade:升級會改什麼
  • rollback:rollback 會改什麼
  • revision:比較同一個 release 的兩個 revision,例如 helm diff revision ngf 1 2
  • release:比較兩個 release,例如 prod 和 staging

要注意 helm-diff 預設是和 Helm 記錄的上一版 manifest 比。如果有人用 kubectl edit 直接改過資源,要加 --three-way-merge 才會和叢集的實際狀態比對。


星期日, 10月 04, 2026

pre-commit

在使用 Claude 時,Claude 建議我使用這工具搭配 gitleaks,可以在提交代碼前檢查是否有機敏資料會被提交到 git repository。

Claude 都這麼建議了,就試試吧。

在 Ubuntu 24.04 ,gitleaks 跟 pre-commit 都已經可以使用 apt 安裝。

sudo apt install gitleaks pre-commit

接下來就是配置。

目前我是先在一個 repository 測試,所以要先撰寫 .pre-commit-config.yaml

# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v3.2.0
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
    -   id: check-yaml
    -   id: check-added-large-files
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.2
    hooks:
      - id: gitleaks

在這裡,我使用 pre-commit 所提供的範例,剛好也是我常會用的

  • 檢查行末空白
  • 末行的EOF
  • yaml 格式
  • 避免加入過大的檔案

再來是 gitleaks 的部份,這邊我有點猶豫的是語法,不確定我已經用 apt 安裝 gitleaks 了,是否還要加上 repo。後來想,先加上去再說,錯了再處理就好。但結果看起來是可以使用。

在編寫完成以後,執行以下指令安裝

pre-commit install

再來是 gitleaks 設定

# gitleaks 設定:沿用內建規則,再補上內建沒有的規則(#14)
[extend]
useDefault = true

# Tailscale key:tskey-<auth|client|api|scim|webhook>-<id>-<secret>
# 內建規則沒有涵蓋,見 work-diary/20261002-tailscale-oauth-secret.md
[[rules]]
id = "tailscale-key"
description = "Tailscale auth key / OAuth client secret / API key"
regex = '''\btskey-[a-z]+-[0-9A-Za-z]{6,}-[0-9A-Za-z]{16,}\b'''
keywords = ["tskey-"]

# Telegram bot token:<bot id>:AA<33 字元>(共約 46 字元)
# 內建的 telegram-bot-api-token 要求 token 前面有「telegr」,Alertmanager 的 `bot_token: <token>` 抓不到(#22)
[[rules]]
id = "telegram-bot-token-bare"
description = "Telegram bot token(不需要 telegram 關鍵字)"
regex = '''\b[0-9]{8,10}:AA[0-9A-Za-z_-]{33}\b'''
keywords = [":aa"]

然後就收工了。

pre-commit install 會把腳本寫到 .git/hooks/pre-commit ,讓 git commit 時,可以執行此腳本來檢查。

星期二, 9月 15, 2026

壓縮pdf

MacOS的預覽程式本身就可以壓縮 pdf ,方法可以參考 Apple 官方網站的文章:https://support.apple.com/zh-tw/guide/preview/prvw1509/mac

開啟 pdf 以後,

  1. 選擇「檔案」>「輸出⋯」。
  2. 在「Quartz 濾鏡」彈出式選單中,選擇「減少檔案大小」。
  3. 儲存

這樣就可以了。

但….如果 pdf 已經壓縮過、包含向量圖、嵌入字型或特殊物件時,那麼反而可能得到反效果,檔案會變大。

我自己是有安裝 homebrew ,就想說是不是安裝什麼工具來作就好。

問了 AI ,他就說可以用 gs ,也就是 ghostscript 就可以解決。

先安裝

brew install ghostscript

接下來就執行 gs

gs \
  -sDEVICE=pdfwrite \
  -dCompatibilityLevel=1.4 \
  -dPDFSETTINGS=/ebook \
  -dNOPAUSE \
  -dQUIET \
  -dBATCH \
  -sOutputFile=output.pdf \
  input.pdf

把 input.pdf 跟 output.pdf 換掉就可以。

壓縮等級主要是調整 -dPDFSETTINGS= 參數,參數內容可以參考

參數品質檔案大小
/prepress最高最大
/printer高較大
/ebook中推薦
/screen低最小

ghostscript 還可以調整 pdf 內的圖片解析度

gs \
 -sDEVICE=pdfwrite \
 -dCompatibilityLevel=1.4 \
 -dColorImageDownsampleType=/Bicubic \
 -dColorImageResolution=150 \
 -dGrayImageDownsampleType=/Bicubic \
 -dGrayImageResolution=150 \
 -dMonoImageDownsampleType=/Subsample \
 -dMonoImageResolution=300 \
 -dNOPAUSE \
 -dQUIET \
 -dBATCH \
 -sOutputFile=output.pdf \
 input.pdf

其他的方法還有 pdfcpu, ocrmypdf ,這些我就沒測試了。


星期六, 9月 12, 2026

完整移除 pyenv

我是用 homebrew 安裝 pyenv ,之前是用 pyenv 在管理 python 環境,但現在進入 AI 時代,AI 反倒不知道要載入哪個環境。

這邊後來是看到可以用 pipx 來安裝跟管理這種獨立的工具,再加上 uv 管理 python 專案更為方便,為此,乾脆就移除 pyenv 了。

若要先備份每個 python 套件,可以用以下腳本來進行

mkdir -p ~/pyenv-pip-backup

for venv in $(pyenv virtualenvs --bare | grep -v '/'); do
  echo "匯出 $venv ..."
  "$PYENV_ROOT/versions/$venv/bin/pip" freeze > ~/pyenv-pip-backup/"$venv".txt
done

這樣會把所有安裝過的套件備份到 ~/pyenv-pip-backup 目錄下。

然後用 homebrew 移除 pyenv。

brew uninstall pyenv

# 若有安裝 pyenv-virtualenv 這個 plugin(也常透過 brew 裝)
brew uninstall pyenv-virtualenv

再刪除 pyenv 檔案。

rm -rf "$(brew --prefix)/opt/pyenv" 2>/dev/null  # 保險起見清一下 opt 連結(通常不存在)
rm -rf ~/.pyenv

清理環境變數,先找看哪個檔案有

grep -n "pyenv" ~/.zshrc ~/.zprofile ~/.bash_profile ~/.bashrc ~/.profile 2>/dev/null

通常內容是

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

把這些刪除掉。

最後關閉終端機,重新開,讓環境變數重新載入。

開完以後,用以下方式檢驗,照理說應該就都看不到了。

# 確認指令已消失
command -v pyenv
which pyenv

# 應該回傳「找不到指令」或空白

# 確認目錄已清空
ls -la ~/.pyenv 2>&1

# 應顯示 No such file or directory

# 確認 PATH 中已無 pyenv 蹤跡
echo $PATH | tr ':' '\n' | grep pyenv

# 應該沒有任何輸出

# 確認 brew 也不再列出
brew list pyenv 2>&1

星期三, 9月 02, 2026

將 pod 佈署到Control plane上

 一般來說,是無法佈署應用程式到 Control plane 上的,主要是要讓 Control plane 的資源儘量不受到排擠。這是因為 node 用了 annotation/taint 方式來做標記,這樣 scheduler 才知道這些 node 是不能放 pod 的。

在資源不夠的情況下,會想儘可能使用到所有 node 資源。這時候可以透過以下方式來處理

# Source - https://stackoverflow.com/a/72264143
# Posted by TheDHM, modified by community. See post 'Timeline' for change history
# Retrieved 2026-09-02, License - CC BY-SA 4.0

kubectl taint node <master-node> node-role.kubernetes.io/control-plane:NoSchedule-
kubectl taint node <master-node> node-role.kubernetes.io/master:NoSchedule-

要注意的地方,請先用 kubectl describe node來查看 taint 是打上哪一個,再看用哪一個指令。

參考資料: