Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

KubernetesとTerraformで実現するグローバル規模の科学クラウド (1/2)

By Matthew PorterSep 19, 202112 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

こんな状況に心当たりはありませんか?

あるサイエンティストが分析ツールやパイプラインを開発し終えたものの、それを本番環境にどうデプロイすればよいか、チームの誰もが確信を持てない。自動デプロイをシンプルに保ちつつ、パイプラインを支えるコンピュートリソースをコスト最適に拡張・縮小させ、予期せぬハードウェア/ソフトウェア障害への耐性を確保しながら、アップデートの展開や旧バージョンの廃止も簡単にこなしたい。そんな仕組みをどう構築すればよいのか、答えが見つからない――。

これだけ多くの重要なエンジニアリング上の課題が宙に浮いたままで、サイエンティストチームはどうすれば、アカデミックな実験環境でテストと開発を行うマインドセットから抜け出し、構築・運用の工数を最小限に抑えながら、本当に信頼性の高い本番規模の科学計算ツールを生み出すエンジニアリングへと舵を切れるのでしょうか。

オンプレミスのコンピュートクラスタと比べて、GCPやAWSのクラウド環境がもたらすグローバル規模のスケール、極めて高いインフラ信頼性、そしてコスト効率を活かすために、こうしたworkloadsをクラウド上で動かしたいとお考えではありませんか?

あるいは、そうしたworkloadsをクラウドで動かす際の土台となるDevOpsの原則についても、解説を聞きたいと思われているかもしれません。

本記事では、Google Cloud Platform (GCP) とAmazon Web Services (AWS) の両プラットフォームで動作するサンプルを使い、最新のDevOpsの原則を活用して実際の科学計算(バイオインフォマティクス)workloadsを実行する方法を、詳細なデモを交えて解説します。それでは早速、本題に入りましょう。

大まかに言うと、このサンプルコードでは次のことを行います。

  • 代表的なバイオインフォマティクスツール(FastQCおよびBWA)をコンテナイメージにまとめ、各クラウドのイメージリポジトリにアップロードする方法を示します
  • Infrastructure as CodeツールであるTerraformを使い、workloadsの実行に必要なクラウドインフラ一式を立ち上げ(かつ素早く破棄)します
  • これらのイメージと立ち上げたクラウドインフラをもとに、共通のワークフローパイプラインを各クラウドのフルマネージドなKubernetesサービス(コンテナ実行管理・オーケストレーションシステム)にデプロイします。Kubernetesクラスタ上でのタスクのワークフロー/パイプラインのオーケストレーションにはArgoを使用します

DockerTerraformKubernetesArgoを組み合わせることで、次のことが学べます。

  • workloadsの実行に必要なインフラを、シンプルなコマンドだけで立ち上げ、更新し、破棄する方法
  • 個々のステップで予期せぬエラーやインフラ障害が発生した際に自動でリトライしながら、エンドツーエンドの分析DAG型workloadsを実行する方法
  • workloadsのログやメトリクスを、クラウドネイティブなログ・メトリクス分析ツールに集約する方法
  • 必要に応じて自動でスケールアップ(グローバル規模の処理能力まで)・スケールダウン(コンピュートリソースを最小限、あるいはゼロに)するインフラ上でworkloadsを実行し、タスク完了に必要なCPU/RAM/ストレージリソース分だけを支払う方法。サーバーをアイドル状態のまま放置して請求額を無駄に膨らませる時代はもう終わりです
  • 新しいソフトウェアバージョンをシームレスに展開し、旧バージョンの利用を段階的に終わらせる方法

これらの原則を示すコードベースはこちらでご覧いただけます第2部では、その活用方法を解説します。DevOpsの原則の概観は飛ばしてコードに進みたい方は、ここで第1部を読み終えていただいて構いません。

一方、こうしたDevOpsの目標を支える技術についてガイド付きで知りたい方は、このまま読み進めてください。内容が濃いので、濃いめのコーヒーを一杯ご用意いただくことをおすすめします。

以下では、DevOps、コンテナ、Kubernetes、Terraform、そしてそれらの活用がバイオインフォマティクスをはじめとする実用ソフトウェアにとってなぜ不可欠なのかを、集中講座形式で解説します。

コンテナ:ツールをスケーラブルにデプロイするための基盤

