なぜプラットフォームエンジニアリングが必要なのか
レガシーシステムをモダン化する際には、多数のレイヤーで構成されているDB・ミドルウェア・アプリケーションを、マネージドクラウドサービスやコンテナ化されたマイクロサービスに置き換え、三次元の立体的な構成に変更するケースが一般的である。
しかし、この場合、アプリケーションに関しては、マイクロサービス化やインターフェースの変更、プロトコル変更によるロジック分離やリファクタリング、そしてDBに関しては、スキーマ変更やインターフェースのリセット、他にもネットワーク設定やセキュリティ、リソースの再構成や運用ポリシーの変更など、新たにさまざまな課題を抱えることになる。これにより、ラーニングカーブが急激に上昇し、学習に必要な認知負荷も高まってしまう。
また、開発上の課題だけでなく、複数の部署との連携が必要となり、組織構成や責任の割り当てなどの組織的な課題も生じるだろう。実際、株式会社ジールのNoh Seontaek氏は、多くの部署から問い合わせを受けると同時に、“エラい人”を納得させるために多くの時間を要した経験があるという。
「これでは、せっかく改善するためにモダン化したはずなのに、結局、時間もお金もかかってしまっている。そこで、DevOpsを導入して、改善しようと考えた」(Noh氏)

DevOpsは、開発と運用のプロセスを統合して不要なコミュニケーションをなくそうとする概念であり、「You build it, you run it.(自分で作ったものは、自分で運用せよ)」という言葉で表現される。
DevOpsを導入したことで、開発チームの効率性は上がった。だが、時が経ち、プロジェクトが増えていくと、クラウドネイティブ技術やアーキテクチャの複雑さは増していく。開発者があらゆる業務や責任を負わなければならない状況に陥り、DevOps導入前よりも生産性が悪化してしまったのだ。
この問題にはオーストラリアのエンジニア Evan Bottcher氏も着目しており、「デジタルプラットフォーム」という概念を2018年に生み出している。さらにその翌年、デジタルプラットフォームの概念とDevOpsのアンチパターンを掛け合わせて誕生したのが、Matthew Skelton氏とManuel Pais氏が著した書籍『Team Topologies: Organizing Business and Technology Teams for Fast Flow』である。
Bottcher氏が提唱したデジタルプラットフォームは、のちに「内部開発者プラットフォーム(以下、IDP:Internal Development Platform)」として進化を遂げている。IDPとは、開発者がセルフサービス機能を活用できるよう、ツールチェーンとワークフローを設計・構築したものであり、アプリケーションのライフサイクル全体に必要な運用要件を包括している。そして、このIDPを提供するのがプラットフォームエンジニアであるというわけだ。
IDPがあれば、開発者は不要な負担を背負うことなく「You build it, you run it.」を実現して、自分の開発に集中することができるようになる。

そんなIDPを提供するプラットフォームエンジニアリングの目標は、次の3つであるとNoh氏は語る。
- Go faster(迅速に対応する):エンドユーザー(開発者)に迅速かつ持続的な価値を届けるべく、「Everything as a Service」を提供する。
- Decrease risk(リスクを減らす):再利用可能なコンポーネントで手動プロセスを自動化する。
- Increase efficiency(効率を上げる):デジタルプラットフォームとリソースを、フリートとして管理・拡張する。
続いて、IDPの構築において最も重要であるというコンテナプラットフォームの話に入っていこう。
IDP構築のポイント(1):コンテナランタイム
以下の図はIDPをKubernetesで構築した例だ。プラットフォームエンジニアは開発者と協議して、必要な要求を適用してプラットフォームを提供する。開発者はこのプラットフォームを活用して、アプリケーションをコンテナ化するだけで良い。

「なぜコンテナがIDPの構築に適しているかと言えば、先に挙げたプラットフォームエンジニアリングの3つの目標と、コンテナのメリットがマッチしているからである」と語るのは、続いて登壇した同社の岡田雄真氏だ。
「なかでも、デプロイが頻発するような開発環境においては、コンテナの『Quick Deployment(迅速なデプロイ)』や『Portability(可搬性)』『Consistency(一貫性)』といった特徴が効いてくる。また、バーチャルマシンと比較しても、コンテナはゲストOSのカーネルを必要としない分、オーバーヘッドが軽くなり、迅速に起動できるメリットがある」(岡田氏)

