公式サンプルを使ってAWS App Meshの仕様を理解する

記事タイトルとURLをコピーする

こんにちは、島村です。
前回、サービスメッシュと App Mesh の概要紹介ブログを書きました。

blog.serverworks.co.jp

今回は App Mesh を利用した AWS 公式サンプルを使用してApp Meshの機能を確認をしていきたいと思います
公式サンプルはリンク先の GitHub リポジトリにあります。 github.com

App Meshがどんな構成になっているのか、どんな設定必要なのかを理解するため、環境構築以外はあえて手動で作成していきます。
お急ぎの方はサンプルの手順通りCloud Formationで自動的に作成してください。

なお、このサンプルは次の流れを体験することができます。

  1. External ELB Internal ELBを使用したサービス間接続
  2. Cloud Mapを利用したサービス間接続
  3. App Mesh + Cloud Mapを利用したサービス間接続
  4. App Mesh 仮想ルーターを使用したトラフィック制御

結論

本ブログが長くなりそうなので、App Mesh を構成するには何が必要なのか先に記載しておきます。 詳細ではなくどういった構成要素が必要なのかざっくり知りたい方は参考のドキュメントページもご覧ください。

1.IAM Policy

今回はECSで検証を行なっています。 タスクロールに AWSAppMeshEnvoyAccess のAWS マネージドポリシー相当の権限が必要になります。 これがないとEnvoyのサイドカーコンテナが起動しません。

2.App Meshの構成

App Meshを使ってメッシュ内リソースの定義をする必要があります。
仮想サービス、仮想ノード、必要に応じて仮想ルータなども定義する必要があります。
サービスディスカバリにCloudMapを使う場合は Cloud Map の名前空間も作る必要があります。

3.タスク定義の追加

Envoy のサイドカーコンテナ用のタスク定義の追加が必要になります。
ブログ内にタスク定義のサンプルは記載しますのでそちらを参照してください。

Envoy に渡す環境変数には必須のものとパラメータを定義するものがありますが、APPMESH_RESOURCE_ARN だけは必須のパラメータになります。 App Mesh の設定に応じて仮想ノードか仮想ゲートウェイの ARN を入力するようにしましょう。

4. 仮想サービス名を名前解決できるようにする

接続元サービスのタスクから接続先のサービス名へリクエストを送る際に、仮想サービス名で通信を行います。
その際に、仮想サービス名で名前解決ができないとEnvoyにリクエストが送る前にリクエストが失敗します。
Route 53 プライベートホストゾーンや hosts ファイルでもいいので、ダミーレコードを登録しサービス名を登録しておきましょう。

名前解決された後、envoyコンテナにHTTPリクエストがプロキシされ、envoyコンテナの設定に合わせてルーティングされます。
ダミーレコードで返ってきたIPアドレスは使用されないので安心してください。

この挙動は Envoy の仕様によるものですので、Envoyについて後日調べてみたいと思います。

環境構築

環境構築は用意されているリポジトリにあるスクリプトで作成していきます。

注意点!
GitHub リポジトリをクローンしてきましょう。
注意点ですが、スクリプトの中ではDocker イメージをビルドしていますが、使用するイメージはarmではありません。 使用している環境が Arm ベースの CPU を使用しているとイメージのビルドがうまくいかないです。
その場合、EC2 を利用してデプロイできるようにしましょう

手順通りやっていきます。

構成図

最初にデプロイされる環境を構成図に起こしてみました。

環境変数の登録

まずは以下の通り環境変数を登録します。

export AWS_ACCOUNT_ID=AWSアカウントID
export AWS_DEFAULT_REGION=ご利用するリージョン
export ENVOY_IMAGE=public.ecr.aws/appmesh/aws-appmesh-envoy:v1.27.2.0-prod

Envoy で指定するイメージについては以下ドキュメントで確認できます。

docs.aws.amazon.com

デプロイ

環境変数を設定した後以下の通りコマンドを実行しデプロイを行います。

cd /aws-app-mesh-examples/walkthroughs/howto-ecs-basics

./deploy.sh deploy 0-prelude

動作確認

デプロイされたら External ELB の DNS 名 + /color のパスをつけてリクエストを送ってみましょう。

[ec2-user@ip-xxx-xx-xx-xx howto-ecs-basics]$ curl http://appmes-Publi-CzSXhxkGcWYA-xxxxxx.ap-northeast-1.elb.amazonaws.com/color
{"color":"green", "stats": {"green":1}}

