3つのレイヤーから構成される「ML Platform」

青山真也氏:さらに今回は、実際に私たちが作っているML PlatformとKubernetes as a Serviceを例に、どんな拡張性を活かした実装をしているのかを、一部紹介したいと思います。

まずはML Platformから紹介していきます。ML Platformの概要ですが、私たちがML Platformと言っているのは、主に3つのレイヤーから構成されています。

1つ目の物理層のレイヤーは、DGX A100とNetAppのAFF A800から成る物理的なレイヤーです。A100は1枚のGPUを複数のGPUに分割できる、マルチインスタンスGPUに対応しています。なので1筐体当たり56GPUまでいけます。

A800は、複数のプロトコルに対応していて、ブロックストレージのiSCSIと、共有ストレージのNFSの両方で提供できるようにしています。

その上に存在するのがGPU as a Serviceのレイヤーです。これがKubernetesを使って構築されている基盤になっています。GPUインスタンスや、Jupyter Notebookの提供を行なっているレイヤーです。

さらにその上のレイヤーにあるのが、GPU as a Serviceをベースとして提供しているアプリケーションプラットフォーム的なレイヤーです。

AI Platform相当のものが「Google」にもあるのですが、そのGoogleのAI Platform相当の基盤を提供していて、それぞれの基盤で同じような感覚で利用できるようになっています。

ほかにもGCPとオンプレだけではなく、オンプレとオンプレ、複数のデータセンター間へのマルチDCな展開も、現状検討しています。参考までに物理構成ですが、100Gbpsでつながっていて、けっこう高性能な基盤になっています。

2層目のGPU as a Serviceのレイヤーをもう少し深掘りしていきたいと思います。KubernetesとGPUの連携をしていかなきゃいけないので、KubernetesにはDevice Pluginという拡張ポイントが用意されていて、今回のようにNVIDIAのGPUや、TPUとか、FPGAなど、さまざまなデバイスをKubernetesから扱えるようになっています。

ちょうどこんな感じで、コンテナに対してリソースの制約としてGPUを1つアサインすると、コンテナに対してアタッチできます。

先ほど言っていた複数のGPUに分割できるMIGも、このDevice Pluginで対応しているので、分割したGPUをコンテナにアサインすることもできます。ここはOSSとしても提供されているので、そのまま使うだけです。

拡張機能の実装「クラウド向けの認証情報との連携」

今から2つ、GPU as a Serviceで独自に拡張している部分を紹介していきたいと思います。

1つ目がクラウド向けの認証情報との連携です。Notebookや機械学習などでコードを書いていると、クラウドの認証情報を使ってクラウドのS3からデータをロードしたり、できたモデルをプッシュしたり、クラウドのデータベースから何かを取って来たりなど、クラウドの認証情報を使ってクラウドとやりとりすることがけっこう多いかなと思います。

クラウド上のNotebookなどを使っている場合は、そのクラウドが認証連携を自動的に行なってくれるので、あまり気にすることなく使えます。

一方、オンプレ側でやっている場合、オンプレとクラウドを利便性良くつないであげる必要があるので、そういった実装を入れる必要があります。

私たちはどうしているかというと、KubernetesのSecretリソースに、新しいタイプとしてGCP向けとAWS向けのcredentialタイプを作っています。右のマニフェストのように、SecretタイプでGCPとAWSが用意されていて、かつデータの構造としてGCPとAWSでそれぞれ必要なタイプのキーが用意されています。

そのまま適当にタイプを付けて登録もできるのですが、私たちの基盤では、Validating Webhookを拡張ポイントとして使っています。この特定のタイプでSecretが登録される時には、対応する特定のフィールドがきちんと登録されているかどうかをチェックするようにしています。

このSecretを実際にPodにマウントする必要があります。マウントする方法は、GCPのWorkload IdentityやAWSのIAM roles for service accountsと同じように、Podのアノテーションに対して指定することもできますし、いったんServiceAccountに対して紐付けておいて、このServiceAccountをPodにアタッチして、間接的に紐付けることもできます。

このアノテーションに登録されている時に、実際にPodにマウントする処理は、Mutating Webhookで行なっています。Podのマニフェストが登録されると、アノテーションが埋め込まれているので、Podのenvフィールドやvolumesフィールドなどを自動的に書き換えて登録するという処理が、Mutating Webhookのレイヤーで行われます。

ほかにも、細かくいろいろな実装はあるのですが、今回はこれぐらいにしたいと思います。このように、Validating WebhookとMutating Webhookを使って拡張できるようになっています。

拡張機能の実装「S3などから効率的にデータを取得」

2つ目です。先ほどチラッとお話ししましたが、機械学習ではS3などからボリュームにデータをロードしたいというケースがけっこうあります。これもPersistentVolumeClaimを作って、Pythonのスクリプトで自動的にロードするとけっこう面倒くさいので、KubernetesのPlatformのレイヤーでサポートしています。

PersistentVolumeClaimのリソースを作成する時に、これもアノテーションでどこからデータを持ってくるかや、どのパスにデータをロードするかなどを指定して、特定のバケットからデータをロードする仕組みを用意しています。

具体的にはどうしているかというと、これはControllerで実装していて、PVCが登録されると、この情報をもとにデータをロードするKubernetesのジョブを作成して、データをロードしていきます。

ステータス情報は、PVCのstatus.conditionsのフィールドに状態として管理するかたちにしています。

現状、そのPVCのstatus.conditionのフィールドの状態を見てがattach待ちみたいなことはしてくれていないので、そのあたりはアップストリームの改修なども視野に入れつつ、やっていこうかなと考えています。

