Yahoo! JAPANのHelmの管理状態

高橋陽太氏(以下、高橋):続きまして、高橋からHelmのアップデートについてお話をしていきます。Helmは、Kubernetesのアプリケーション管理ツールです。Kubernetesのリソースをテンプレート化して、Chartとして管理します。ふだんKubernetesを使っている方なら、ご存知かと思います。バージョン2では、Tillerを経由してリソースの管理をしていました。

私たちの環境では、OpenStackクラスタはHelmのChartで管理しています。Helmはバージョン2からバージョン3の変更点が多く、私たちの環境でかなりの修正が必要だったため、アップデートが後回しにされていました。しかし、Kubernetesのバージョンアップもあり、Helmのバージョン3への対応が必須となりました。

このアップデート作業の失敗談と、そこから得られたものについてお話をします。

まず、Helmを利用して、どのようにOpenStackクラスタをデプロイしているのかを説明します。はじめに、Jenkinsによって該当するOpenStackクラスタの更新があると、各namespaceを作成します。このKubernetesのnamespaceが、OpenStackクラスタの単位となります。そして、その中にdeploy-managerというものをデプロイします。このdeploy-managerは、各namespace内のコンポーネントの初期化や、前処理の実行、namespace内のChartのデプロイをするために、インハウスで開発したツールです。

また、OpenStackコンポーネントのバージョンや、クラスタのさまざまなパラメーターはGitで管理されていて、更新後は自動的にdeploy-managerをとおしてデプロイされるようになっています。

バージョン2のHelmのアップデート

それでは、アップデートについてお話しします。Helmのバージョン2からバージョン3への変更が、大きな変更となっていて、単純にバイナリを置き換えるだけではアップデート完了とできません。

特に、Tillerが削除されていることや、Helmのリソース情報を保持するデータ形式が変更になっていることが大きな変更です。データ形式の変更については、公式のコンバートツールが用意されていて、それを利用できます。

しかし、私たちの環境はdeploy-managerをとおして各リソースを管理する、入れ子構造となっているため、少し複雑な構成です。そのため、無停止でアップデートをするためには、必要なリソースの依存関係など、内部構造を理解した上で手順をよく練る必要がありました。

Jenkinsによって自動化されているため、日常的な運用では触れることが少なく、詳細な部分まで理解することは、新卒1年目であった私がアップデート作業の中で最も時間をかけたポイントです。

簡単に説明すると、スライドの図のような手順でアップデートを進めることになりました。まず、各リソースの管理をしているdeploy-managerを一時的に止め、その間にバージョン2のリソース情報をバージョン3に移行します。そして最後にdeploy-manager、Helm 3の対応が完了したdeploy-managerをデプロイして完了です。

アップデートで起きたChartのデプロイ失敗

さて、手順は決定したのでアップデート作業に入っていきますが、その作業中に一部のクラスタでdeploy-managerからChartのデプロイが失敗するようになってしまいました。これによって、対象クラスタはリソース更新がすべて失敗した状態になってしまいました。

エラーの状況を整理すると、スライドの図のような状況になっていました。これはアップデート作業が完了したあとに、Helmのソースコードを含め詳しく調べていてわかったことですが、既存のリソースとdeploy-managerが、インストールしようとするKubernetesリソースのAPIのバージョンが異なっていました。

Helmのバージョン3からは、インストールしようとするリソースとの競合を検知する仕組みに大きな変更があり、その差でエラーが発生する状態でした。では、なぜAPIバージョンが異なるものがリポジトリにあったのかという話をします。

そもそも、Kubernetesのアップデートを並行して行っていたために、直近でKubernetes APIのバージョンを切り替える作業を実施していました。そしてこの変更は、一部の稼働環境で反映されていない状態で、古いAPIバージョンのまま動作をしていました。

今回のアップデート作業を機に、Helmに関しても設定ファイルで使用するバージョンを選択できるようにしました。

エラーの直接的な引き金となったのは、このChartのバージョンをHelmのバージョンと同時に上げてしまったことです。これによって、Helmのバージョン3に切り替わるのと同時に、KubernetesのリソースのAPIのバージョンも同時に更新される状態となってしまいました。

実際の作業時は、エラーの原因まで特定することができませんでした。しかし幸いなことに、エラーメッセージや検証環境でHelm 3の管理用アノテーションをすでにデプロイされているリソースに挿入すると、Helm 3の管理下であると認識させることが可能だとわかっていたので、それをエラーが起きた環境で実施しました。結果的に、かなりの量の作業が発生してしまいました。これでアップデートの話は終わりです。

アップデート作業で学んだ2つのこと

今回新卒として初めて、自分でアップデートの計画を立てる段階から、実際にバージョンアップをすることに挑みました。これをとおして、私が学んだことをまとめます。

まず1つ目は、アップデートの対象を明確にすることです。今回のアップデート作業の失敗の原因は、複数のリソースを同時にアップデートしようとしたことです。さらに、そのための原因の調査も難しくなってしまいました。特に、Helmのバージョン2からバージョン3のような、大きな変更を含むアップデートの際は、手順も対象もなるべくシンプルになるように設計しておくべきだと思いました。

2つ目は、アップデート作業の際は、心と時間に余裕を持つことです。今回私は、KubernetesリソースのAPIバージョンがHelmのバージョンと同時に上がることを、検証の段階で考慮できていませんでした。やはり、Kubernetesのアップデートと、Helmのアップデートを並行して行っている観点で、もう少し検証に時間をかけるべきだったと感じています。また、そもそも大きな更新を含むアップデートの作業の際は数段飛ばしせず、確実にアップデートすることが必要で、そのためにも時間と心の余裕は大事だと感じました。

完全自動化とアップデート作業で重要なこと

最後に、全体のまとめに移ります。Yahoo! JAPANでは、多くのOpenStackクラスタのコントロールプレーンとして、大規模なKubernetesクラスタをオンプレで構築しています。そして、Kubernetesのアップデートをとおして、段階的にアップデート作業ツールを整備してきました。

完全自動化のためには、作業中に問題に気づける仕組みづくりが重要だと考え、現在もよりよい仕組みづくりに取り組んでいます。

最後に、Helmアップデートの話をしました。バージョン2からバージョン3のアップデート作業を実施しましたが、結果的に、かなりの想定外の作業が発生してしまいました。そこから、アップデート作業の際は心と時間に余裕を持ち、手順および対象をシンプルにするという教訓を得ました。

短いですが、これで私たちの発表は終わりです。ありがとうございました。