レスポンスがあれば成功しています。

Cloud Map を利用したサービス検出

最初にデプロイされた環境ではサービス間通信でELBを介して実施しています。
この環境を Cloud Map を使用する環境へ変更していきます。

構成図

Cloud Map 名前空間とサービスの作成

Cloud Mapコンソールへ移動します。
移動できたら名前空間を作成していきます。

設定するパラメータ

項目 設定値
名前空間名 howto-ecs-basics.pvtdns
インスタンスの検出 API呼び出しとDNSクエリ
VPC 作成したVPC
TTL 15

名前空間を作成したら、サービスを作っていきます。
名前空間の中にサービスが含まれるような関係性ですね。

設定するパラメータ

項目 設定値
サービス名 color
サービス検出 API と DNS
DNS 複数回答値ルーティング

ここまでできたら ECS コンソールへ移動します。

ECSサービスの設定変更

Backend サービス構成を変更していきます。
[appmesh-howto-ecs-basics-ColorECSServicexxxx] のサービスを選択し、[サービスの変更] を選択してください

サービス検出の設定項目を展開します。
パラメータは以下の通り設定していきます

項目 設定値
サービス検出を使用 チェック
既存の名前空間を作成 チェック
名前空間名 howto-ecs-basics.pvtdns
既存のサービスの検出サービスを選択 colorを選択
Amazon ECS タスク状態の伝達を有効にする チェック

余談にはなりますが、ECSのサービス設定を変更する画面でも新規名前空間とサービス名の作成は可能です。
今回はCloudMapの設定にも慣れるためにあえてCloudMapコンソールを利用しました。

タスク定義の修正

現状フロントエンドのタスク定義で設定しているバックエンドの向き先は環境変数で渡されています。
そのため、フロントエンドのタスク定義の中に記載されている値を修正していきます。

ECSコンソールから[タスク定義]を選択し、[新しいリビジョンを作成]を押します。

[COLOR_HOST] の値を編集し、[color.howto-ecs-basics.pvtdns:8080] に置き換えます。

編集後、サービスの設定変更画面からタスクのリビジョンを最新に上げて設定を反映してください。
サービス内のタスクが最新のタスクに置き換えられえます。

Internal ELBの削除

Internal ELBを削除しておきましょう。

動作確認

curlコマンドを実行し確認してみます。

[ec2-user@ip-xxx-xx-xx-xx howto-ecs-basics]$ curl http://appmes-Publi-CzSXhxkGcWYA-xxxxxx.ap-northeast-1.elb.amazonaws.com/color
{"color":"green", "stats": {"green":1}}

応答がありましたね。Internal ELBが存在しなくともバックエンドから応答が返ってきました。

App Mesh を利用したサービス間接続

いよいよApp Mesh を利用したサービス間接続を行なっていきます。

構成図

App Mesh の構成

メッシュの作成

App Mesh を構成していきます。App Mesh コンソールへ移動しましょう。
移動できたら、[メッシュの作成] を選択します。

設定するパラメータは少ないので、添付のスクリーンショットを見ながら構成してください。

Egress フィルターについて

設定項目は少ないのですが、Egress フィルターはどんな設定項目なのか理解しておいた方がいいため記載します。
Egress フィルターはメッシュ内のリソースからアウトバウンド通信の挙動に関する設定項目です。
Egress フィルターには2つの設定項目があります。

設定項目 意味
DROP_ALL メッシュ内のリソース及び、*.amazonaws.comのAPIコールは許可
ALLOW_ALL 任意のエンドポイントへアクセスを許可

ALLOW_ALLの場合には注意点があり、後述の仮想ノードの設定内にあるバックエンドサービスを指定する欄がありますが、そちらにすべての通信先を定義する必要があります。
この設定を行わないとALLOW_ALLを設定したからといって通信が可能になるわけではなさそうです。

仮想ノードの作成

仮想ノードを作成していきます。
フロントエンドとバックエンドどちらも作ります。

まずはバックエンドから作成していきます。
バックエンドはCloudMapを利用してリソースを検出していきます。
空欄を選択すると、既存リソースが選択肢と出てくるかと思うので選択してください。

Cloud Map属性について

キーとバリューを設定します。
この設定を行うとCloud Mapに紐づけられているリソースの中でも属性で指定したタグを持った
リソースのみが Cloud Map のクエリ結果に含まれるような挙動を行うことができます。

