Kubernetesの設定をパッケージ化するためにHelmを使用することにした根拠について説明
はじめに
Corda 5は当初からクラウドネイティブを想定して設計されています。具体的には、ワーカーアーキテクチャにより、Cordaプラットフォームを構成するコンポーネントの独立したスケーリングとレジリエンシーを実現し、全てがメッセージバスにより疎結合されています。これらのコンポーネントの提供メカニズムとして、コンテナオーケストレーションプラットフォームであるKubernetesを用いて実現します。この実現方法は最適解と言えるでしょう。本記事では、Kubernetesの設定をパッケージ化するためにHelmを使用することにした根拠について説明します。(訳注:今回の記事は、技術的な細部にも踏み込んだ記事です。)
なぜHelmなのか?
Kubernetesは、コマンドラインから直接的にリソース作成することもできますが、より一般的には、必要なリソースを宣言した上で、Kubernetesが稼働しているクラスタと要求されたリソースが一致しているかを確認させる形をとります。これらのリソース設定には、YAML(訳注: 簡単なデータシリアライズ言語です)が使用されます。それでは、なぜCordaをインストールするためにYAMLファイルへのリンクを提供するだけではいけないのでしょうか?
環境特有の設定が必要だからです。CordaにPostgreSQLやKafkaをどこで見つけるかといった前提条件を指定することは、R3側で用意できるYAMLファイルには不可能です。また、予想される処理負荷に対応するためにFlow workerの数を変更したいかもしれませんし、Cordaの開発者であればデバッグを有効にする必要があるかもしれません。これらは全てCordaの起動前に必要な設定(事前に設定する必要があります)であるため、Corda内の設定値とすることができません。
既に、KubernetesのYAMLを取得し、それを編集するツールは数多く存在しています。Kustomizeが代表的な例です。これらのツールは、他人の設定を受け取り、それを自分のニーズに合わせて変更する必要がある場合に最適です。現在、一般的に提供されていないのは、設定のオリジナルの提供者が現場で変更された設定を検証し、反映させる手段です。そこで、Helmの出番となります。
本来、Helmはテンプレートエンジンを提供します。設定の提供者は、Kubernetesリソースのセットをテンプレートとして定義し、変更可能なポイントを定義します。また、必要であればデフォルト値も定義します。これらは、Helmがチャートと呼ぶものに一緒にパッケージ化されます。(※他のKubernetesプロジェクトと同様に、Helmは航海(訳注:チャートには海図という意味があります。)という隠されたテーマを追いかけ続けているようですね。) チャートの使用者は、インストール時に自身が上書きした内容を特定できます。
Helmを使ったCordaのインストール
オープンソース版のCordaのデプロイ方法の詳細は、Githhub wikiに載っていますが、念の為、Helm CLIを使う最も単純なインストール方法を紹介します
helm install charts/corda mycorda -f values.yaml
Helmは中央リポジトリからバージョン管理されたチャートをインストールすることができますが、ここではcoda-runtime-osというGitHubリポジトリにあるcharts/cordaディレクトリを指定しています。values.yaml ファイルには環境固有の設定が含まれています。詳細はGitHub wikiに記載されていますが、values.yamlに記載されている項目としては以下のようになります。
kafka:
bootstrapServers: kafka.example.com:9092
db:
cluster:
host: postgresql.example.com
existingSecret: prereqs-postgresql
この例では、環境内の前提条件にアクセスするために、必要な最低限の情報のみ用意しています。
秘密情報(Secret)の管理について一言
一般的に、KubernetesにおけるSecretの管理に関する問題は既に解決されているとされています。しかしながら、その解決方法は無数に存在します。そのため、Cordaのようなプラットフォームにとっては、潜在的に相互運用が必要な統合機能が複数あることを意味し、複雑であることが分かります。
IDの証明書と、ネットワーク参加認証の証明書はプラットフォームの中核部分であり、これらはHSM(Hardware Security Module)に保存されることを前提に、crypto workerによってプラットフォーム内で処理されます。しかし、例えば、Postgre SQLの認証情報などプラットフォームのブートストラップ(立ち上げ)に必要な証明書についてはどうでしょうか。
今のところ、私たちは単純な2つのオプションをサポートしています。
- Helmチャートのインストールに認証情報を上書きする形で渡します。
- Helmチャートのインストールに上書きする形で、認証情報を含む「単一のSecret」を渡します。
1つ目は安全でないように思えますが、実際は、Helm Secrets プラグインのようなツールを使用すると、Helm チャートがインストールされる時点まで認証情報を暗号化して保持することができます。それでも不十分と考えるユーザーのために、2つ目のオプションもサポートしています。CordaオペレータはKubernetesのSecretをどのように設定するかを自由に決めることができます。BitnamiのSealed Secretsといったツールのように、認証情報がKubernetesのクラスタ内でのみ復号されるようにすることができます。
私たちは、この2番目のオプションでさえ、一部のCordaユーザーにとっては不十分であると思われるので、より安全な手法が提案されることを期待しています。皆様からのご意見をお待ちしています。
リリースの管理
Helmは単にテンプレートエンジンだけでなく、より多くの機能を提供します。既にCLIに拡張性を持たせるプラグインについては触れました。Helmのドキュメントを参照すると著名なプラグインのリストが存在します。中でも、Helmはリリース(訳注: リリースとは、Kubernetesの用語であり、クラスタで実行されているチャートのインスタンスを指します。)という概念もサポートしています。
先ほどのインストール例では、mycordaというリリースを作成しました。Helmは各リリースの現在の設定をSecretに保存します。このSecretは、リリースがデフォルトでデプロイされているネームスペースに存在します。これにより、Helmはあるリリースの変更履歴を保持することができ、以前のバージョンへロールバックさせることもできます。ただし、リリースしたデプロイが後方互換性を持っていることが条件になります。Corda 5がGAに到達する前に、アップグレード/ダウングレードのポリシーを明確にするつもりです。ご期待ください。
Helmが提供するもう一つの機能としては、Hookが挙げられます。Hookを使うことで、リリースのライフサイクルの様々なポイント(例:インストール時やアップグレード時)でKubernetesにて、リソースを作成することができます。現在、Install Hookは、Corda Helm チャートで使用されています。用途としては、PostgreSQLとKafkaの初期ブートストラップを行うKubernetesのジョブの作成です。これらのジョブは、初期データベーススキーマの作成と入力、および必要なKafkaトピックの作成を行います。私たちは、全てのCordaのオペレーターが、これらのアクションを実行するのに十分な権限を持つ証明書を提供することを望んでいないと認識しています。したがって、これらのステップはチャートの上書きによって変更することができ、必要な設定はオペレーターが個別に実行することができます。
進化したHelm
以前のバージョンのHelmは、Tillerと呼ばれるサーバーサイドのコンポーネントを用いてデプロイを行っていました。このため、Tiller がデプロイを許可したユーザーよりも大きな権限を持っている場合、(中央集権的なモデルに近くなるため)セキュリティリスクが増大する可能性がありました。ありがたいことに、現在ではTillerは廃止され、HelmはCLIという形で、ローカルユーザーの権限を使ってKubernetes APIを動かしています。つまり、KubernetesクラスタにおけるHelmのサインは、リリース履歴を含む前述のSecretと、デプロイされたリソースに追加されたラベルのみということになります。
もし、設定項目に関してHelmではどうしようもなかった場合、まずはR3に連絡をすることをおすすめします。もし、お客様が必要なものであれば、他のお客様もその機能を必要としている可能性が高いので、チャートの上書きで必要なものを指定していただけるとありがたいです。もし環境設定に必要な項目が足りなかった場合、Helmにはpost-renderingという概念があり、クラスタに適用する前に生成されたリソースを修正できます。また、Kustomizeを使って変更することもできます。
なぜ”オペレーター”を使わないのか?
オペレーターパターンは、Kubernetesにアプリケーションをデプロイするための手段として、非常に人気があります。これは、Kubernetes APIを、アプリケーションのデプロイに必要な設定値を含むcustom resourceで拡張する事を含みます。アプリケーションプロバイダは次に、custom resourceのインスタンスをアプリケーションのインスタンスに変換するcustom controllerを作成します。このアプローチの利点は、custom controllerは単に必要なKubernetesリソースの作成を処理するだけでなく、状態の管理など他のアクションを実行できることです。
Cordaにてoperator patternを採用することに対して否定はしませんが、今現在、私たちの焦点はプラットフォームが十分にクラウドネイティブである事です。つまり、プラットフォームの他の機能との協調動作なしに、worker自身だけで状況を処理し切れる事を重視しています。
より広範なエコシステム
Helmのような地位が確立されたツールを使用する利点は、より広範なエコシステムをもたらすという点です。例えば、Ansible や Terraform を使ってインフラのデプロイを管理している場合、Helmと統合することができます。また、Flux用のHelmコントローラーを使用してCordaのデプロイをGitOpsのアプローチで行いたい場合もあるでしょう。
また、Helmは他のアプリケーションの起動・実行の際に活躍します。例えば、coda-dev-helmのGitHubリポジトリでは、開発用にCordaの前提条件をKubernetesクラスタにデプロイするためにHelmチャートを提供しています。これは既存のPostgreSQLとKafkaのHelmチャートをCordaに適した方法で設定し、パッケージ化したものになります。
DeveloperのHelm学習について
ここで少し、R3でのお話をしたいと思います。R3の開発者は、当初、Docker Compose を使って、Kafka や PostgreSQL と共に Corda workerを立ち上げてきました。Cordaとその前提条件のためのHelmチャートは、CI/CDパイプラインで実行されるテストの一部として初めて導入されました。そこから次のステップとして、開発者がパイプラインの実行中に発生した問題をデバッグできるように、Docker Desktopやminikube上のKubernetesでテストをローカルに実行しました。
Compose ファイルと Helm チャートを同期させるためのオーバーヘッドもありましたが、お客様が運用で使用する予定のものと同じアーティファクトを開発者が使用することには明らかな利点があります。やがて、Cordaクラスタを運用する際には、すべての開発者にHelmチャートを使ってもらうべきであると考えるようになり、Composeファイルは徐々に使われなくなりました。Helmチャートへの移行には、多少の学習時間が必要でしたが、R3の開発者は非常に素早くこの変化に適応することができたこともご報告させていただきます。
まとめ
Corda 5のデプロイにHelmを使用するに至ったプロセスと、それによって可能になった機能についてご理解いただけたと思います。皆様のフィードバックをお待ちしております。
<ご質問・ご要望の例>
- Corda Portalの記事について質問したい
- ブロックチェーンを活用した新規事業を相談したい
- 企業でのブロックチェーン活用方法を教えて欲しい 等々
SBI R3 Japanインターン エンジニアリング部所属
Corda 5の技術検証や記事翻訳など多岐に渡ります
趣味:英語学習(まだまだですが…)・テニス・映画鑑賞