あとは先ほど紹介したクラウドの認証情報も扱えるようになっていて、認証情報を指定しておくと、その認証情報を使ってPrivateバケットのデータをロードできるようになっています。

現状はここまでの実装になっているのですが、当然複数回同じデータをロードするのはコスト的にあまりよくないので、元データを効率的に扱えるように、KubernetesのVolumeSnapshot機能と連携しつつ、そこから切り出して取り扱う連携にすることも現在検討しています。ここまでが、GPU as a Serviceのレイヤーについてです。

サイバーエージェント独自のプラットフォーム「AI Platform」

次に紹介するのはAI Platform部分のレイヤーです。これはGCPのAI Platformと互換性のある、私たち独自のプラットフォームだと思ってください。プラットフォーム間でMLワークロードをオフロードできます。

どのように同じようなかたちで操作性を保っているかというと、kubectl pluginを独自に実装することで、gcloud ai-platformコマンドと同等のサブコマンドを用意しています。なので、kubectl ai-platform以下は、基本的にはGCPと一緒です。あとは内部で必要な設定情報などを合わせています。kubectlからKubernetesを操作することで、AI Platformと同等の使用感を実現しています。

内部的には何をしているかというと、AI Platformの内部ではKubeflowを使っています。KubeflowはML向けのツールキットなのですが、TensorflowやPyTorchなどのさまざまなMLのフレームワークをサポートしていたり、ハイパーパラメーターチューニングをサポートしていたりします。

こういったMLフレームワークやハイパーパラメーターチューニングのツールを抽象化した独自のリソースをKubeflowはもっているので、そのカスタムリソースをkubectl pluginからうまいこと操作するかたちで、AI Platformは実装されています。

細かい内容を話していくと、それだけで30分や1時間がかかってしまうので、もし興味がある方は、前回NVIDIAのGTCで発表した資料も参考にしてみてください。

Kubernetes自体をデプロイして管理する仕組みを刷新するプロジェクトが稼働中

ここからは、後半のKubernetes as a Serviceの話をしていきたいと思います。私たちが、Kubernetes as a Service、いわゆるKubernetesクラスターを作って、ユーザーさんに払い出す仕組みをやり始めたのがだいたい2016年の中頃ぐらいからです。正式にリリースしたのが2017年ぐらいなので、もうけっこう前ですね。5年前ぐらいからこのAKEを作っています。

当時は、弊社ともう1、2社ぐらいしかこういったKubernetes as a Serviceを作っているところがなかったので、けっこう注目されていたかなと思います。このあたりのより詳細な過去の経緯は、また別途Keynoteで登壇した資料があるので、ぜひそちらを参考にしてください。

このAKEの中でどのような拡張機能が用意されているかというと、弊社にはOpenStackベースで作られたPrivate Cloudがあって、そこと独自に連携する部分を実装しています。

例えば、クラウドのLoad balancerと連携するCloud Controller Managerや、Ingress Controller、あとはAutoscaleに対応するためのCluster Autoscaler、そうしたPrivate Cloudと連携する部分を全部作らなければいけなかったので、自前で実装しています。

Kubernetesクラスターを払い出したはいいのですが、その払い出したクラスターを自動的に管理していかなきゃいけないので、それを実現するNodeを自動的にアップデートしたり、オートリペアするContorollerも内部で使っています。

ここまではよかったのですが、最近になってKubernetes自体をデプロイして管理するための仕組みを刷新するプロジェクトを動かしていまして。開発当初はKubeadmという公式のツールでも、HA構成じゃなくてもまともに動かない時代だったのですが、2021年になってそのあたりはかなりいろいろなものが出てきたので、現状置き換えの作業を行なっています。

当時はOpenStack HeatというCloud Formationに似たものを使っていましたが、かなり運用コストが高いのと、チームメンバーのナレッジ的にもそこを脱却したいという思いがありました。

あとは冒頭お伝えしたとおり、メディアとAI事業本部のデータセンターのチームが合併したので、その両方で提供できるKaaSを提供したいというのもあって、刷新プロジェクトを今行っています。

どんなものに刷新するかというと、Cluster APIと呼ばれるOSSのプロジェクトを利用したオーケストレーションを行っていくように、現状移行中です。

これは何かというと、まずこの下にあるようなbootstrap clusterという、Kubernetesを管理するためのKubernetesクラスターを作ります。親クラスターですね。ここに ”kind: Cluster”のリソースを登録すると、その登録情報をもとCluster APIのContorollerがVMを立てたりしながら、Kubernetesクラスター自体を管理して作っていくのがCluster APIです。

なぜこれにしたかというと、KubernetesのOSS、コミュニティによってメンテナンスされているというのも理由の1つですが、KubernetesのCluster自体もリソースとして管理されるようになるので、複数のClusterがあると複数のKubernetesのリソースとしてこのClusterリソースが登録されます。

それにより、この複数のKubernetesを横断しして管理するContorollerを作って何かできると考えています。自動的な管理を、より1段高められると考えています。Clusterリソースを元に、モニタリングの設定を自動的に行うなどのContorollerも書けると考えています。なので、Cluster APIを使って今後はより発展させていきたいと思っています。

最後にまとめです。今回は、弊社のdevチームで開発しているKubernetes関連のプラットフォームの拡張機能の一部を紹介しました。Kubernetes上で一般的なアプリケーションを動かす以外にも、Kubernetesと連携したかたちのアプリケーションは、さまざまなかたちで書けます。ぜひみなさんにもこういったところを挑戦してもらえたらなと思います。本日はありがとうございました。