例えば、CloudMapに紐づけられているリソースの中で resouce:A ,resouce:Bのようなタグをつけていて、 Bだけにアクセスをしたい場合は属性で resouce:B を選択すればresouce:BタグがついているリソースのみDNSのレコードが返ってくるような 動きになります。


次にデフォルトのセキュリティ設定を行う項目です。 今回は設定しませんが、サービス間通信でデフォルトとなるセキュリティを定義することができます。

設定する仮想ノードが通信を行うバックエンドを指定します。
メッシュの設定でALLOW_ALLとなっている場合には、この設定項目でバックエンドを指定する必要があります。
バックエンドごとに通信のセキュリティ仕様を変更することも可能です。

Envoy プロキシのログ出力に関する設定項目です。
ログの出力パスや、ログの出力形式を設定できます。出力形式はEnvoyのデフォルト形式やテキスト、JSONが選択可能です。

リスナー設定です。 仮想ノードがインバウンドトラフィックを受け付ける必要がある場合は設定を行いましょう。
今回はhttp:8080で受け付ける設定を行います。

ここまでがバックエンドの設定です。
続いてフロントエンドの設定を行います。

スクリーンショットは割愛します。設定項目は次の通りです。

項目 設定値
仮想ノード名 howto-ecs-basics-front-node
サービス検出名 DNS
DNS名 パブリックELBのDNS名
バックエンドサービス color.howto-ecs-basics.mesh.local
HTTPリスナー HTTP:8080

※そのほかはデフォルトで問題ありません。
設定が完了したら仮想サービスの作成に移ります。

仮想サービスの作成

次に仮想サービスの作成に移ります。

項目 設定値
仮想サービス名 color.howto-ecs-basics.mesh.local
プロパイダ 仮想ノード
仮想ノード名 howto-ecs-basics-color-node

仮想サービス名は実際のサービス名と簡単に一致できるように実際に呼び出されるサービス名が推奨となっています。
App Meshの設定は以上で終わりです。

Route 53 プライベートホストゾーンの作成

Route53 で仮想サービス用のプライベートホストゾーンを作成します。

作成できたらレコードを登録します。

タスク定義の修正

envoyのサイドカーコンテナを追加するためにタスク定義を修正していきます。

フロントエンド

{
    "containerDefinitions": [
        {
            "name": "envoy",
            "image": "public.ecr.aws/appmesh/aws-appmesh-envoy:v1.27.2.0-prod",
            "cpu": 0,
            "portMappings": [
                {
                    "containerPort": 15001,
                    "hostPort": 15001,
                    "protocol": "tcp"
                },
                {
                    "containerPort": 15000,
                    "hostPort": 15000,
                    "protocol": "tcp"
                },
                {
                    "containerPort": 9901,
                    "hostPort": 9901,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "ENABLE_ENVOY_DOG_STATSD",
                    "value": "1"
                },
                {
                    "name": "ENABLE_ENVOY_XRAY_TRACING",
                    "value": "1"
                },
                {
                    "name": "ENABLE_ENVOY_STATS_TAGS",
                    "value": "1"
                },
                {
                    "name": "APPMESH_RESOURCE_ARN",
                    "value": "mesh/howto-ecs-basics/virtualNode/howto-ecs-basics-front-node"
                },
                {
                    "name": "ENVOY_LOG_LEVEL",
                    "value": "debug"
                }
            ],
            "mountPoints": [],
            "volumesFrom": [],
            "dependsOn": [
                {
                    "containerName": "xray",
                    "condition": "START"
                }
            ],
            "user": "1337",
            "ulimits": [
                {
                    "name": "nofile",
                    "softLimit": 15000,
                    "hardLimit": 15000
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "front"
                }
            },
            "healthCheck": {
                "command": [
                    "CMD-SHELL",
                    "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
                ],
                "interval": 5,
                "timeout": 10,
                "retries": 10
            }
        },
        {
            "name": "app",
            "image": "893075211920.dkr.ecr.ap-northeast-1.amazonaws.com/howto-ecs-basics/feapp:2ab92e3",
            "cpu": 0,
            "portMappings": [
                {
                    "containerPort": 8080,
                    "hostPort": 8080,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "PORT",
                    "value": "8080"
                },
                {
                    "name": "COLOR_HOST",
                    "value": "color.howto-ecs-basics.mesh.local:8080"
                },
                {
                    "name": "XRAY_APP_NAME",
                    "value": "front"
                }
            ],
            "mountPoints": [],
            "volumesFrom": [],
            "dependsOn": [
                {
                    "containerName": "envoy",
                    "condition": "HEALTHY"
                },
                {
                    "containerName": "xray",
                    "condition": "START"
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "front"
                }
            }
        },
        {
            "name": "xray",
            "image": "public.ecr.aws/xray/aws-xray-daemon",
            "cpu": 0,
            "portMappings": [
                {
                    "containerPort": 2000,
                    "hostPort": 2000,
                    "protocol": "udp"
                }
            ],
            "essential": true,
            "environment": [],
            "mountPoints": [],
            "volumesFrom": [],
            "user": "1337",
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "front"
                }
            }
        }
    ],
    "family": "howto-ecs-basics-front",
    "taskRoleArn": "[タスクロールARNに置き換える]",
    "executionRoleArn": "[タスク実行ロールARNに置き換える]",
    "networkMode": "awsvpc",
    "volumes": [],
    "placementConstraints": [],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "proxyConfiguration": {
        "type": "APPMESH",
        "containerName": "envoy",
        "properties": [
            {
                "name": "ProxyIngressPort",
                "value": "15000"
            },
            {
                "name": "AppPorts",
                "value": "8080"
            },
            {
                "name": "EgressIgnoredIPs",
                "value": "169.254.170.2,169.254.169.254"
            },
            {
                "name": "IgnoredUID",
                "value": "1337"
            },
            {
                "name": "ProxyEgressPort",
                "value": "15001"
            }
        ]
    },
    "tags": []
}