本記事と関連コードベースが取り組む中心的な課題は、DevOps(開発と運用)の問題です。Docker化、Kubernetes、Terraformはいずれも、プログラムを大規模かつ確実にデプロイすることをシンプルにするという同じゴールに向けて連携します。最新のDevOpsの基礎を理解するには、コンテナの基本を押さえる必要があります。まずはそこから始めましょう。

多くのバイオインフォマティクス研究者にはおなじみの問題があります。アカデミアで開発された、依存関係が古いオープンソースのプログラムを使いたいケースです。インストールしようとすると、Python、Perl、その他依存ライブラリのバージョン要件がローカルにインストール済みの新しいバージョンと衝突し、パッケージ管理は悪夢のような状態になります。

おそらく多くの方は、AnacondaやPythonのvenvコマンドで仮想環境を作成して、この問題を回避してきたことでしょう。しかし残念ながら、このアプローチには限界があります。ある時点で、この方法は維持コストに見合わないほど扱いづらくなり、立ち行かなくなります。仮想環境は開発・テスト段階では許容範囲かもしれませんが、スケールさせる段階では到底持続できません。

規模を問わず多くの企業が、この事実を身をもって思い知る場面に立ち会ってきました。皆、白旗を揚げるまでに、必要以上に長くこのやり方に固執していました。

そこで登場するのがコンテナ化

コンテナとは、アプリケーションを任意のコンピューティング環境でベアメタルに近いパフォーマンスで素早く実行するために必要なコードと依存関係をすべて内包した、隔離されたソフトウェアプロセスです。

コンテナ/Dockerイメージは、コンテナをどう構築・実行するかを定義したものです。コンテナとは、コンテナイメージにパッケージされた命令を実行するプロセスを指します。

コンテナイメージは、シンプルなDockerfileで次の項目を定義することで作成します。

  • イメージのベースとなるOS(これは、そのイメージから作られたコンテナを別のホストOS上で実行することを妨げるものではありません)
  • インストールするパッケージ
  • イメージから生成されたコンテナを実行する際に走らせるシェルコマンド

このDockerfiledocker buildに渡すと、不変(イミュータブル)なイメージが作成されます。

では、イメージにパッケージしたサービスに、冗長性と水平スケーリングをどう持たせるか?

答えは、コンテナイメージの実行可能インスタンスを、複数のデータセンターにまたがる複数のホスト上で複数のコンテナとして展開し、それらの間でロードバランシングを行うことです。クラウドプロバイダーのグローバル規模を考えれば、コンテナによる水平スケーラビリティと障害耐性のポテンシャルは事実上無限です。

たとえば、FastQCのようなツールとその依存関係をすべてまとめたコンテナイメージを作成できます。このFastQCイメージから起動されたコンテナは、ホストマシンのハードウェア・ソフトウェア・OSを問わず、ほぼあらゆるコンピュート環境で、あらゆるスケールでデプロイできます。これは大きな恩恵です。

このコンテナの実行方法は、FastQCを単体で動かす場合とほぼ同じです。たとえば、入力ファイルをFastQCコンテナに渡し、結果の出力ファイルを受け取る、といった操作も簡単に行えます。

すべてのクラウドプロバイダーは、イメージのpush・pullを行うための独自のコンテナレジストリを提供しています。これは、gitリポジトリのブランチをpush・pullするのとよく似た仕組みです。たとえば、docker pull <image_name>を実行すれば、お使いのクラウドのコンテナリポジトリにホストされたFastQCイメージを取得できます。これにより、クラウド環境内のさまざまなコンピュートリソースにイメージを配置でき、依存関係インストールの面倒な手順を踏むことなく、docker run <image_name>でFastQCをすぐに実行できる状態になります。

gitリポジトリとの類似はそれだけにとどまりません。コンテナにもlatestv1.0.1といったタグを付けられるので、どのコンテナイメージがどのコードベースのバージョンに対応するかを追跡できます。docker run <image_name>:<tag_name>を使えば、特定のイメージバージョンに基づくコンテナをpullして実行できます。

コンテナ vs. 仮想マシン (VM)

コンテナは、ソフトウェアをパッケージ化して多様なコンピュート環境で実行可能にするという点で仮想マシンに似ているように聞こえる、と感じた方もいるでしょう。両者の違いは何で、なぜスケーラブルなDevOpsではコンテナが好まれるのか、疑問に思う方もいるはずです。

  • コンテナとVMはいずれも単一のホスト上で実行できますが、コンテナはVMのように、パッケージしたソフトウェアに加えて独自のOSを動かすことに伴う大きなパフォーマンス低下を招きません。コンテナはホストOSを共有するため軽量で、パフォーマンス低下は通常0.5%程度にとどまります。