次に、コンテナの内部構造について話が及んだ。
コンテナを構築・操作する際に内部で実行されているソフトウェアを「コンテナランタイム」という。コンテナランタイムには、高レベルと低レベルがあり、それぞれ次のような役割がある。
- 高レベルコンテナランタイム:コンテナイメージの取得や、コンテナネットワークやストレージの管理を行う。(代表例:CRI-O・containerd・Docker・libpod)
- 低レベルコンテナランタイム:高レベルランタイムからの指示を受け、コンテナの作成や削除を実行する。(代表例:runc・kata-runtime・gVisor)
まず、Kubernetesのようなコンテナオーケストレーションシステムと、高レベルコンテナランタイムがやりとりをする。その際のインターフェースとなるのが「CRI(Container Runtime Interface)」というKubernetes向けに標準化された規格である。
次に、「OCI(Open Container Initiative)」というコンテナ技術の標準仕様を策定する団体が定めた規格に則り、高レベルコンテナランタイムが低レベルコンテナランタイムとやりとりを行う。
そして最後に、低レベルコンテナランタイムが実際にコンテナの操作を行う。
「Dockerがリリースされた当時は、『コンテナ=Docker』と評されるほど、Dockerは支配的なポジションを築いていた。しかしDockerはCRIに対応しておらず、Kubelet(Kubernetesのノード管理エージェント)がDockerエンジンとやりとりするには、Docker Shimという中間レイヤーが必要だった。他にもいくつかの課題もあり、Docker依存を解消するために進化してきたコンテナランタイムもある。このようにコンテナランタイムが進化すると、実運用ベースでの切り替えが発生することがあるため、プラットフォームエンジニアはトレンドをきちんと押さえておくことが重要だ」(岡田氏)
IDP構築のポイント(2):コンテナオーケストレーション
続いて、コンテナオーケストレーションについて、見ていこう。コンテナオーケストレーションは、「コンフィグレーション・プロビジョニング・可用性・拡張性・セキュリティ・リソース割り当て・負荷分散・ヘルスモニタリング」といった機能により、大規模なコンテナ運用の負荷を大幅に軽減し、アプリケーションの可用性・安定性を向上させる。
コンテナを実行する際には、コンテナオーケストレーションが自動でスケジュールを決め、最適なホストを選定し、コンテナランタイムによってデプロイが行われる。その後のコンテナライフサイクルもコンテナオーケストレーションによって自動化されるが、オーケストレーションツールによって、コンテナランタイムの種類や実行方法、細かい機能には差異があるため、システムやプラットフォームに最適なものを選択する必要がある。
3つの代表的なコンテナオーケストレーションを比較してみよう。
- Docker Swarm:Dockerネイティブなオーケストレーションツール。マネージャーと複数のノードで構成されており、各ノードのDockerデーモンによってコンテナが実行される。他の2つに比べ機能が限定的であるものの、学習コストが低く小規模なシステムで利用されることが多い。
- Apache Mesos:マスターと複数のエージェントデーモンで構成されている。マスターノードにスタンバイを用意しておくと、マスターがダウンしても復旧できるという高い可用性を実現している。コンテナだけでなく、コンテナ化されていないワークロードにも処理を分散できる。柔軟性が高く、ビッグデータの処理やマシンラーニングなどを統合管理するような超大規模なシステムで活用されることが多い。
- Kubernetes:コンテナオーケストレーションのデファクトスタンダード。学習コストが高い一方、機能が豊富で、コミュニティも活発である。AWS・GCP・Azureなどクラウド対応が充実しているが、中身のランタイムには差分があることをプラットフォームエンジニアは押さえておく必要がある。

最後に岡田氏は「開発者中心の組織において、開発者の効率性を向上させ、認知負荷を解消するためには、プラットフォームエンジニアリングという新しいアプローチが求められている。プラットフォームエンジニアリングの実現にはIDPの構築が必要であり、IDPのベースとなるコンテナからアプローチしていくことが有効だ」と語り、セッションを締め括った。