バックエンド

{
    "containerDefinitions": [
        {
            "name": "app",
            "image": "893075211920.dkr.ecr.ap-northeast-1.amazonaws.com/howto-ecs-basics/colorapp:2ab92e3",
            "cpu": 0,
            "portMappings": [
                {
                    "name": "app-8080-tcp",
                    "containerPort": 8080,
                    "hostPort": 8080,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "PORT",
                    "value": "8080"
                },
                {
                    "name": "COLOR",
                    "value": "green"
                },
                {
                    "name": "XRAY_APP_NAME",
                    "value": "color-green"
                }
            ],
            "mountPoints": [],
            "volumesFrom": [],
            "dependsOn": [
                {
                    "containerName": "envoy",
                    "condition": "HEALTHY"
                },
                {
                    "containerName": "xray",
                    "condition": "START"
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "color"
                },
                "secretOptions": []
            }
        },
        {
            "name": "envoy",
            "image": "public.ecr.aws/appmesh/aws-appmesh-envoy:v1.27.2.0-prod",
            "cpu": 0,
            "portMappings": [
                {
                    "name": "envoy-15001-tcp",
                    "containerPort": 15001,
                    "hostPort": 15001,
                    "protocol": "tcp"
                },
                {
                    "name": "envoy-15000-tcp",
                    "containerPort": 15000,
                    "hostPort": 15000,
                    "protocol": "tcp"
                },
                {
                    "name": "envoy-9901-tcp",
                    "containerPort": 9901,
                    "hostPort": 9901,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [
                {
                    "name": "ENABLE_ENVOY_DOG_STATSD",
                    "value": "1"
                },
                {
                    "name": "APPMESH_RESOURCE_ARN",
                    "value": "mesh/howto-ecs-basics/virtualNode/howto-ecs-basics-color-node"
                },
                {
                    "name": "ENABLE_ENVOY_STATS_TAGS",
                    "value": "1"
                },
                {
                    "name": "ENABLE_ENVOY_XRAY_TRACING",
                    "value": "1"
                },
                {
                    "name": "ENVOY_LOG_LEVEL",
                    "value": "debug"
                }
            ],
            "mountPoints": [],
            "volumesFrom": [],
            "dependsOn": [
                {
                    "containerName": "xray",
                    "condition": "START"
                }
            ],
            "user": "1337",
            "ulimits": [
                {
                    "name": "nofile",
                    "softLimit": 15000,
                    "hardLimit": 15000
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "color"
                },
                "secretOptions": []
            },
            "healthCheck": {
                "command": [
                    "CMD-SHELL",
                    "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
                ],
                "interval": 5,
                "timeout": 10,
                "retries": 10
            }
        },
        {
            "name": "xray",
            "image": "public.ecr.aws/xray/aws-xray-daemon",
            "cpu": 0,
            "portMappings": [
                {
                    "containerPort": 2000,
                    "hostPort": 2000,
                    "protocol": "udp"
                }
            ],
            "essential": true,
            "environment": [],
            "mountPoints": [],
            "volumesFrom": [],
            "user": "1337",
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "color"
                },
                "secretOptions": []
            }
        }
    ],
    "family": "howto-ecs-basics-color",
    "taskRoleArn": "[タスクロールARNに置き換える]",
    "executionRoleArn": "[タスク実行ロールARNに置き換える]",
    "networkMode": "awsvpc",

    "volumes": [],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "proxyConfiguration": {
        "type": "APPMESH",
        "containerName": "envoy",
        "properties": [
            {
                "name": "ProxyIngressPort",
                "value": "15000"
            },
            {
                "name": "AppPorts",
                "value": "8080"
            },
            {
                "name": "EgressIgnoredIPs",
                "value": "169.254.170.2,169.254.169.254"
            },
            {
                "name": "IgnoredUID",
                "value": "1337"
            },
            {
                "name": "ProxyEgressPort",
                "value": "15001"
            }
        ]
    },
    "tags": []
}