最新のハイパーバイザー上で動く仮想マシンの場合、パフォーマンス低下が1〜3%で済めば運がいいほうです。スケールが大きくなれば、この差はコストに対して目に見える影響を与えます。

  • コンテナはビルドとデプロイが圧倒的に速く、VMでは実現できないアジャイルな開発プロセスを可能にします。VMはビルドに数分から数時間かかることもあります。
  • コンテナは不変であり、単一のファイルで定義されるため、ソフトウェアの継続的インテグレーションをより信頼性の高いものにします。たとえば、必要に応じて以前の動作確認済みバージョンへロールバックできますし、最後にデプロイされて以降に改変されていないことが保証されているため安心です。
  • コンテナは、モノリシックなアプリケーションよりも疎結合で分散されたマイクロサービスを優先するという、実証済みのソフトウェアアーキテクチャの作法を後押しします。これにより、修正や新機能のリリース時のデプロイが速くなり、本来は密結合である必要のなかった他の機能まで、モノリシックアプリ内の単一の不具合に巻き込まれて停止してしまう事態を防げます。

理想を言えば、大規模に展開する各プログラムは、それぞれ独自のコンテナイメージとして書かれるべきです。そうすることで、プログラムごとにデプロイされるコンテナ数を、リソース需要に応じて独立してスケールアップ・ダウンできるようになります。

  • コンテナはホストOSのリソースを共有し、また詳細なロギングとメトリクス取得を念頭に設計されているため、OSレベル・アプリケーションレベルでのロギングとメトリクス監視がより容易になります。

コンテナ実行の管理

たとえば、FastQCのようなプログラムをコンテナ化し、latestv0.11.9といった適切なタグを付けたとします。これを使ってFastQCの耐障害性とスケーラビリティを実現する――いや、大幅に簡素化するには、どうすればよいでしょうか。

そこで登場するのがKubernetes

Kubernetes(K8sと略されることが多い)は、コンテナ化workloadsの自動管理をコミュニティに広く普及させることを目的に、Googleが2014年に公開したオープンソースのジョブスケジューラ兼クラスタ管理プラットフォームです。グローバル規模のオペレーションを比較的簡単に実現できることから、広く普及しました。

Kubernetesは現在、オーサー数とissue数の観点でGitHubリポジトリのなかで2番目に人気が高く、これを上回るのはLinuxカーネルだけです。

K8sのドキュメントには、Kubernetesがなぜこれほど有用なのかについて優れた、ただしかなり長文の解説があります。K8sの強みを手短にまとめると、次のようなことが可能になります。

  • 自動的なビンパッキング: コンテナ化されたタスクの実行に使えるノード(クラウドサーバー)のクラスタをKubernetesに渡します。各コンテナがどれだけのCPU、メモリ、ストレージを必要とするかを伝えれば、Kubernetesはリソース利用率が最適になるようにコンテナをノードへ配置します。
  • セルフヒーリング: Kubernetesは、(ソフトウェアエラーやハードウェア障害で)失敗したコンテナを再起動し、コンテナを置き換え、ユーザー定義のヘルスチェックに応答しないコンテナを停止し、サービス提供の準備が整うまでクライアントに通知しません。
  • サービスディスカバリとロードバランシング: Kubernetesは、DNS名や独自のIPアドレスでコンテナを公開できます。トラフィック負荷が高ければ、そのコンテナの複数インスタンスにトラフィックをロードバランシングして分散させ、大規模な構成でも安定性を保ちます。
  • 自動化されたロールアウトとロールバック: Kubernetesではデプロイ済みコンテナのあるべき状態を記述でき、実際の状態を制御された速度でその望ましい状態へ近づけられます。たとえば、新しいコンテナ(例:‘v2’タグの付いたソフトウェアコンテナ)を作成し、既存コンテナ(例:‘v1’タグ)を削除して、コンピュートリソースをすべて新しいコンテナに引き継がせる、といった処理を自動化できます。新コンテナへの移行は一括で行うことも、たとえば既存コンテナを5分ごとに5%ずつ置き換えるようにカスタマイズすることも可能です。新コンテナのロールアウト中にエラー率の上昇が見られた場合も、コマンド一つでロールバックできます。

フルマネージドのKubernetes

