AWSで実現するモダンアプリケーション入門
第1章
モダンアプリケーションとは
モダンアプリケーションを実現するテクノロジーとしてサーバーレスとコンテナーがあるが、 これはモダンアプリケーションを実現するためにサーバーレスとコンテナーを「使わなければいけない」という意味ではない。 モダンアプリケーションという名前から「現代式の技術の組み合わせ」のように聞こえてしまいますが、モダンアプリケーションはアプリケーションの設計、構築、管理を継続的に見直し、変化を受け入れ続ける開発戦略のことを指す。
EC2で実現するモダンアプリケーション
たとえば、Amazon Cloud Watchでモニタリングをしつつ、リクエスト数などのメトリクスが閾値を超えた場合はAmazon EC2 AutoScalingでAmazon EC2インスタンスを増やす。
また、EC2 Image Builderでアプリケーションに必要なパッケージを含んだAMI(AmazonMachineImage)を構築し、AWS Systems ManagerPatch ManagerでAmazonEC2インスタンスにパッチを適用することで、日常的な運用業務を自動化できます。
さらに、AWS Codeサービス群でアプリケーションをデプロイし、AWS CloudFormationでAWSサービスを構築することで、デプロイ作業も自動化できます。
第3章
The Twelve-Factor app
2012年ごろにheroku社のエンジニアによって提唱されたアプリケーションを実装するためのベストプラクティス。
どのようなプログラミング言語でも幅広く適用ができる。
beyond The Twelve-Factor app
2016年ごろにPiotal社のエンジニアによって提唱されたベストプラクティス。
15種類から構成されている。クラウドについても考慮されている。
プラクティスの内容
コードベース
コードベースとアプリケーションを1:1の関係になっていること、そしてアプリケーションとデプロイが 1:N
の関係になっていることが重要。
よってアプリケーションの種類ごとにコードベースを作り、コー ドベースから本番環境/ステージング環境/開発環境など、複数の環境に異なるバージョンをデプロイする。
複数のアプリケーションから同じコードベースを参照すると依存度が高くなるため、ライブラリとして切り出す判断が必要になる。
このコードベースを実現するサービスにGitHubなどがある。
そして、1つのアプリケーションで1つのリポジトリを持ち、それぞれの環境にデプロイをしているため、TheTwelveFactorAppの「コードベース」を満たしています。
依存関係管理
アプリケーションで依存関係を厳密に宣言する必要。
依存関係を厳密に宣言する手段の例を挙げると、RubyGemsのGemfileで依存関係を宣言し、Bundlerの bundle exec
コマンドで依存関係を分離します。
また、システムツールの暗黙的な存在も認めない。 具体的な例としては、アプリケーションからOSに組み込まれているcurlコマンドを使ってしまうと、暗黙的に依存してしまいます。そこでRubyのnet/httpやFaraday、Pythonのrequestsなど、専用ライブラリを使います。また、画像処理のためにImageMagickなどに依存している場合は、明示的にImageMagickをインストールします。このように、暗黙的に依存することを避けることが重要です。
設定 機密情報 コード
設定をコードから分離する。
設定とは環境ごとに異なる値のことを指す。
これらの設定をアプリケーションに定数として定義してしまうと、設定とコードを分離できず、TheTwelveFactorAppに違反する。
また、Ruby on Rails
など、アプリケーションフレームワークによっては、環境ごとの設定を設定ファイルという形式で管理するしくみが含まれていることもあります。
このしくみを使った場合、コードの中には直接設定を記述しませんが、同じコードベースの中には保持していることになります。
これは、アプリケーションフレームワークのお作法に沿ってはいるものの、設定とコードを分離するという根本的な解決には至っていない。
Beyond the TwelveFactor Appでは、設定を外部化するというベストプラクティスが追加されている。
クラウド上などのバックエンドサービスに設定を保存し、アプリケーションでは設定をそこから取得することを意味しています。そうすれば、設定自体を一元管理できるだけでなく、バックエンドサービス上のしくみを使って設定の履歴管理をしたり、アクセス制限もできる。
バックエンドサービス
ここで言っているバックエンドサ ービスとは以下のこと
- データベース(MySQL)
- キュー(RabbitMQ)
- 電子メールサービス(Postfix)
- キャッシュ(Redis,Memcached)
- API(TwitterAPI・Google Maps API・アプリケーションAPI)
- AWSサービス(AmazonS3,AmazonRDS)
開発環境はアプリケーションと同じサーバー(ローカル)にMySQLデータベースがインストールされていて、本番環境はAmazonRDSforMySQLを使う構成になっているとする。
開発環境と本番環境で、アプリケーションのコードを変更せずにデータベースの接続先を切り替えることができるのであれば、バックエンドサービスのプラクティスにしたがっていると言える。
APIファースト
Beyond the Twelve FactorAppには、アプリケーションが大きくなるにつれてサービス間の依存度が強くなり、統合が失敗しやすくなると書かれています。
公開されたインターフェースであるAPIを第一に考える思想が「APIファースト」
言い換えると、すべてのアプリケーションをAPIとして、TheTwelveFactorAppのプラクティス「バックエンドサービス」になることを目指します。
Railsでいう APIモード
のこと。
インターフェースというのは OpenAPI
のこと
デザイン・ビルド・リリース 実行
ログ
第4章
データの取得による状況の可視化
サービスの状況を把握することはビジネスの成功において不可欠。
例として
- アプリケーションが期待していた応答時間でサービスを提供しているか
- サービスのアクティブユーザー数はどの程度か
状況を可視化するというプラクティスは以前から広く取り入れられていますが、「イノベーションの促進」や「信頼性の向上」といったモダンアプリケーションのメリットを得るには、従来とは異なる可視化戦略が必要です。サーバーレスやコンテナ、マイクロサービスなど、採用しているテクノロジーやアーキテクチャの構成に応じて、データを収集し分析するための適切なツールを導入します。
可視化しないといけないこと
AmazonCloudFrontやElasticLoadBalancingのAmazonCloudWatchメトリクスから、REDメソッドに相当するデータを取得しています。
また、AmazonEC2やAmazonRDSのAmazonCloudWatchメトリクスから、リソースの状況を可視化するためのデータを取得しています。
そして、AmazonCloudWatchダッシュボードを利用して、これらのメトリクスを確認しています。将来的に、サーバーレスやコンテナーといったAmazonEC2以外のコンピューティング環境や、現在利用していないマネージド型サービスを新たに採用した場合を想定しています。
CloudWatchにメトリクスを集約することで、現在と同じようにAmazonCloudWatchダッシュボードを統一的なビューとして活用できます。
ビジネスデータ
例
- アクティブなユーザー数(キャンペーンLPなどマーケティング観点)
- 新規の会員登録/退会をしたユーザー数(将来の経営計画観点)
- 書籍の販売数(将来の経営計画観点)
- 閲覧数/検索数(キャンペーンLPなどマーケティング観点)
- 滞在時間(キャンペーンLPなどマーケティング観点)
運用データ
- 運用担当者の呼び出し回数
- 設定変更など運用作業の依頼として起票されるチケット数
- チケットが完了するまでの経過時間
- 1日あたりのデプロイ数
- サービスの可用性
システムデータ
アプリケーションやインフラストラクチャーの可視化をする。
アプリケーションの可視化
クライアントからのリクエストに応答するというリクエスト駆動のサービスであれば広く適用できる。
これらのメトリクスは頭文字を取ってREDメソッドと呼ばれることもある。
- リクエスト数(Rate)
- リクエストのエラー数(Errors)
- リクエストの処理時間(Duration)
キューと処理するジョブで構成されるサービスでは、以下のようなデータを取得することでインフラストラクチャやアプリケーションの状況を可視化できます。
これらのメトリクスは頭文字を取ってUSEメソッドと呼ばれることもある。
- タスクの処理件数(Utilization)
- キューイングされているタスクの件数(Saturation)
- エラー件数(Errors)
インフラストラクチャーの 可視化
アプリケーションが実行されているサーバーのCPU利用率・メモリ利用率・ネットワークI/Oといったメトリクスや、AmazonS3といったマネージド型サービスの提供するメトリクスが考えられます。
これらのメトリクスは、積極的に追跡したりアラームを設定する対象ではありませんが、前述のREDメソッドやUSEメソッドで何かしらの問題を検知した場合に調査するための重要なデータとなります。また、リソースの状況を可視化することで「そのリソースがどれくらい使われているのか」という専有率を把握できるため、キャパシティプランニングにも活用できます。
アプリケーションとして大事なこと
ビジネスデータをログへ出力するようにアプリケーションを実装し、それらのログをストリーミングで集約して保存するように設計しておく。
こうすることで、ビジネスデータの分析や可視化については、後から柔軟にツールを選定できる。
※マイクロサービスであれば、吐き出したlogはすべてひとつのS3に吐くなど。
可視化するツール
AWSであればAmazon QuickSight BIツールがある。
運用データのポイント
運用担当者の呼び出し回数を抑えるために、開発チームに対してデプロイの敷居を高くするさまざまなプロセスを設定するかもしれません。こうなっては、モダンアプリケーションのメリットであるイノベーションの向上につなげることはできなくなる。
解決方法としてはDevOpsモデルを導入すること。
DevOps
開発チームと運用チームの間にある壁を取り除き、一体化したチームとして協調性を持って作業を進めます。 たとえば、開発のスピードを犠牲にすることなく「運用担当者の呼び出し回数」を抑えるために、それぞれのチームが協調した取り組みを実施できます。 開発観点では小さな変更を頻繁にデプロイすることでデプロイごとのリスクを下げる、運用観点ではCI/CDパイプラインを導入してデプロイを自動化するといったように、開発の生産性を損なうことなく信頼性の高い運用ができます
オブザーバビリティ(可観測性)
システムの内部で何が起きているのかを説明できるシステムの能力を示している。
たとえば、先月の自社システムの可用性や応答時間を教えてほしい、というマネージャーからの質問に回答ができる状態であれば、そのシステムはオブザーバビリティを備えていると言えるでしょう。
システムがオブザーバビリティを獲得するためのデータとして、すでに紹介したメトリクスに、ログとトレースデータを加えた「3本の柱」という考え方がある。
メトリクスは、リクエスト数などの特定の指標について、数値データを時系列で確認できる点は便利ですが、数値データ以外の情報は持つことができません。
数値以外の詳細なデータはログとして保存します。
また、マイクロサービスのような分散システムを実行している場合、サービス間を横断するリクエストの追跡にトレースデータが必要となるでしょう。
このように、メトリクスとログとトレースデータはそれぞれが異なる性質のデータを持っていますが、システムの内部で何が起こっているのかを把握する際に重要なデータとなります
オブザーバビリティとモニタリングの違い
この2つの目的について整理してみましょう。オブザーバビリティの目的は、システムの内部で何が起きているのか、すなわち「問題を把握すること」だといえます。
一方、モニタリングの目的は「問題を発見すること」だといえます。つまり、モニタリングでは予測可能な問題を対象としており、オブザーバビリティでは対象となる問題が予測可能であるとは限らない、という点でこれら2つの目的は異なります。
第5章
サーバーレスやコンテナーテクノロジーによる運用改善
サーバーレステクノロジーを使った「領収書機能」とコンテナテクノロジーを使った「ポイント機能」を紹介し、要件にあったテクノロジーを選択する考え方。
アプリケーションの要件にあったテクノロジーを選択し、モダンアプリケーション化を進めることが重要。
サーバーレスの定義はどこ
AWSが独自に定義したものではない。
サーバーレスの定義としてサーバーレスはコードをホストして実行するためにサーバーを使わなくなること指すのではなく、サーバーのプロビジョニングやスケーリング、キャパシティプランニングといった作業に時間やリソースを費やす必要がなくなるという考えたを指す(CloudNativeComputingFoundation(CNCF))
第6章
CI/CDパイプラインによるデリバリーの自動化
アプリケーションを継続的にデリバリーするためのソフトウェア開発プラクティス。
- 継続的インテグレーション(CI:ContinuousIntegration)
- 継続的デリバリー(CD:ContinuousDelivery)
これら2つを行うことをCI/CDパイプラインという。
CI/CDのパイプラインは開発初期で構築するべき。
継続的インテグレーション(CI:ContinuousIntegration)
小さな変更をメインブランチへ取り組むことに焦点を当てる。
あるいは、フィーチャーフラグの導入などによりメインブランチへの取り込みとリリースのタイミングが分離している場合、開発者が メインブランチへ直接コミットするようなケースも考えられる。
例
成果物としてビルドアーティファクトを作成する必要があります。
今回はコンテナワークロードですので、コンテナイメージを作成し、作成したコンテナイメージをAmazonECRリポジトリに保存します。
CIに必要な要件
継続的インテグレーションでは、定期的に変更点をメインブランチへマージするために自動的なテストやビルドの実行が不可欠です。
そのため、まずはパイプラインの後続処理で利用するソースコードを取得する機能が必要となります。
続いて、アプリケーションのテストを実行するためのCIサーバーが必要です。
最後に、ユニットテストや静的コード解析をパスしたアプリケーションコードに対してビルドを実行し、成果物としてビルドアーティファクトを作成します。これは、コンテナイメージやAWSLambda関数のパッケージの作成が該当します。
継続的デリバリー(CD:ContinuousDelivery)
継続的デリバリーについて説明します。
継続的デリバリーとは、アプリケーションコードの変更をトリガーにして、自動的にテストやビルド、リリースの準備を実施するソフトウェア開発のプラクティスです
CDに必要な要件
アプリケーションのデプロイプロセスを自動化する。
デプロイの対象となるアプリケーションは、継続的インテグレーションのステップの中でビルドアーティファクトが作成されているため、継続的デリバリーのステップではこれを利用してデプロイを進めていきます。
アプリケーションのデプロイでは、稼働中のサービスに影響を与えることなく、アプリケーションを新しいビルドアーティファクトに置き換えることが重要。
ローリングデプロイやBlue/Greenデプロイを実行する機能が必要
2つを合わせると
開発環境や本番環境などのアプリケーション実行環境に、テストを通過した成果物がビルドされてデプロイされます
以下のようにCI/CDパイプラインでは、いくつかの処理をまとめステージとして管理するのがいい(後から拡張しやすくなる)
AWSでのCI/CDパイプライン
CloudFormationの比較的簡単な例を紹介しましたが、とくにAWSLambda関数や関連するイベント設定など、サーバーレスサービスを組み合わせる場合、AWSCloudFormationテンプレートの記述が長くなってしまう可能性がある。
その場合はAWS SAMを使用する場合もある。
またAWS SAMにはAWS CloudFormationのビルドやデプロイを一貫した操作で行うためのコマンドとしてAWS SAM CLIが用意されています。たとえば、sam buildコマンドを実行すると、アプリケーションの依存関係を解決しアーティファクトをZIPファイルにまとめます。
そしてsam deployコマンドを実行すると、AWSCloudFormationのしくみを使ってデプロイします。
第7章
要件にあったデータベースの選択