X-Ray のサイドカーコンテナもあるので、トレースマップが確認できます。

応答が返ってくることが確認できました。

curl http://appmes-Publi-CzSXhxkGcWYA-xxxxxxx.ap-northeast-1.elb.amazonaws.com/color
{"color":"green", "stats": {"green":1}}

App Mesh 仮想ルーターを使用したトラフィック制御

いよいよ最後の検証項目です。
App Mesh の仮想ルーターを使用して、アプリケーションバージョンごとにトラフィック分散を行ってみます。

構成図

Colorアプリバージョン2 用のタスク定義作成

Colorアプリバージョン2用のタスク定義を作成します。
以下、タスク定義です。タスク定義名はなんでも良いです。

{
    "containerDefinitions": [
        {
            "name": "app",
            "image": "893075211920.dkr.ecr.ap-northeast-1.amazonaws.com/howto-ecs-basics/colorapp:2ab92e3",
            "cpu": 0,
            "links": [],
            "portMappings": [
                {
                    "containerPort": 8080,
                    "hostPort": 8080,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "entryPoint": [],
            "command": [],
            "environment": [
                {
                    "name": "PORT",
                    "value": "8080"
                },
                {
                    "name": "COLOR",
                    "value": "blue"
                },
                {
                    "name": "XRAY_APP_NAME",
                    "value": "color-v2"
                }
            ],
            "environmentFiles": [],
            "mountPoints": [],
            "volumesFrom": [],
            "secrets": [],
            "dependsOn": [
                {
                    "containerName": "envoy",
                    "condition": "HEALTHY"
                },
                {
                    "containerName": "xray",
                    "condition": "START"
                }
            ],
            "dnsServers": [],
            "dnsSearchDomains": [],
            "extraHosts": [],
            "dockerSecurityOptions": [],
            "dockerLabels": {},
            "ulimits": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "color"
                },
                "secretOptions": []
            },
            "systemControls": []
        },
        {
            "name": "xray",
            "image": "public.ecr.aws/xray/aws-xray-daemon",
            "cpu": 0,
            "links": [],
            "portMappings": [
                {
                    "containerPort": 2000,
                    "hostPort": 2000,
                    "protocol": "udp"
                }
            ],
            "essential": true,
            "entryPoint": [],
            "command": [],
            "environment": [],
            "environmentFiles": [],
            "mountPoints": [],
            "volumesFrom": [],
            "secrets": [],
            "user": "1337",
            "dnsServers": [],
            "dnsSearchDomains": [],
            "extraHosts": [],
            "dockerSecurityOptions": [],
            "dockerLabels": {},
            "ulimits": [],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "color"
                },
                "secretOptions": []
            },
            "systemControls": []
        },
        {
            "name": "envoy",
            "image": "public.ecr.aws/appmesh/aws-appmesh-envoy:v1.27.2.0-prod",
            "cpu": 0,
            "links": [],
            "portMappings": [
                {
                    "containerPort": 15001,
                    "hostPort": 15001,
                    "protocol": "tcp"
                },
                {
                    "containerPort": 15000,
                    "hostPort": 15000,
                    "protocol": "tcp"
                },
                {
                    "containerPort": 9901,
                    "hostPort": 9901,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "entryPoint": [],
            "command": [],
            "environment": [
                {
                    "name": "ENABLE_ENVOY_DOG_STATSD",
                    "value": "1"
                },
                {
                    "name": "ENABLE_ENVOY_XRAY_TRACING",
                    "value": "1"
                },
                {
                    "name": "ENABLE_ENVOY_STATS_TAGS",
                    "value": "1"
                },
                {
                    "name": "APPMESH_RESOURCE_ARN",
                    "value": "mesh/howto-ecs-basics/virtualNode/howto-ecs-basics-color-v2-node"
                },
                {
                    "name": "ENVOY_LOG_LEVEL",
                    "value": "debug"
                }
            ],
            "environmentFiles": [],
            "mountPoints": [],
            "volumesFrom": [],
            "secrets": [],
            "dependsOn": [
                {
                    "containerName": "xray",
                    "condition": "START"
                }
            ],
            "user": "1337",
            "dnsServers": [],
            "dnsSearchDomains": [],
            "extraHosts": [],
            "dockerSecurityOptions": [],
            "dockerLabels": {},
            "ulimits": [
                {
                    "name": "nofile",
                    "softLimit": 15000,
                    "hardLimit": 15000
                }
            ],
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "howto-ecs-basics-log-group",
                    "awslogs-region": "ap-northeast-1",
                    "awslogs-stream-prefix": "color"
                },
                "secretOptions": []
            },
            "healthCheck": {
                "command": [
                    "CMD-SHELL",
                    "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
                ],
                "interval": 5,
                "timeout": 10,
                "retries": 10
            },
            "systemControls": []
        }
    ],
    "family": "howto-ecs-basics-color-v2",
    "taskRoleArn": "arn:aws:iam::893075211920:role/appmesh-howto-ecs-basics-TaskIamRole-MshyekWmPTT1",
    "executionRoleArn": "arn:aws:iam::893075211920:role/appmesh-howto-ecs-basics-TaskExecutionIamRole-2zjo3T0pueNQ",
    "networkMode": "awsvpc",
    "volumes": [],
    "placementConstraints": [],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512",
    "proxyConfiguration": {
        "type": "APPMESH",
        "containerName": "envoy",
        "properties": [
            {
                "name": "ProxyIngressPort",
                "value": "15000"
            },
            {
                "name": "AppPorts",
                "value": "8080"
            },
            {
                "name": "EgressIgnoredIPs",
                "value": "169.254.170.2,169.254.169.254"
            },
            {
                "name": "IgnoredUID",
                "value": "1337"
            },
            {
                "name": "ProxyEgressPort",
                "value": "15001"
            }
        ]
    },
    "tags": []
}

