抜錨
技術

CloudNativePG の managed roles で ArgoCD が永久に OutOfSync になる問題

公開日

問題

備忘として書きます。

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 のマニフェストにも書いてやれば粒度が揃って差分が消える。

 

1yaml
2managed:
3 roles:
4 - name: blog
5 ensure: present
6 login: true
7 connectionLimit: -1
8 inherit: true


 

これで ArgoCD の diff は解消。Synced に戻った。