【AWS】マイクロサービスを支える２つのサービス(AWS App Mesh編)

## はじめに
※本記事は以下記事の続きになります。
[【AWS】マイクロサービスを支える２つのサービス(AWS Cloud Map編)](https://qiita.com/kaburagi_/items/c97c16a0ad842436667b)

システム設計のスタンダートとも言えるマイクロサービス。
AWSでマイクロサービスといえば「Fargate」「Lambda」などが最初に思いつくかと思います。
本記事ではマイクロサービスアーキテクチャ構成に当たって、
重要な役割を持ち、縁の下ので支えてくれている「AWS Cloud Map」「AWS App Mesh」についてまとめた記事になります。
※本記事では「AWS App Mesh」について記載をしております。

## 「App Mesh」が解決できるマイクロサービスの課題

### 【課題①：サービス間通信の信頼性の確保-Reliability】
ネットワーク状況/対向サービスの不具合(クラッシュなど)による失敗を想定して防御的実装が必要

#### サービス間通信の信頼性を高めるために主に必要な機能一覧
1. 一時的な呼び出し失敗
　→リトライ機能の実装
2. 継続した呼び出しの失敗
　→サーキットブレーカー(何度呼び出しても失敗する場合、対向システム復旧まで呼び出し停止)
3. 呼び出し先サービスのパフォーマンス低下
　→タイムアウト(ユーザへの想定レスポンスタイムを守るため、一定のレスポンスタイムを超える場合はエラーとする)
4. 呼び出し元システムの不具合
　→スロットリング(呼び出し元の実装誤りによって無限にリクエストを受ける可能性があるため、一定数呼び出しが連続した場合エラーとする)
5. 暗号化通信の実装
　→プロトコル制御、TLS暗号化、ACM(AWS Certificate Manager)と統合

### 【課題②：サービス間通信の可観測性-Observebility】
各チームにおいて「ログ/メトリクス/トレース情報」の取得を行っているが、出力形式などが不揃いだと一貫した調査が行えない。技術レベルの違い、追加設定などを考慮すると個々の設定は困難。つまり、各アプリ個別実装の場合は、全体の観測が困難となってしまう。

上記課題①②の解決手段が「サービスメッシュ」こと**App Mesh**

## Appmesh
### 一言でいうと
マイクロサービス間通信の信頼性担保やシステム全体を観測できるサービス
　⇒各アプリにプロキシを付与することで、各種設定/信頼性の担保をオフロードするサービス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/39c74279-6238-9e22-f70a-a280a848bc68.png)