嬉しいことに、Kubernetesは現在、主要なクラウドプロバイダーからフルマネージドサービスとして提供されています。代表例は次のとおりです。

  • Google CloudのGKE (Google Kubernetes Engine)
  • Amazon Web ServicesのEKS (Elastic Kubernetes Service)

これらのサービスは、Kubernetesのインストールやハードウェアのプロビジョニングといった作業をシンプルにし、Kubernetesクラスタ作成の手間を抽象化してくれます。コンソール上で数クリック・数分で作成できるK8sクラスタに対して、スケーラブルなworkloadsを起動することに集中できます。

GKEとEKSはいずれも、サーバーレスのクラスタコントロールプレーンマシンを備えています。これがいわばマスターノードとして機能し、ノードと呼ばれる複数のワーカーマシンと連携します。実行したいコンテナをコントロールプレーンに送信すると、コントロールプレーンがそれをノード上で実行するようにスケジュールします。ノード上で実行されているとき、これらのタスクはPodと呼ばれます。

整理すると、Pod(通常は単一のコンテナ)はノード上で実行され、Pod数のスケールアップ・ダウンはコントロールプレーンマシンが制御します。フルマネージドのK8sサービスでは、ノードのオートスケーリングのセットアップも自動化されています(GKEではオートスケーリングが組み込まれており、EKSではAWS内にEC2 Auto Scalingテンプレートが作成されます)。GKEとEKSなら、Podとノードの双方のオートスケーリングを最小限の手間で実現できます。

K8sクラスタをセットアップする際は、オプションのノードグループ、つまりクラスタで利用するハードウェアリソースのファミリーを定義しておくとよいでしょう。科学計算系のworkloadsを投入する場面では、ノードグループの指定が一般的です。

たとえば、GCPのc2ファミリーやAWSのc5ファミリーといったCPUリッチ/CPUコスト最適型のマシンファミリーを使う「high cpu」ノードグループを作成し、CPU負荷の高いworkloadsをこのノードグループに割り当てる、といった運用が可能です。GCPのa2-highgpuファミリーやAWSのp3ファミリーを使う「GPU」ノードグループを別に用意し、GPUを利用するworkloadsをそこに投入する、といったこともできます。こうすることで、特定のマシンタイプ上で動かすべきworkloadsに紐づいて、マシンタイプごとに独立してスケールアップ・ダウンが行えます。

ただし、GKEのStandardモードではなくAutopilotモードを使う場合、クラスタにノードグループを指定する必要はありません。GKE AutopilotはK8sエコシステムをグローバル規模のサーバーレスコンピューティングへとさらに近づけるかたちでDevOps業界をリードしており、ハードウェアリソースのプロビジョニングは抽象化されます。GKE Autopilotでは、コンテナのCPU/RAM/ストレージ要件を定義したK8sジョブを送信するだけで、GKEがその仕様に基づき、コンテナタスクの実行に必要なコンピュートリソースを裏側で自動的にスケールアップ・ダウンします。AWSにおけるGKE Autopilotの相当物がECS Fargateです。

再現性と自動化を備えたインフラ

コンテナ化と、Kubernetes上での堅牢なコンテナ実行を結びつけるのがTerraformです。読みやすいYAMLテキストで、目指すクラウドインフラの状態を定義できる、オープンソースのInfrastructure as Codeツールです。コマンド一つで、クラウドインフラの作成・更新・破棄を実行できます。

コンテナがソフトウェアバージョンを不変にし、再現とスケールを容易にするのに対し、Terraformは、それらのコンテナが動くクラウドベースのインフラを、複製・更新・削除しやすくし、かつ完全にバージョン管理できるようにします。

ソフトウェアをコンテナへ、workload管理システムをKubernetesへ移し、クラウドインフラをTerraformでコード化する。こうしておけば、ステルス段階からグローバル運用までスケール可能で、バグのある新リリースやハードウェア障害といったよくあるトラブルからも素早く復旧できる――そんな企業の土台を、DevOpsエコシステムの根幹をほとんど変えずに築くことができます。

得た知識を実践に活かす

お時間をいただき、ありがとうございました。本記事がDevOpsへの理解を深める一助となれば幸いです。ここで取り上げたスキルを実際に活用してみたい方は、動作するデモコードベースを使いながら学べる本シリーズ後編(全2回の最終回)へお進みください。

お読みいただきありがとうございました! 最新情報は DoiT Engineering Blog DoiT Linkedin Channel DoiT Twitter Channel でぜひフォローしてください。キャリアの機会については https://careers.doit-intl.com をご覧ください。