ECS サービスの作成

バージョン2アプリケーションのサービスを作成していきます。
タスク定義以外は、既存サービスと設定値は変わりません。

App Meshの構成

App Mesh 仮想ノードの作成

続いて、バージョン2アプリケーションの仮想アプリケーションを作成していきます。
既存の仮想ノードと同様の設定を行います。
Cloud Map 属性のキーは一緒なのですが、値は新バージョンのアプリを指定するようにしてください。

App Mesh 仮想ルーターの作成

仮想ルータを作成していきます。
指定するパラメータ自体は少ないです。

App Mesh 仮想ルートの作成

仮想ルータを作成できたら、続いて仮想ルータに紐づける仮想ルートを作成していきます。

プロトコルを[HTTP]で指定します。ルート優先度は空白で問題ありません。
なお、ルート優先度は 0 - 1000 の数字で指定ができますが、数値が小さいほど優先度が高いものとなります。
ターゲットは既存バージョンと新バージョンを50:50の割合でトラフィック転送するように設定します。 重みは0:100 としない限り、重みが配分されますのでトラフィックを一時的に寄せたい場合は0を指定するようにしましょう。

App Mesh 仮想サービスの修正

仮想ノードに向いているため、仮想ルータを指定するように既存の仮想サービスを修正します。

動作確認

curl コマンドを数回実行し、 X-Ray のトレースマップを確認してみましょう。
v2のアプリケーションが表示され、分散されていることが確認できると思います。

最後に

いかがでしたでしょうか。
手動で設定などを行ったので大変だったと思いますが、基本的にはIaCで管理することになると思います。
設定項目が多く理解に時間はかかりますが、その分柔軟に設定ができるのでしっかり理解して使い倒していきたいですね。

参考

Cloud Map 関連

docs.aws.amazon.com

App Mesh 関連

仮想ノード - AWS App Mesh

Envoy 関連

www.envoyproxy.io

島村 輝 (Shimamura Hikaru) 記事一覧はコチラ

最近ECS周りをキャッチアップ中。趣味は車・バイク全般。
一応、AWS12冠です。