### もう少し詳しく
タイムアウト/スロットリングなどアプリケーションレベルの通信をインフラ側で制御できるようにするサービス。このサービスが誕生した背景にはもちろん「マイクロサービス」の課題がある。個々のアプリケーション単位でチームに適した開発手法を採用するため、信頼性/可観測性を確保するための統一的な仕組みの導入が困難となった。
そこで「**通信処理を別のプロセスに切り離す**」というアイディアの元生まれたのがApp Meshとなる
ただ、App Mesh自体はEnvoyプロキシ(機能のオフロード先プロキシ)を管理するコントロールプレーンを提供するサービスメッシュなので、
App Mesh自体はプロキシとしての役割を持たない。
![](https://storage.googleapis.com/zenn-user-upload/efc342106a79-20221117.png)


#### そもそも統一の仕組みがないとどうなるの？
- サービス信頼性の低下に繋がる
	- Aサービスでは存在している仕組みがBサービスには存在していないなどシステム全体でみると信頼性の低下が発生する
- 障害発生時調査が難航する
	- ログ調査の際に、Aサービスではココまでログが出ているが、Bサービスではログが見れないなど一貫性のある調査が困難になる。




## Appmeshの機能まとめ
以下機能をアプリケーション側で設定することなく、インフラ側で統一的な設定が可能となります。
つまりアプリケーションレベルの通信設定をネットワークモデルとして定義し、Envoyプロキシの設定として配布できる。
※ネットワークモデル：システム同士の通信機能。今回はEnvoyプロキシという通信機能を使用してシステム間通信を行っている

#### Appmeshの機能
- トラフィックコントロール
	- 負荷分散
	- 重み付け分散
	- ヘルスチェック
	- リトライ
	- タイムアウト
	- サーキットブレーカー
	- スロットリング
- ルーティングコントロール
	- プロトコル制限
	- Pathベース
	- Heeaderベース
	- Cookieベース
	- Hostベース
- 可観測性
	- メトリクス/ログ/トレース情報をAppmesh経由で出力可能
		- 設定や形式の統一が安易
	- アクセスログについてもenvoy側で取得し、統一フォーマットでCloudwatchLogsに連携することが可能
		- awslogsログドライバー利用前提


## Appmeshの構成要素

### Envoyプロキシ
- プロキシ：アプリケーション間の通信制御を行うプロセス
- プロキシ界隈のデファクトスタンダート(OSS)
- サービスのサイドカーとしてサービスの通信を制御し、信頼性担保の機能を持たせることが可能
- yamlファイルで各種設定を行う

### コントロールプレーン
- サービスメッシュ全体の構造定義
	- メッシュを構成するプロキシに対し動的に設定を配信することで、アプリ側のデプロイサイクルを阻害せずにプロキシ側のみデプロイすることが可能
![](https://storage.googleapis.com/zenn-user-upload/25db180dfe1f-20221118.png)

## Appmesh通信経路/用語
![](https://storage.googleapis.com/zenn-user-upload/ec6fa9aeef89-20221117.png)
- Mesh
	- VPCのような論理的な境界
	- Meshの中でVirtual NodeやVirtual Serviceを用いてNWモデルを設定する
- Virtual Node
	- 実際のターゲットアプリケーションへの論理的ポインタ
	- Envoyの実行パラメータにVirtual Node名を設定することで、Node情報と関連付けが行われる。
- Virtual Service
	- アプリケーション通信先
	- リクエストはVirtual NodeもしくはVirtual Routerにルーティングされターゲットアプリケーションへ到達する
	- Virtual Serviceを使用することで、Virtual Serviceからのリクエストを集約できる
- Virtual Router
	- ルーティング設定
	- リクエストをルーティングするためのLB(ロードバランサ)


### 実際にやってみた
■作成構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/b36dc6c6-3195-2df4-d095-bf059f194096.png)
※前提としてECSの構築は完了していることとします。

■作成順序
1. Meshを作成
2. Virtual Routerを作成
3. Virtual Serviceを作成
4. Virtual Nodeを作成
　※Virtual Nodeで主にタイムアウト等を設定
5. ルーティング設定
6. ECSタスク定義用IAMロールを作成
7. ECSタスク定義を作成

#### 1.Meshを作成
##### 1-1 コンソールよりMeshを作成
「AWSコンソールよりApp Mesh」-「メッシュ」-「メッシュを作成」
![2022-11-29_17h47_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/66358e48-b9a2-7aab-da74-b828e52c03f5.png)

#### 2.Virtual Routerを作成
![68747470733a2f2f73746f726167652e676f6f676c65617069732e636f6d2f7a656e6e2d757365722d75706c6f61642f6563366661396165656638392d32303232313131372e706e67 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/96e1531a-5c8c-47d8-065d-c81c7e3307ff.png)

##### 2-1 コンソールよりVirtual Routerを作成
「[1.Meshを作成]にて作成したメッシュを選択」-「仮想ルーター」-「仮想ルータを作成」
　・受信用プロトコルとポートとして「http:8000」を設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/03752e22-54c9-93d0-09f2-f85853357a7b.png)

#### 3.Virtual Serviceを作成
![68747470733a2f2f73746f726167652e676f6f676c65617069732e636f6d2f7a656e6e2d757365722d75706c6f61642f6563366661396165656638392d32303232313131372e706e67 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/7f629004-d42e-6906-6c3e-ece248be2a54.png)

##### 3-1 コンソールよりVirtual Serviceを作成
「[1.Meshを作成]にて作成したメッシュを選択」-「仮想サービス」-「仮想サービスを作成」
　・仮想ルータの項目に[2.Virtual Routerを作成]にて作成した仮想ルータを設定
![2022-11-29_18h24_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/b308d8a6-613b-9fa8-f98b-d1c9ea81e22f.png)

#### 4. Virtual Nodeを作成
Virtual Nodeは送信元/送信先の2つのコンテナ分必要になる
![68747470733a2f2f73746f726167652e676f6f676c65617069732e636f6d2f7a656e6e2d757365722d75706c6f61642f6563366661396165656638392d32303232313131372e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/6bec3daa-a063-dc9f-4a71-ad0e6b3420b1.png)

##### 4-1 送信元であるfront側のVirtual Nodeを作成
「[1.Meshを作成]にて作成したメッシュを選択」-「仮想ノード」-「仮想ノードを作成」
　・名前空間の項目に[AWS App Mesh編]にて作成したCloud Mapの情報を入力
　　[【AWS】マイクロサービスを支える２つのサービス(AWS Cloud Map編)](https://qiita.com/kaburagi_/items/c97c16a0ad842436667b)
　・httpアクセスログ出力設定の項目に「/dev/stdout」と設定
　　※この設定はEnvoyコンテナに対するアクセスログの有効化とEnvoyコンテナ内の出力先設定
　・リスナー設定の項目に各種設定したい機能を設定
![2022-11-29_18h37_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/6fa341ea-f372-506a-8d29-6a7048e0e78f.png)

##### 4-2 送信先であるbackend側のVirtual Nodeを作成
※仮想サービスが存在しないこと以外はfront側と同一設定
![2022-11-30_22h36_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/c0be0c35-742c-e491-1161-cdab38d2d5b7.png)

#### 5. ルーティング設定
##### 5-1 Virtual Routerのルートを作成
「作成した仮想ルーターを選択」-「ルート」-「ルートを作成」
 ・ターゲットの設定にてバックエンド側のノードを選択
![2022-12-01_22h46_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/7c949516-7be2-9c2b-3e1a-167cb6a6b619.png)

#### 6. ECSタスク定義用IAMロールを作成
以下ポリシーを付与したロールを作成
　・AmazonECSTaskExecutionRolePolicy
　・CloudWatchFullAccess
　・AmazonSSMFullAccess
　・AWSAppMeshEnvoyAccess
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/1c1526c6-dbb1-9993-5017-3fe9176b56b5.png)


#### 7. ECSタスク定義作成
※前提としてECSが動作するVPCにEnvoyコンテナ取得用のAppmesh用VPCエンドポイント(com.amazonaws.ap-northeast-1.appmesh-envoy-management)を構築しておくこと。

##### 7-1 送信元であるfront側のECSタスク定義を作成
　・サービス統合の項目にて、前工程で作成したメッシュ情報を入力する
　　※前提として、ここで設定しているアプリケーションコンテナ名はコンテナ定義の項目にて設定済みとする
　・コンテナ定義の「Envoy」とプロキシ設定の項目はサービス統合の項目にて「適用」ボタンを押下することで、設定値が自動入力される。
　　※[プロキシ設定項目の詳細](https://docs.aws.amazon.com/app-mesh/latest/userguide/getting-started-ecs.html#update-services)

![2022-12-01_22h59_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/b07c8059-d4e6-c73a-c3a4-4f02ee5c1904.png)

##### 7-2 送信先であるbackend側のECSタスク定義を作成
front側のappコンテナを変更するだけなので割愛

#### 通信確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/8cf39e14-d8ee-c9ad-ba5b-43cde16db49e.png)
front側コンテナからbackend側コンテナに向けてcurlコマンドを実行したところ、
EnvoyコンテナのCloudwatchLogsにログの出力を確認
![2022-12-01_23h02_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764568/a663abcb-126b-94b2-5a2d-dff16b529f09.png)

## 終わりに
今回は「AWS App mesh」について機能説明と実機を用いたデモを行ってみました。
App meshの実装に悩まれている誰かの参考になれば幸いです。