問題
備忘として書きます。
homelab の Kubernetes クラスタで、ブログ(Payload CMS)のバックエンドを CloudNativePG で運用している。ArgoCD の DIFF タブを見ると、`postgresql.cnpg.io/Cluster` の `blog-db` が延々と OutOfSync のまま。差分の中身はこうだった。

左(live)に `connectionLimit: -1` と `inherit: true` があり、右(Git の desired)にはない。ArgoCD は「live にあって desired にない → 消したい」と解釈するので、差分が消えない。selfHeal を有効にしていると、ArgoCD が消しにいく → オペレータが書き戻す、のループになってしまう。
原因
NPG の declarative role management は、ロールの属性を PostgreSQL の慣習に沿ってデフォルト補完する。公式ドキュメントによると、<cite index="4-1">inherit 属性は PostgreSQL の慣習に従ってデフォルトで true、connectionLimit 属性は同じく PostgreSQL の慣習に沿ってデフォルトで -1 になる</cite>。
そして重要なのが reconcile の挙動で、ユーザーがデータベース内でロール属性を直接変更した場合、CloudNativePG オペレータは次の reconciliation サイクルでその変更を元に戻す<。つまりオペレータは「あるべき完全な状態」を live の Cluster リソースに書き込む。ここでデフォルト値も明示的に埋められるため、Git 側に書いていないフィールドが live に出現し、ArgoCD の目には drift として映る、というカラクリだった。
要するに、**desired(Git)と live(オペレータが補完後)の粒度が食い違っている** のが根本原因。
解決
オペレータが埋めているデフォルトを、そのまま Git のマニフェストにも書いてやれば粒度が揃って差分が消える。
1yaml2managed:3 roles:4 - name: blog5 ensure: present6 login: true7 connectionLimit: -18 inherit: true
これで ArgoCD の diff は解消。Synced に戻った。