こんにちは、menu事業部エンジニアの鈴木です。私は、menuのマイクロサービスチームでGCPを用いたクラウドインフラおよびマイクロサービスの開発・保守・運用をしています。
はじめに
最近、Helm v4がリリースされましたね!
Helmは、Kubernetesのパッケージマネージャーとして広く使われているツールです。アプリケーションのデプロイやアップグレードを簡単に行えるので、多くの現場で活用されています。
そのHelm v4で、新しくServer-Side Apply(SSA)のサポートが追加されました。--server-sideというオプションを使うことで、Kubernetesのリソース更新をサーバー側で行えるようになります。
この新機能について調べていく中で、ある疑問が生まれました。
検証のきっかけ
Helm v4のリリースノートを見ていて、こんなことを考えました:
「Helm v4でServer-Side Applyが実装されたということは、それまで(v3)にはこの機能がなかったのか〜。」
ちょうど同じタイミングで、Kubernetes関連のOSSについて調べているときに、external-secrets-operator(ESO)という話題を見かけました。「ESOはserver side applyでないとアップグレードできない」という情報です。
調べてみると、ESOのCRDはv0.19.0以降、機能が増えたことでサイズが大きくなったことが報告されていました。
v0.19.0のリリースノートを確認すると、🔴 BREAKING CHANGE 🔴 として以下のように書かれていました:
CRDが大きすぎるため、シンプルな
kubectl applyやArgoのデフォルトのclient side applyは動きません!
kubectl applyには--server-sideを追加する必要があります。
つまり、CRDのサイズが大きくなったことで、従来の方法では更新できなくなったということです。
ここで私はこう考えました:
- ESOの公式リリースノートに「BREAKING CHANGE」「Server-Side Applyが必須」と明記されている
- Helm v3には、Server-Side Applyがない
ということは、CRDが大きくなったESO v0.19.0以降は、Helm v3ではアップグレードできないのではないか?
Helm v4のServer-Side Applyを使えば、アップグレードできるのではないか?
公式が「BREAKING CHANGE」とまで言っているのだから、この推測は正しいだろうと思いました。
とはいえ、推測だけでは分かりません。実際に試してみることにしました。
検証内容は以下の2つです:
- Helm v4のServer-Side Applyを使って、ESOをv0.18.0からv1.1.1にアップグレードできるか?
- Helm v3では本当にアップグレードできないのか?
それでは実際に試してみましょう!
検証環境の準備
Helm v4のインストール
macを利用しているので、brewでHelmを最新にします。
$ brew update
$ brew upgrade helm
v4のバージョンになっていることを確認します。
$ helm version
version.BuildInfo{Version:"v4.0.1", GitCommit:"12500dd401faa7629f30ba5d5bff36287f3e94d3", GitTreeState:"clean", GoVersion:"go1.25.4", KubeClientVersion:"v1.34"}
問題ありませんね!
Kubernetes環境の準備
Kubernetes環境については、kindやDocker Desktopやクラウドのマネージドk8sなど、お好きな環境を準備してください。
検証用なので、ローカルのKindクラスターなどで十分です。
検証1:Helm v4のServer-Side Applyを試してみる
ESO v0.18.0のインストール
まず、対象のKubernetesクラスターにコンテキストを向けておきます。(kubectxを利用すると便利です!)
次に、ESOの旧バージョン(v0.18.0)をインストールします。
$ helm install external-secrets external-secrets/external-secrets --version 0.18.0
以下のように表示されたらインストール成功です!
NAME: external-secrets
LAST DEPLOYED: Sun Dec 7 21:02:26 2025
NAMESPACE: default
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
external-secrets has been deployed successfully in namespace default!
Helmだとすごく簡単に導入できますね!
v1.1.1へのアップグレード(Server-Side Applyを使用)
それでは、v1.1.1へのアップグレードを試してみます。
まず、リポジトリに最新版があるか確認します。
$ helm search repo external-secrets/external-secrets --versions | head -n 2
NAME CHART VERSION APP VERSION DESCRIPTION
external-secrets/external-secrets 1.1.1 v1.1.1 External secrets management for Kubernetes
確認できましたね。もし表示されない場合は、helm repo updateでリポジトリを更新してください。
それでは、Helm v4の--server-sideオプションを使ってアップグレードしてみます!
$ helm upgrade external-secrets external-secrets/external-secrets \
--version 1.1.1 \
--server-side=true
結果:
Release "external-secrets" has been upgraded. Happy Helming!
NAME: external-secrets
LAST DEPLOYED: Sun Dec 7 21:21:07 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
DESCRIPTION: Upgrade complete
TEST SUITE: None
NOTES:
external-secrets has been deployed successfully in namespace default!
成功しました!バージョンの履歴も確認してみます。
$ helm history external-secrets
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Sun Dec 7 21:02:26 2025 superseded external-secrets-0.18.0 v0.18.0 Install complete
2 Sun Dec 7 21:21:07 2025 deployed external-secrets-1.1.1 v1.1.1 Upgrade complete
素晴らしい!v0.18.0からv1.1.1へ無事にアップグレードできました。
予想通り、Helm v4のServer-Side Applyを使えばアップグレードできることが確認できました。
検証2:Helm v3では本当にアップグレードできないのか?
Helm v4ではアップグレードできることは分かりました。では、本当にHelm v3では無理なのでしょうか?
私の仮説では「Server-Side Applyがないから無理」でしたが、実際に試してみないと分かりませんよね。
Helm v3の準備
事前にHelmのバージョンをv4からv3に落としておきます。また、先ほど導入したESOをアンインストールして、再度v0.18.0を導入したところから始めます。
$ helm version
version.BuildInfo{Version:"v3.19.2", GitCommit:"8766e718a0119851f10ddbe4577593a45fadf544", GitTreeState:"clean", GoVersion:"go1.25.4"}
$ helm ls -A
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
external-secrets default 1 2025-12-07 21:33:20.209825 +0900 JST deployed external-secrets-0.18.0 v0.18.0
v3の環境が整いました。
v1.1.1へのアップグレード(Helm v3)
まず、v4と同じように--server-sideオプションを試してみます。
$ helm upgrade external-secrets external-secrets/external-secrets \
--version 1.1.1 \
--server-side=true
結果:
Error: unknown flag: --server-side
当然ですね。Helm v3には--server-sideオプションがありません。
では、このオプションを外したらどうなるでしょうか?
私の仮説では、「CRDが大きいからアップグレードできないはず」でした。
実際に試してみます。
$ helm upgrade external-secrets external-secrets/external-secrets \
--version 1.1.1
結果:
Release "external-secrets" has been upgraded. Happy Helming!
NAME: external-secrets
LAST DEPLOYED: Sun Dec 7 21:37:29 2025
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
external-secrets has been deployed successfully in namespace default!
あれ、、、アップグレードできてしまいました!
私の予想とは違う結果になりました。なぜでしょうか?
なぜHelm v3でもアップグレードできたのか?
調べてみました。
すると、Helm v3はすでに3-wayマージという仕組みを導入していることが分かりました。
Helm v3の3-wayマージは:
- リリース保持データ(Helmが管理している前回の状態)
- テンプレート(今回適用したいマニフェスト)
- ライブリソース(クラスター上の現在の状態)
この3つを比較してパッチを生成します。
重要なのは、kubectl applyのlast-applied-configurationアノテーションに依存していないということです。そのため、CRDのサイズが大きくても問題なくアップグレードできるみたいです。
つまり、私の「Helm v3ではCRDが大きいとアップグレードできない」という考えは誤りでした。
公式が「BREAKING CHANGE」と言っているのに、なぜ?
ここで疑問が生まれます。ESOの公式リリースノートには「BREAKING CHANGE」「Server-Side Applyが必須」と書いてあったはずなのに、なぜHelm v3でもアップグレードできたのでしょうか?
改めてリリースノートを確認してみると、以下のように書かれていました:
シンプルな
kubectl applyやArgoのデフォルトのclient side applyは動きません!
kubectl applyには--server-sideを追加する必要があります。
よく見ると、ここではHelmについては言及されていません。つまり、kubectl applyとArgoの話をしているのです。
kubectl applyは、Client-Side Applyを使ってlast-applied-configurationアノテーションにマニフェスト全体を保存します。CRDが大きくなると、このアノテーションがKubernetesのサイズ制限(通常256KB)を超えてしまうため、Server-Side Applyが必要になります。
一方、Helm v3はkubectl applyとは異なる独自の3-wayマージを使っており、last-applied-configurationアノテーションには依存しません。そのため、この制限に引っかからなかったのです。
つまり、「BREAKING CHANGE」はあくまでkubectl applyやArgoを使っている人向けの警告で、Helmを使っている場合は独自の仕組みによって問題なくアップグレードできる、ということだったのです。
では、Helm v4のServer-Side Apply対応は何が嬉しいのか?
ここで新たな疑問が生まれます。
「Helm v3でもアップグレードできるなら、Helm v4のServer-Side Applyは何のためにあるのか?」
公式ドキュメントを読むと、以下のように説明されています:
複数のツールが同じリソースを管理する場合の競合解決を改善します。オペレーターや他のコントローラーがいる環境でテストします。
つまり、Server-Side Applyは「アップグレードできるかどうか」の問題を解決するものではなく、「複数のツールが協調してリソースを管理する」ための機能だということが分かりました。
今回の検証では、この機能の詳細な挙動までは確認できていませんが、複雑化するKubernetes運用において有用な機能であることは間違いなさそうです。
まとめ
今回の検証で分かったこと:
-
Helm v3でも、CRDが大きいリソース(ESO)を問題なくアップグレードできる
- 3-wayマージの仕組みがすでに導入されているため
- ESOのリリースノートの「BREAKING CHANGE」は、
kubectlやArgoを使う場合の話だった
-
Helm v4のServer-Side Applyは、アップグレードの可否を左右する機能ではない
- 公式ドキュメントによると、複数のツールでのリソース管理における競合解決のための機能
-
推測だけでなく、実際に検証することの大切さ
- 「新機能が追加された = それまでできなかった」という思い込みは正しくないこともある
- 公式のリリースノートも、文脈をよく読む必要がある
私は最初、「Helm v3ではアップグレードできないから、v4のServer-Side Applyが必要だ」と考えていました。しかし、実際に手を動かして検証してみることで、この考えが誤りであることに気づきました。
今回間違った理解を正すために検証することの大切さを学びました。