はじめに
株式会社MatrixFlowでは、ウェブブラウザから機械学習を実行できるノーコードAIプラットフォームであるMatrixFlowの開発を行っています。MatrixFlowの実行基盤はAmazon Web Services (AWS) 上にあります。本記事では、AWS上で稼働しているMatrixFlowの実行基盤を以下の3つに分類して、それぞれの実装内容とそうなった背景・運用していて良い点悪い点を紹介していきます。
以下の図が、今回紹介するMatrixFlowの実行基盤の全体像です。
また、本記事で複数回出てくるAWSサービスと記事内の表記方法の対応は以下の通りとします。
AWSサービス名 | 記事内ので表記方法 |
---|---|
Amazon ECS | ECS |
Amazon EC2 | EC2 |
Amazon ECR | ECR |
AWS Fargate | Fargate |
AWS Batch | Batch |
Amazon S3 | S3 |
Amazon RDS | RDS |
AWS CodePipeline | CodePipeline |
AWS CodeBuild | CodeBuild |
AWS CodeDeploy | CodeDeploy |
Amazon CloudFront | CloudFront |
Application Load Balancing | ALB |
各部分の詳細
1. MatrixFlowのサービス稼働について
サービスの稼働部分というのはユーザーからのリクエストを受け付けて、処理する部分のことを指しています。主なリクエストと処理内容は以下の3つです。
- フロントエンドのコンテンツ配信
- API/WebSocket通信
- 学習/推論実行
より詳しい構成とその構成を選択した理由を紹介していきます。
フロントエンドのコンテンツ配信の構成
MatrixFlowでは、フロントエンドの実装にはVue.jsを利用しています。配信するコンテンツはDockerイメージ内にビルドしたHTMLやJavaScriptなどのファイルを置いてあります。そして、それらのファイルをECS内で稼働しているNginxから配信しています。
ECSからフロントエンドのコンテンツを配信している技術的な理由は特にはなく、MatrixFlowをECSで稼働させる前の構成を引き継ぎました。ビルドされたファイルを配信しているだけのため、サーバーサイドでレンダリングなども行ってはいないです。
よくない点として、ECSが落ちてしまうとコンテンツ配信も同時に止まってしまい、ユーザーに見えてほしくないページが表示されてしまうところです。CloudFrontでのコンテンツ配信も考えられますが現時点でその構成はとっていないです。
API/WebSocket通信とAmazon ECSの構成
ユーザーとのデータのやりとりは、REST APIとWebSocketを利用しています。REST APIとWebSocketはPythonのWebフレームワークであるFastAPIを利用しており、FastAPIはECS上で稼働しています。ユーザーのデータはRDSやS3に保存されており、ECSからそれぞれのリソースへアクセスするようになっています。
ECSをコンテナ実行環境として選んだ理由は、ローカル開発やテスト実行ではDockerを使用しており、Dockerイメージの資産をそのまま利用できるためです。加えて、CodePipelineやCodeDeployを利用してデプロイ自動化をしたかったことも理由の1つです。
ECSのタスクの起動タイプはEC2ではなくFargateを選択しています。これは、FargateだとAWSの責任範囲がEC2に比べて大きく、自社で管理するよりもセキュリティは高く運用コストは低いと判断したためです(参考:AWS責任共有モデル)。もちろん、Fargate上で稼働しているアプリケーションに関してはAWSの責任範囲ではないので、アプリケーションの安全性は、利用しているPythonやパッケージのバージョンをなるべく最新のものにしたり、コンテナイメージをスキャンしたりすることで担保するようにしています。
ECS以外のコンテナ実行環境であるEKSの利用は現時点では考えていません。理由は、kubernetesの運用経験がなくローカルでもdocker-composeを利用して開発を利用しているためです。kubernetesを導入する際には、ローカルの開発環境も合わせて変えた方が良いと思うのですが開発者に不要な負担を強いる点も導入に至らない理由になります。加えて、AWSのkubernetesサービス(Amazon EKS)はECSと違ってサービスを利用しているだけで稼働料金がかかるためです。それらの理由からECSでDockerコンテナを稼働させています。
ECS/Fargateで動かしているメリットは、Dockerコンテナを動かすだけで簡単に使い始めることができ、管理することが少ない点です。加えて、ECSの起動に失敗した場合はDockerfileが間違っていることが多く、問題の切り分けがしやすいところも良いです。デメリットは、起動に少し時間がかかるところと、EC2で実行する場合と比べて少し稼働料金が高いことです。そのため本番環境以外では、スポットインスタンスなどを利用することで料金を抑えるようにしています。
学習・推論実行を行うBatchの構成
学習や推論は、Batchで実行しています。すなわち、ユーザーが学習や推論を実行するたびにそれぞれに個別のBatchのジョブが開始されます。
学習や推論を実行する際には大量の計算リソースを消費します。学習や推論をREST APIやWebSocketの通信を受け付けているECS上で実行するとサービスが正常に動作しないことがありました。加えて、ECSのFargateで学習や推論を実行するには、そもそも計算リソースが十分ではないことも考えられました。そのため、学習や推論をECSではなくBatchで動かして、十分な計算リソースを確保しつつサービスに影響が無いようにしています。
この構成の良いところは、学習や推論だけ別のインスタンスで稼働しているので本番のサービスに影響を及ぼさないところです。反面よくないところとしては、学習と推論を実行し始めてから時間がかかりユーザーを最大で5分ほど待たせてしまう点です。これはBatchの機能として処理のリクエストから処理開始まで即時実行が求められているわけでは無いので、起動が早くなくても正しい挙動です。調べたところ時間がかかっていたのは、EC2の起動時間とDockerイメージをECRからプルするところでした。そのため現時点では解決策として、数台のEC2をあらかじめ起動して少しでも待ち時間が少なくなるようにしています。
2. MatrixFlowのリリースのパイプラインについて
MatrixFlowのリリース時の作業
MatrixFlowでは、AWS上に3つの環境を動かしています。
- 開発が動作確認する開発環境
- カスタマーサクセス部や営業部などが本番リリース前に動作確認するドッグフーディング環境
- ユーザーが操作できる本番環境
ここでいうリリースとは、開発者が行った修正や新規機能をユーザーが操作できる本番環境へ反映・デプロイすることです。その際にMatrixFlowでは以下のステップを踏まえたリリース作業をしています。
- 開発環境に反映・デプロイする
- 開発環境でテストを実行する
- ドッグフーディング環境に反映・デプロイする
- ドッグフーディング環境で動作確認を開発部以外のメンバーに動作確認をしてもらう
- 本番環境に反映・デプロイする
リリース作業についてもAWSのサービスを利用して、①・③・⑤の箇所は自動で各環境に反映・デプロイされます。そして、デプロイでは以下の2つの作業を実施しています。
- DockerイメージのビルドとECRへのプッシュ
- データベースのバックアップとマイグレーション実行
この反映・デプロイの自動化のAWS上の構成について説明します。
MatrixFlowのリリースの自動化について
MatrixFlowではCodePipelineとCodeBuildとCodeDeployを利用してデプロイの自動化をしています。以下の図がデプロイの全体像になっています。
GitHubの特定のブランチにPushされると、GitHub ActionsからEventBridgeにイベントが発火されます。GitHub Actionsから直接CodePipelineの実行をしないことで、セキュアにしつつ疎結合な作りにしています。
GitHubへPushでデプロイが開始されるのですが、デプロイが毎回動いてしまうと困る場面があります。それはテスト実行中やバグの修正中で、これらのときは全てのバグを直した上でデプロイを実施したい時です。そのため、デプロイを実行したい時だけに進められるようにCodePipelineの承認という機能を利用しています。承認のタイミングでは必ず開発メンバーの誰かのアクションが必要なため、この機能でデプロイを進めるかどうかを制御しています。
承認が実行されると、最初のCodeBuildではECSやBatchで利用するDockerイメージをビルドしてECRにPushします。その次のCodeBuildではデータベースのRDSのバックアップを取得し、マイグレーションを実行しています。Dockerイメージのビルドとデータベースの更新を別々のCodeBuildにしているのは、デプロイ実行中にエラーが発生した時に問題の切り分けがしやすいようにするためです。
デプロイの最後にECSをCodeDeployを利用して更新しています。サービスのダウンタイムをなるべく小さくするために、ECSの更新方法にはBlue/Greenデプロイを採用しています。Blue/Greenデプロイとは、旧環境と新環境を一時的に並列で実行し、新環境が正しく動くことを確認してからリクエストを新環境へ流す方法です。新環境が完全に立ち上がるまで旧環境がへリクエストを流すことができるのでユーザーは環境の切り替わりをほとんど意識することなく操作可能になっています。
これらのリリース作業ではそれぞれ区切りとなるタイミングやデプロイが成功・失敗した場合Slackに通知が飛ぶようになっています。そのため、AWSのコンソールまでリリースの進行状況を確認しなくても、リリース状況がほぼリアルタイムに把握することができます。
これらの自動化をするようにしてよくなった点は、更新時の人的ミスの削減と属人化の排除ができた点です。Dockerのビルドやデプロイの実行を自動で行ってくれるため、更新時の人的ミスは起こらなくなりました。加えて、テスト時のバグ修正や新規機能追加の反映を行う際に誰でも開発環境を更新できるようになり、デプロイ作業時の負担が減りました。よくないところは、Dockerのビルドに時間がかかりデプロイ全体の作業が遅くなってしまっている点です。現時点で、1回のデプロイに1時間ほどかかっておりここの時間をもっと短くできたら良いなと思っています。
3. MatrixFlowのセキュリティ・監査について
MatrixFlowはtoB向けのサービスのため、契約時にセキュリティチェックを求められることがあります。主に要求されることは、アプリケーションのセキュリティと監査証跡のためのログの保管が主になっています。
アプリケーションのセキュリティ
MatrixFlowのアプリケーションのセキュリティの1つであるWAFは、AWSが提供しているAWSでのWAFオートメーションを参考に構築しました。
WAFに付与しているのは、記事のコードを参考に以下の4項目を付与してあります。
- AWS マネージドルール (A)
- SQL インジェクション (D) および XSS (E)
- スキャナーとプローブ(G)
- IP 評価リスト (H)
AWSマネージドルールを適用するだけで、基本的な脅威からは守ることができます。以下の図は、実際にWAFが設定したルールに基づいて不審なアクセスをブロックしているログです。そのほかのAWSサービスの設定を評価・監査・審査のためにAWS ConfigやAWS SecurityHubを利用しています。一定のセキュリティを担保してMatrixFlowは稼働しています。
監査証跡のためのログ
MatrixFlowでは、ECSで稼働しているアプリケーションやAWS WAF・RDS・VPC・ELBのログはAmazon CloudWatch LogsやS3に出力しています。これらのログは経過日数で削除しておらず、過去に遡って検索できるようにしています。
そのほかにもAWSそのものの操作ログをAWS CloudTrailを利用して取得してあります。記録はS3に2021年3月から保存されており、その時点からのAWS内の操作ログを取得・確認することができます。
おわりに
MatrixFlowの構成について、大きく3つに内容を分類して紹介しました。本記事では、サービス稼働部分が主な話でしたがAWS構成をコードで管理している取り組みの記事も書く予定です。