Helm パッケージ管理ツール
ご存じのとおり、k8s は複数の node 上でコンテナリソースを管理できますが、各コンテナは対応する pod-yaml ファイルによって管理する必要があります。
この記事で話したいのは、実は yaml ファイルが制御不能になる問題です。アプリケーション 1 つに Deployment を 1 枚、Service を 1 枚書くだけなら大した負担ではありません。しかしクラスタ内のアプリケーションが増えると、設定ファイルの数は目に見える速さで膨れ上がります。イメージタグを 1 つ変えるのに何枚ものファイルをめくり、環境を 1 セット増やすには設定一式をコピーしてパラメータを 1 つずつ書き換える。この段階まで来ると、人力での yaml 保守はもはや現実的ではありません。
大量の yaml の話から始めよう
まず問題の整理から。ある namespace に数十個の pod を組み合わせてデプロイする必要があるとします。例えば mysql クラスタ、kafka クラスタ。しかも kafka クラスタをデプロイするには先に zookeeper クラスタが必要で、アプリケーションには Redis クラスタや MQ キューのクラスタも必要、さらにアプリケーション自体のデプロイもあり、マイクロサービスは 50~100 個、あるいはそれ以上に及ぶこともあります。
こんなシナリオで yaml 設定ファイルを書けと言われたら、おそらく断りたくなるでしょう。仮に一度デプロイし、苦労の末に完了したとしても、リモートのデータセンターのクラスタにもう一度デプロイしなければならないとしたらどうしますか? ましてや、複数の異なるデータセンターのクラスタで設定情報を完全に一致させるにはどうすればいいのでしょうか?
これらの yaml の間には暗黙のデプロイ順序があり、大量の重複した設定項目もあります。イメージレジストリのアドレス、リソース制限、ストレージクラス名などは、ほぼすべてのファイルに書き写さなければなりません。共通パラメータが 1 つ変わったとき、どこか 1 箇所でも修正が漏れれば、それは潜在的なリスクです。
というわけで問題は明白です。すべての yaml 設定ファイルを一元管理でき、かつ再利用できるツールが必要なのです。
Helm:k8s のパッケージマネージャー
そこで Helm が誕生しました。その位置づけは CentOS における Yum パッケージ管理ツール、あるいは Debian における apt パッケージ管理ツールに似ています。ただし今回のパッケージ管理は k8s 環境をベースにしています。
Helm における各パッケージは Chart と呼ばれ、1 つの Chart は 1 つのディレクトリです。ディレクトリの中核的な内容は 3 つの部分にまとめられます。Chart.yaml はこのパッケージの名前やバージョンなどのメタ情報を記述し、values.yaml はデフォルトの設定値を格納してインストール時に外部から上書きでき、templates/ ディレクトリにはテンプレート構文を含む k8s リソースファイルが置かれます。インストール時、Helm は values をテンプレートにレンダリングして本物の yaml を生成し、それをクラスタに適用します。一度のインストールの結果は Release と呼ばれます。
設定再利用の鍵はこのテンプレート機構にあります。異なるデータセンター、異なる環境が同じ Chart を共有し、それぞれは小さな values ファイルを 1 枚保守するだけ。データセンター間の設定不一致の問題は自然に解消されます。Chart は依存関係も宣言でき、「kafka をデプロイする前に zookeeper が必要」といった関係はサブ Chart に任せられるので、順序を人が覚えておく必要もなくなります。
アプリケーションの公開者は Helm によってアプリをパッケージ化し、依存関係を管理し、バージョンを管理してソフトウェアリポジトリに公開し一元管理できます。k8s へのデプロイが必要になったら、コマンド 1 つで pod アプリケーション一式をデプロイできます。
日常的に使うコマンドは多くありません:
# Chart リポジトリを追加する(よく使われる bitnami リポジトリを例に)
helm repo add bitnami https://charts.bitnami.com/bitnami
# ローカルにキャッシュされたリポジトリインデックスを更新する
helm repo update
# コマンド 1 つでアプリ一式をデプロイ。Chart が必要なリソースをすべて自動作成する
helm install my-mysql bitnami/mysql
# 現在の namespace にデプロイ済みの Release を確認する
helm list
デプロイ後のアップグレードとロールバックも Helm が引き受け、変更のたびに新しいリビジョンとして記録されます:
# カスタムの values ファイルでデフォルト設定を上書きしてアップグレードする
helm upgrade my-mysql bitnami/mysql -f my-values.yaml
# アップグレードに問題があれば前のリビジョンにロールバックする
helm rollback my-mysql
Helm の公式サイト:
GUI 管理:Kubeapps
公式の中国語ドキュメントはかなり詳しく書かれているので、興味があれば読んでみてください。ここではさらに、Helm の UI 管理ツールを 1 つおすすめします。企業の Helm パッケージ情報をより手軽に管理できます。
kubeapps
Kubeapps 自体がクラスタ内にデプロイされる Web アプリケーションで、画面上でリポジトリの Chart を閲覧し、フォームに設定を入力してインストールを完了でき、既存の Release の確認やアップグレードもできます。全員にコマンドラインでクラスタを操作させるわけにいかないチームにとって、この種のツールはかなりの手間を省いてくれます。
ハマりどころと注意点
1) カスタム設定は自分の values ファイルに置く
デフォルト値の上書きには、Chart 内の values.yaml を直接書き換えるのではなく、できるだけ -f で独立した values ファイルを渡すようにしましょう。前者は Chart のアップグレード時にそのまま使い回せますが、後者の変更は Chart の更新時に上書きされて失われやすいのです。
2) アンインストールはよく考えてから
helm uninstall は Release に関連するリソースを一括で削除します。mysql のようなステートフルなアプリケーションでは、実行前にストレージボリュームの保持ポリシーを確認し、データごと消してしまわないようにしてください。
3) Chart のバージョンとアプリのバージョンは別物
Chart.yaml の version は Chart 自体のパッケージバージョンを指し、appVersion のほうが中のソフトウェアのバージョンに対応します。アップグレード前にどちらが変わるのかをよく確認し、テンプレートを変えただけのつもりが実はアプリまでバージョンアップしていた、という事態を避けましょう。
まとめ
Helm はあちこちに散らばった yaml を Chart にまとめ、テンプレート + values という方式で設定の再利用と複数環境の一貫性の問題を解決し、デプロイ・アップグレード・ロールバックをコマンド 1 つに収束させました。規模が小さいうちは手書きの yaml でもなんとかなりますが、アプリケーションが増えてきたら、早めに Helm というパッケージ管理のレイヤーを導入することで、後々の大量の反復作業を省けます。さらに Kubeapps のような UI ツールを組み合わせれば、チームで協働する際の敷居もぐっと下がります。
COMMENTS