はじめに
はてなサマーインターン2018の大規模システム開発コースの成果報告をします。
今年は、メンターのid:cohalzさん、id:wtatsuruさんの下、実際に使われているサービスをAmazon ECS(Elastic Container Service)にデプロイする基盤を構築しました。 コンテナでサービスを本番運用するために、AutoScaleの検証や、デプロイ時間の計測、改善策の検証を行いました。また、開発、デプロイフローを楽にするために、AWS CodeBuild、CodePipelineを使ってCI/CDの構築も行いました。これにより、PullRequestごとにCIが走り、masterにマージされたら自動でECSにデプロイすることができるようになります。高速なデプロイ切り替えを行うために、Blue-Green Deploymentの検討も行いました。 他にも、MicroScannerを用いてセキュリティスキャンを行い、パッケージの脆弱性を確認を行いました。 これらの構成の再現性を持たせるために、CloudFormationで構成を管理することもやっていきました。
既存の課題
急なアクセス数増加への対応
問題点
現在は、負荷を見てそれに耐えられる台数を決めていました。 しかし、負荷が少ないときは、リソースが余ってしまいます。 負荷が増えても、EC2インスタンスを手動で増やす必要があります。 そのため、想定以上の急なアクセスがあった場合、対応が遅れてしまうことがあります。
解決策
コンテナ化し、スケーリングしやすくします。 AutoScaleを導入し、負荷に応じてタスク数を変えます。
CI/CD管理コスト
問題点
CIにJenkinsを使っていますが、 Jenkinsサーバの管理コストがかかっていました。 さらに、CDは行っておらず、リリースプロセスは人手で行っていました。
解決策
CI/CDには、CodeBuild、CodePipelineを用います。 CodeBuildでは、テストや、Dockerイメージの作成を行います。 CodePipelineでは、CodeBuildで作ったイメージを使って、ECSに自動デプロイを行うようにしました。
AWSでのサービスのコンテナ化
AWSでコンテナアプリケーションを運用する際、ECS(Elastic Container Service)が利用できます。 同じようにコンテナクラスタを運用することができるサービスにEKS(Elastic Kubernetes Service)があります。 EKSを採用しなかったのは、AWSにおいてKubernetesの導入・管理コストが高かったためです。 なぜなら後述するAWS Fargateは現時点ではEKSに対応しておらず、EKSを運用するとなるとクラスタのノードのEC2の管理をする必要があるからです。 ECSならコンテナノードにFargateを用いることができるため、ECSを採用しました。
ECS内の構成
今回構築したコンテナクラスタの中は以下のようになっています。 コンテナノードはEC2ではなくFargateを採用しました。
AWS Fargateについて
AWS Fargateは2018年7月に東京リージョンにリリースされた新しい起動タイプで、EC2の代わりにコンテナクラスタに配置することができます。Fargateでは、EC2でのときと違って、リソース管理やホストOSのことを考える必要がなくなります。Fargateは標準で各サブネットのAZごとに配置されます。 Fargateは、awsvpcモードを使用が必須になるため、ENIの付け替えが必要になりデプロイ時間が長くなります。
ハマリポイント
1サービスあたりのFargateタスク数、Fargate全体でのPublicIP数が20までと少なく、複数のタスクを立てて入れ替える検証を行う際に簡単に到達してしまうので注意が必要です。
開発・デプロイフロー
CodeBuildによるCI
CodeBuildはソースプロバイダにGitHubを選択した際、WebHookを受け取れるため、 PR発行ごとにdockerイメージをビルドして、そのイメージを使って、テストを行います。 結果はPRに表示されます。
CodePipelineによるデプロイ
masterブランチにマージされたことをトリガーに、デプロイを行います。
ソースプロバイダをGitHubに、ビルドにはCodeBuild、デプロイ先はECSに設定します。
このときハマったのが、CodePipelineがGitHubから取ってくるソースコードはgit clone
でとって来られるわけではなく、zipでダウンロードされることです。これにより、CodePipelineから動かすCodeBuildにおいては、リポジトリ内のシェルスクリプトの権限が変わっていたり、ビルド中にgit
コマンドを使おうとしてもリポジトリとして認識されなかったりします。
AutoScaleの検証
AutoScaleの検証も行いました。AutoScaleの設定項目では、平均CPU使用率、平均メモリ使用量、ALBへのリクエスト数に対して閾値が決められます。 今回は平均CPU使用率50%で発火するように設定し負荷試験を行った結果、AutoScaleイベントの発火からサービスインまで2分かかりました。
デプロイ時間
デプロイ時間の計測
ECSで10個のタスクを10個入れ替え、計測したところ、以下のようになりました。
- 6個のタスクを作成し、入れ替えを行う。このとき古いタスクはすべて落とす(10分)
- 4個のタスクを起動する(2分)
計12分かかりました。 つまり、デプロイしたとき、新規バージョンで不具合が出た場合、 前バージョンへ戻すときも同様にかかります。
これを短縮するために、Blue-Green Deploymentを検討しました。
Blue-Green Deploymentの検討
検討のために、BlueとGreenの環境を用意しDNSで切り替えるようにしました。 実際にBlueからGreenに切り替えを行い、Route53のヘルスチェック(30秒毎)を設定したところ、切り替え後のチェックからすぐにGreenにアクセスされていることが確認できました。
セキュリティスキャン
MicroScannerというツールの検証を行いました。
コンテナ内にセキュリティスキャンをかけてくれるツールで、Dockerfile内にMicroScannerを実行するように記述することでスキャンした結果をJSON形式で返却します。
Dockerfile
# 中略 ADD https://get.aquasec.com/microscanner / RUN chmod +x /microscanner ARG token RUN /microscanner ${token}
$ docker build --build-arg=token=<TOKEN> --no-cache .
診断結果は以下のようなJSON形式で出力されます。 現段階では、MicroScanerをどうCodeBuildに組み込んで結果を可視化するかどうかが課題となっています。
"vulnerability_summary": { "total": 1, "low": 1, "negligible": 120 }
また、MicroScannerの有料プランの検証も行いました。 有料プランでは以下のようなWebの管理画面でセキュリティスキャンの結果を見ることができます。
CloudFormation
この構成の構築を簡単に再現するためにAWS CloudFormationを使いました。 デプロイフローに関してはecs-refarch-continuous-deploymentを参考にしました。
終わりに
今回は、AWS上にコンテナをデプロイする基盤を構築、検証しました。 今後の展望としては、Blue-Green Deploymentの手法をCodePipelineで実現させ、前バージョンへコマンドで一つですぐに戻せるようにできるようになればと思っています。
この記事は、id:guni1192がお送りいたしました。 ありがとうございました!!