【kubernetes】last-applied-configurationの役割とConfigMapのマージ戦略

先日、テスト環境上のKubernetesで、アプリケーションがDBに急に接続できなくなってしまった。GitHubのmasterブランチで管理している設定ファイルには全く変更がなかったので、原因をどう調べようか迷っていたところ、まずConfigmapのlast-applied-configurationを見てみると良いと教えてもらった。

last-applied-configurationとは

last-applied-configurationはConfigmapのフィールドの一つであり、 kubectl apply コマンドによって最後に適用された設定が記録されている。逆に言うと、それ以外の方法で設定が更新された場合はlast-applied-configurationに記録されない。last-applied-configurationは、内容が変更された設定ファイルを kubectl apply で適用した際に、変更点を洗い出して設定をマージするために使われる。
今回調べてみたところ、last-applied-configurationには正しい接続情報が記載されており、今適用されている設定とは異なっていた。すなわち、誰かが接続情報を手続き的な方法(例えば kubectl replace 等)で直接上書きしたということがわかる。

kubectl apply時のマージ方法

last-applied-configurationの役割は分かったが、ここで一つ疑問が浮かんだ。例えば、 kubectl apply で設定ファイルを更新したが、その後手続き的な方法で設定を変えたために、設定ファイルとlive configuration(実際に適用されている設定)に差が生まれているとする。その場合、次に kubectl apply をした時、手続き的な方法で上書きした設定もマージされ残るのだろうか?

kubernetes.io

基本的に、マージはlast-applied-configurationと新たにapplyされた設定ファイルのみを比較して行われる。もし特定のフィールドが手続き的に変更されていた場合、そのフィールドが新しくapplyされた設定ファイルに含まれていれば、値が更新される。逆に、そのフィールドが新しくapplyされた設定ファイルに含まれていなければ、マージの際の比較対象に含まれず、設定がそのまま残る。

デフォルト値のベストプラクティス

設定変更がマージされる際、上記の挙動は問題を引き起こしうる。デフォルト値を取るフィールドAがあり、その値が設定ファイルに明示されていない場合、当然そのフィールドはlast-applied-configurationに含まれない。その状態で、当該のフィールドを設定ファイルに追加してapplyすると、デフォルト値のフィールドに依拠していた別のフィールドがあったときに予期せぬ挙動となってしまう。
このため、ドキュメントではフィールドのデフォルト値をそのまま使う場合でも、最初から設定ファイルに明記するよう推奨している。例えば、各resourceのselectorとtemplate、それにRollout Strategyなどのフィールドがそれにあたる。