119
97

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS コンテナ運用設計に関するアプローチ

Posted at

ECSメインにAWSサービスを利用してコンテナの運用設計を考えてみます。

コンテナの運用設計

ECS 上で稼働するWebアプリケーションを前提に運用の要件を考えてみます。

image.png

コンテナを使用したマイクロサービスの運用は、モノシリックなシステム運用とは少し異なります、以下の項目を運用項目としてピックアップします。

  • 可用性/スケーリング
  • CI/CD
  • ロギング
  • トレース
  • モニタリング

ECS/ECR のアーキテクチャ

まずはECS/ECR のアーキテクチャについて触れます。

Amazon ECSはコンテナの作成、実行、停止といった管理をメインとしたサービスであり、Amazon ECRは Dockerのレジストリサービスとなります。リポジトリにあるイメージをプッシュしたり、イメージの保管等を行います。

全体的なイメージを以下のように理解をしています。

image.png

ECSの機能

まずECSです。

image.png

ECSは複数のエンティティから機能を果たすため、各々どのような役割を担うかを理解する必要があるかと思います。以下は包含関係と関係性を図解として描いています。

image.png

Task definition(タスク定義)

task definitionとは起動するtaskの情報が定義されたもので、
docker-compose.ymlのようなイメージです。

起動するタイプ(EC2 or Farate)をタスク定義から定義し、1つのタスク定義上に複数のコンテナを定義する事が可能です。
task definitionのimageパラメーター上で、後述のECR imageに対してアクセスし、ECR image をそのままTaskとして実行する事も出来ます。

また、後述するServicetask definitionを指定する必要があります。

サンプルとしてtask definitionが保持するデータを表示させてみます。
イメージ情報やコンピューティングリソース、通信プロトコルなどが定義されている事が判ります。

sample1-describe-task-definition.json
{
    "taskDefinition": {
        "taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:xxxxxx:task-definition/php-sample-fargate:4",
        "containerDefinitions": [
            {
                "name": "php-sample-fargate",
                "image": "xxxx.dkr.ecr.ap-northeast-1.amazonaws.com/test:latest",
                "cpu": 256,
                "memoryReservation": 128,
                "portMappings": [
                    {
                        "containerPort": 80,
                        "hostPort": 80,
                        "protocol": "tcp"
                    }
                ],
                "essential": true,
                "environment": [],
                "mountPoints": [],
                "volumesFrom": [],
                "logConfiguration": {
                    "logDriver": "awslogs",
                    "options": {
                        "awslogs-group": "/ecs/php-sample-fargate",
                        "awslogs-region": "ap-northeast-1",
                        "awslogs-stream-prefix": "ecs"
                    }
                }
            }
        ],
        "family": "php-sample-fargate",
        "taskRoleArn": "arn:aws:iam::xxxxxxx:role/ecsTaskExecutionRole",
        "executionRoleArn": "arn:aws:iam::xxxxxxxx:role/ecsTaskExecutionRole",
        "networkMode": "awsvpc",
        "revision": 4,
        "volumes": [],
        "status": "ACTIVE",
        "requiresAttributes": [
            {
                "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
            },
            {
                "name": "ecs.capability.execution-role-awslogs"
            },
            {
                "name": "ecs.capability.execution-role-ecr-pull"
            },
            {
                "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
            },
            {
                "name": "ecs.capability.task-eni"
            }
        ],
        "placementConstraints": [],
        "compatibilities": [
            "EC2",
            "FARGATE"
        ],
        "requiresCompatibilities": [
            "FARGATE"
        ],
        "cpu": "256",
        "memory": "512",
        "registeredAt": "2021-07-16T10:21:54.039000+09:00",
        "registeredBy": "arn:aws:sts::xxxxxxxxxx:assumed-role/xxxxxxx
    }
}

Task definitionJSONにて定義出来ます。
なお、AWS CLI を使用してタスク定義のテンプレートを生成する事が可能で、
空のタスク定義のテンプレートがAWSドキュメントに記載されています。

generate-template.awscli
aws ecs register-task-definition --generate-cli-skeleton

タスク定義テンプレート
以下に示しているのは、空のタスク定義テンプレートです。このテンプレートを使用してタスク定義を作成します。これにより、コンソールの JSON 入力領域に貼り付けるか、ファイルに保存して AWS CLI の --cli-input-json オプションで使用できるようになります。詳細については、「タスク定義パラメータ」を参照してください。

ECS Cluster

クラスター自体は、後述するACTIVEServiceTaskが実行される論理的なグループという理解で良いかと思います。
また、クラスターを作成する際に、VPC/サブネットなどのネットワーク情報を定義します。
サンプルとしてECSクラスターが保持するデータを表示させてみます。

sample2-describe-ecs-cluster.json
{
    "clusters": [
        {
            "clusterArn": "arn:aws:ecs:ap-northeast-1:xxxxxx:cluster/fargate-cluster",
            "clusterName": "fargate-cluster",
            "status": "ACTIVE",
            "registeredContainerInstancesCount": 0,
            "runningTasksCount": 2,
            "pendingTasksCount": 0,
            "activeServicesCount": 2,
            "statistics": [],
            "tags": [],
            "settings": [],
            "capacityProviders": [
                "FARGATE_SPOT",
                "FARGATE"
            ],
            "defaultCapacityProviderStrategy": []
        }
    ],
    "failures": []
}

Service

Service は、Task definitionで指定されたTaskに紐づき、ECSクラスター上でACTIVEとなります。
主幹はロードバランサーAutoScalingをECSクラスター上で機能させる要素です。

また、後述のTaskとは機能が分離しており、ECSを立ち上げる必須機能ではありません。

サンプルとしてServiceが保持するデータを表示させてみます。
ロードバランサーの情報や、スケーリングポリシー、後述のTaskのリビジョンを管理、制御するタスクセット(tasksets)と呼ばれる情報を返しています。
なお、aws ecs create-service --cli-input-json により定義されたJSONファイルからサービスの作成も可能です。

sample3-describe-ecs-service.json
{
    "services": [
        {
            "serviceArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxx:service/fargate-cluster/php-samplefargate",
            "serviceName": "php-samplefargate",
            "clusterArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxx:cluster/fargate-cluster",
            "loadBalancers": [
                {
                    "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxx:targetgroup/tg-fargat-php-samplefargate-2/xxxxxx",
                    "containerName": "test",
                    "containerPort": 80
                }
            ],
            "serviceRegistries": [],
            "status": "ACTIVE",
            "desiredCount": 1,
            "runningCount": 1,
            "pendingCount": 0,
            "launchType": "FARGATE",
            "platformVersion": "1.4.0",
            "taskDefinition": "arn:aws:ecs:ap-northeast-1:xxxxxxxx:task-definition/test-task:1",
            "deploymentConfiguration": {
                "maximumPercent": 200,
                "minimumHealthyPercent": 100
            },
            "taskSets": [
                {
                    "id": "ecs-svc/xxxxxxxxx",
                    "taskSetArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxx:task-set/fargate-cluster/php-samplefargate/ecs-svc/xxxxxxxxx","clusterArn": "arn:aws:ecs:ap-northeast-1:386755752236:cluster/fargate-cluster",
                    "startedBy": "CodeDeploy",
                    "externalId": "xxxxxxxxx",
                    "status": "PRIMARY",
                    "taskDefinition": "arn:aws:ecs:ap-northeast-1:xxxxxxxxx:task-definition/test-task:1",
                    "computedDesiredCount": 1,
                    "pendingCount": 0,
                    "runningCount": 1,
                    "createdAt": "2021-07-16T11:04:41.383000+09:00",
                    "updatedAt": "2022-01-21T08:54:17.942000+09:00",
                    "launchType": "FARGATE",
                    "platformVersion": "1.4.0",
                    "networkConfiguration": {
                        "awsvpcConfiguration": {
                            "subnets": [
                                "subnet-xxxxxxxxx",
                                "subnet-xxxxxxxxx"
                            ],
                            "securityGroups": [
                                "xxxxxxxxx"
                            ],
                            "assignPublicIp": "DISABLED"
                        }
                    },
                    "loadBalancers": [
                        {
                            "targetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxx:targetgroup/tg-fargat-php-xxxxxxxxx",
                            "containerName": "test",
                            "containerPort": 80
                        }
                    ],
                    "serviceRegistries": [],
                    "scale": {
                        "value": 100.0,
                        "unit": "PERCENT"
                    },
                    "stabilityStatus": "STABILIZING",
                    "stabilityStatusAt": "2022-01-21T08:54:17.942000+09:00",
                    "tags": []
                }
            ],
            "deployments": []
...

Task

タスク定義 からECSクラスター上に起動したコンテナの集合体であり、アプリケーションの処理をメインに行います。
また、ECSクラスター上で稼働しているTaskは、起動/停止が可能です。

image.png

ECRの機能

image.png

ECR の主要コンポーネントである レジストリ / リポジトリ / イメージについてです。

Registry

レジストリ内にイメージリポジトリを作成し、イメージを保存します。
レジストリ自体は認証(Dockerクライアントとの認証許可を行う事で、レジストリ内のリポジトリとの間でイメージをプッシュ、プルできるようにする)、レプリケーション(AWSのクロスリージョン、クロスアカウントに対するイメージのレプリケーション)等によるものなので、設定情報という理解で良いかと思います。

Repository

後述のコンテナイメージAmazon ECRリポジトリに保存されます。
また、2020年12月以降、ECRはパブリック領域としての利用が可能となり、コンテナイメージをパブリックに公開する事も、ダウンロードすることが可能になりました。

image

docker imageのようなもので、イメージをリポジトリ内へpush(docker push)して、登録を行います。イメージはURI形式で連携が可能で、ECSのタスク定義として使用出来ます。実態はS3へ配置されます。

稼動システムの全体像

コンテナの運用をするために複数のAWSサービスを使用します。
今回は、一般的なWebアプリケーションを想定し、以下の構成図から運用を考えていきます。

image.png

Monitoring

ECSに対して監視を行う場合、Cloudwatch メトリクスCloudwatch Container Insightsの二種類の機能を使用する状況を把握する事が出来ます。
いずれもメトリクスと呼ばれる指標となるデータポイントを一定期間で集計したもので、対象のメトリクスが閾値を超えた場合、アラームを送信するなどの対策も可能です。

image.png

###Cloudwatch メトリクス

Cloudwatch メトリクスは、ECSのサービス単位で MemoryUtilization / CPUUtilization の2つの指標をモニターします。

メトリクス 説明
MemoryUtilization クラスター、サービス単位で使用されているメモリーの割合(%)
CPUUtilization クラスター、サービスで使用されている CPU の割合(%)

image.png

MemoryUtilization / CPUUtilizationでは、クラスター・サービスいずれもタスクの総数から除算する方式で算出されるため、タスク全てが均衡化された数値としてカウントされるようです。これは、特定のタスクへ負荷をモニタリングする要件にはマッチしない事を意味します。

###Cloudwatch Container Insights

Cloudwatch Container Insightsは、Cloudwatchメトリクスより詳細なメトリクスを取得出来ます。また、メトリクス情報を返すリソースの粒度(クラスター、サービス、タスク)も拡張されるためモニタリング機能としてはCloudwatch Container Insightsの方が情報量に優れています。

Amazon ECS クラスターで Container Insights を有効にし、以下のいずれか、または両方を使用する事で多くのメトリクス情報を返します。

  • クラスターレベル、タスクレベル、およびサービスレベルのメトリクスの収集を開始するには、AWS Management Console または AWS CLI を使用します。
  • CloudWatch エージェントを DaemonSet としてデプロイし、インスタンスでホストされているクラスターで Amazon EC2 インスタンスレベルのメトリクスの収集を開始します。

image.png

image.png

メトリクス 対象 説明
ContainerInstanceCount ClusterName クラスターに登録されている Amazon ECS エージェントを実行している EC2 インスタンス数
CpuUtilized TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースのタスクにより使用されている CPU ユニット数
CpuReserved TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースのタスクにより予約されている CPU ユニット数
DeploymentCount ServiceName、ClusterName ECS サービスでのデプロイの数
DesiredTaskCount ServiceName、ClusterName ECS サービスに必要なタスクの数
MemoryUtilized TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースのタスクにより使用されているメモリ
MemoryReserved TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースのタスクにより予約されているメモリ
NetworkRxBytes TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースにより受信されるバイト/秒 ※ネットワークモードがawsvpc、bridgeが対象 
NetworkTxBytes TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースにより送信されるバイト/秒 ※ネットワークモードがawsvpc、bridgeが対象
PendingTaskCount ServiceName、ClusterName PENDING 状態にあるタスクの数
RunningTaskCount ServiceName、ClusterName RUNNING 状態にあるタスクの数
ServiceCount ClusterName クラスター内のサービスの数
StorageReadBytes TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースのストレージから読み込まれたバイト数
StorageWriteBytes TaskDefinitionFamily、ClusterName、ServiceName 指定した対象のリソースのストレージヘ書き込まれたバイト数
TaskCount ClusterName クラスターで実行されているタスクの数
TaskSetCount ServiceName、ClusterName サービス内のタスクセットの数

CloudWatch エージェントからEC2インスタンスレベルのメトリクスの収集

メトリクス 対象 説明
instance_cpu_limit ClusterName クラスター内の単一の EC2 インスタンスに割り当てることができる CPU ユニットの最大数
instance_cpu_reserved_capacity ClusterName、InstanceId、ContainerInstanceId クラスター内の単一の EC2 インスタンスで現在予約されている CPU ユニットの最大数
instance_cpu_usage_total ClusterName クラスター内の単一 EC2 インスタンスで使用されている CPU ユニットの数
instance_cpu_utilization ClusterName、InstanceId、ContainerInstanceId クラスター内の単一の EC2 インスタンスで使用されている CPU ユニットの合計割合
instance_filesystem_utilization ClusterName、InstanceId、ContainerInstanceId クラスター内の単一の EC2 インスタンスで使用されているファイルシステム容量の合計割合
instance_memory_limit ClusterName このクラスター内の単一の EC2 インスタンスに割り当てることができるメモリの最大量(バイト単位)
instance_memory_reserved_capacity ClusterName、InstanceId、ContainerInstanceId クラスター内の単一の EC2 インスタンスで現在予約されているメモリの割合
instance_memory_utilization ClusterName、InstanceId、ContainerInstanceId クラスター内の単一の EC2 インスタンスで使用されているメモリの合計割合
instance_memory_working_set ClusterName クラスター内の単一の EC2 インスタンスで使用されているメモリの量(バイト単位)
instance_network_total_bytes ClusterName クラスター内の単一の EC2 インスタンスでネットワーク上で送受信された 1 秒あたりの合計バイト数
instance_number_of_running_tasks ClusterName クラスター内の単一の EC2 インスタンスで実行中のタスクの数

CWエージェントは、ECR経由でのエージェントが入ったイメージの導入も可能です。

###ネットワークモードについて

メトリクス NetworkRxBytes/NetworkTxBytes で出てきたネットワークモードについて少し触れます。
ECSのネットワークモードとは、タスクのネットワーク動作を定義するものです。
ネットワークモードは、主に以下3点となりますが、Fargateでのタスクネットワーキングはawsvpcのみとなります。

  • awsvpc

タスクには、独自の Elastic Network Interface (ENI) とプライマリプライベート IPv4 アドレスが割り当てられます。これにより、タスクに Amazon EC2 インスタンスと同じネットワークプロパティが与えられます。

image.png

  • bridge

タスクは、タスクをホストする各 Amazon EC2 インスタンス内で実行される Docker の組み込み仮想ネットワークを利用します。

image.png

  • host

タスクは Docker の組み込み仮想ネットワークをバイパスし、タスクをホストしている Amazon EC2 インスタンスの ENI にコンテナポートを直接マッピングします。その結果、ポートマッピングが使用されている場合、1 つの Amazon EC2 インスタンスで同じタスクのインスタンスを複数実行することはできません。

image.png

可用性とScaling

ECSの可用性とScalingはServiceの機能がカバーします。
それぞれの観点から見ていきます。

可用性

ECSのService にはサービススケジューラ(schedulingStrategy)というパラメーターが存在します。

schedulingStrategy では、以下の2つを指定出来ます。

  • REPLICA

クラスター全体で必要な数のタスク(DesiredCount)を配置して維持します。デフォルトでは、サービススケジューラによってタスクはアベイラビリティーゾーン間で分散する構成を自動で行います。

image.png

  • DAEMON

クラスター内のアクティブなコンテナインスタンスごとに、1 つのタスクのみをデプロイします。サービススケジューラは、実行中のタスクのタスク配置制約(後述の参考URL)を評価し、配置制約を満たさないタスクを停止します。
つまりインスタンス数とタスク数が 1対1で実行するように維持します。
DAEMONタイプの設定は、Fargate 起動タイプでは利⽤が出来ません。

image.png

Scaling

ECS上で機能するスケーリングについて考えていきます。
スケーリングには、スケールアップ(タスクサイズと呼ばれるtaskのCPU/memoryの増強)とスケールアウト/インが考えられますが、今回はTaskの停止を伴わないスケールアウト/インについて触れていきます。

###AutoScaling
ECSでは、ServiceへAuto Scalingを設定する事が出来ます。(Service Auto Scaling)

これはサービスの必要タスク数(DesiredCount)を⾃動的に増減させるというものです。

image.png

  • タスクの必要数
    Service Auto Scaling で使用するタスクの数

  • タスクの最小数
    Service Auto Scaling で使用するタスクの下限数

  • タスクの最大数
    Service Auto Scaling で使用するタスクの上限数

なお、タスクの必要数は、最小タスク数最大タスク数の範囲内である必要があります。

Service Auto Scalingでは、オプション機能により、ユーザー定義の条件に従ってスケーラブルする仕組みとなっており、ECSの CloudWatch メトリクスを使用して、ピーク時に対処するためにサービスをスケールアウトし (実行するタスクを増やし)、使用率の低い期間にコストを削減するためにサービスをスケールインする (実行するタスクを減らす) ことができます。

以下の2タイプが Service Auto Scalingとしてサポートしています。

  • ステップスケーリング

アラーム違反の大きさに応じて異なる一連のスケーリング調整値に基づいてリソースをスケールします。
以下2つのメトリクスから選択し、任意のパーセンテージに応じたスケールアウト/インが動作する仕組みです。

  • ECSServiceAverageCPUUtilization
    サービスの平均 CPU 使用率

  • ECSServiceAveregemorutilization
    サービスのメモリ平均使用率

例として、メトリクス ECSServiceAverageCPUUtilizationを使用し、30 - 70%を通常時のtaskカウントとし、30%未満でtask 1つへスケールイン、70 - 89% でtaskを3つへスケールアウト、90%以上はtaskを4つへスケールアウトなどという設定が可能です。

image.png

image.png

また、クールダウンと呼ばれるスケールアウト/インアクティビティが完了してから別のアクティビティが開始されるまでの時間を指定する事が可能です。
なお、スケールインのクールダウンの場合、クールダウン期間中に別のアラームによってスケールアウトがトリガーされると、Service Auto Scaling によって即座にスケールアウトされます。
スケーリングイベントが発生している最中に、別のスケーリングイベント(80%から更に90%以上になった場合)が発生し得る場合、クールダウン時間を減らす事で突如発生するスパイクにも対応が可能となります。

  • ターゲット追跡スケーリング

特定の CloudWatch メトリクスのターゲット値に基づいてリソースをスケールします。
ステップスケーリング同様に以下3つのメトリクスを選択し、ターゲット値を指定します。

  • ECSServiceAverageCPUUtilization
    サービスの平均 CPU 使用率

  • ECSServiceAveregemorutilization
    サービスのメモリ平均使用率

  • ALBRequestCountPerTarget
    Application Load Balancer ターゲットグループ内のターゲットごとに完了したリクエスト数

ターゲット追跡スケーリング では、選択したメトリクスのターゲット値を標準としたアラームの自動生成が行われます。

例えばECSServiceAverageCPUUtilizationターゲット値を60%とした場合、スケールアウト/インの閾値(%)が、自動で作成され、60%を保とうとする仕組みです。

image.png

image.png

サービス可用性の影響を軽減させるため、スケールインポリシーは長期間にわたって実行されるようです。(X分間のXデータポイントのX値がスケールアウトポリシーの評価対象より長く設定される)

Capacity Provider

ECSクラスターでは、Capacity Providerと、Capacity Provider strategyと呼ばれる実行されたタスクをスケーリングする際に、リソースを指定する機能が備わっています。
AutoScaling の戦略に合わせて、Capacity Providerを使用して、コストを削減する事も可能です。

Capacity Provider

ECSクラスターに関連付けられ、後述の Capacity Provider strategyに使用されます。
タスクが実行されるインフラストラクチャがFargateであれば FargateあるいはFargate spot を選択します。EC2であれば既存の Auto Scaling group をラップする形で使用します。

起動タイプ キャパシティプロバイダー
EC2 Auto Scaling Group
Fargate FARGATE, FARGATE SPOT

ECS on EC2におけるCapacity Providerは、指定したAutoScaling Groupをラップします。起動タイプがEC2に特化した、Capacity Providerのパラメーターは主に2つです。

  • Managed Scaling
    有効な場合、Auto Scalingのスケーリングプランを使用して Auto Scaling Groupのスケールアウト/インのアクションを管理します。無効になっている場合、Auto Scaling Groupを自分で管理します。

  • Target Capacity
    Managed Scalingが有効になっている場合に指定可能で、1~100%をターゲット値として指定する事で、先述したターゲット追跡スケーリングポリシーを使用する事が出来ます。

一方、Fargateの場合、FARGATE SPOTが存在します。
FARGATE SPOTは通常のFARGATEよりもコストが安く、通常の FARGATEに比較して最大70%割引されます。但し、Spot の在庫が少なくなってくるとタスクの停止されることがありますので、ある程度仕組み化が必要なようです。

###Capacity Provider strategy

Capacity Provider strategyを指定する事でCapacity Provider が有効となります。Capacity Provider strategyは、2つのパラメーターを指定する事で起動する割合を指定する事が出来ます。これらに FARGATEと FARGATE SPOT を指定する事で有効となります。

パラメーター 説明
Base 最小起動数
Weight 比率

例として、FARGATEおよびFARGATE SPOT を使用するCapacity Providerを指定します。
最低タスク数を2とした場合、以下のような割合で定義すると、Scaleoutしたタスクは、FARGATE SPOTにて起動します。

image.png

CapacityProvider/Service Auto Scaling FARGATE   FARGATE SPOT
Base 2 -
Weight 1 1
Service Auto Scaling 2 (Scaleout policy on)

CI/CD

コンテナを使用するシステムの開発、運用工程では、再現性のあるコンテナの継続的にデプロイをする、あるいはテスト・ビルド・デプロイの自動化をするためなどの目的により、CI/CDの考え方を用いた事例が多いかと思います。

AWSでは、Codeサービスと呼ばれるCI/CDパイプラインを構築する事で、CI/CDをAWS内で完結させることが出来ます。

image.png

今回はECSを使用したシステムのため、ECSへ特記した事項として2点あります。

1. CodeBuildでビルドしたイメージはbuildspec.ymlで定義した情報からECRへイメージをpushが出来ます。(ECRのサービスロールからCodeBuildからのアクセスを許可する必要があります)

2. ECR に格納されているイメージへの変更を検出し、CodeDeployを使用して、ECS クラスターとロードバランサーにルーティングしてデプロイする事が出来ます。

これらを踏まえて、運用観点からどのような設計を行うかを考えていきます。

###パイプライン設計とイメージのメンテナンス
CI/CD パイプラインからイメージの更新がある場合、ECRへイメージを自動プッシュする流れとなります。プロダクションを意識したCI/CD パイプラインでは、本番・検証・開発環境が共存するサービス、分離すべきサービスが混雑する可能性が高いため、環境単位、タスク単位などの細かなパイプライン設計が事前に必要となってくると思います。

その一つとして、ECRリポジトリをどのように分けるなども考慮が必要です。

image.png

ECRのリポジトリにプッシュされたイメージの実態はS3へ保存されますが、このリポジトリに対して、ライフサイクルポリシーを設定する事が可能です。
ライフサイクルはルールに沿って解釈され、イメージのタグに基づいたポリシーを設定する事も可能です。開発規模が大きければ大きいほど、イメージの更新頻度は上がりますので、ライフサイクルも同時に踏まえた上で全体のリポジトリの設計を行い、不要なファイルをメンテナンスする仕組みを設けた方がよさそうです。

image.png

sample4-template-ecr-lifecycle-rule.json
{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Expire images older than 10 days",
            "selection": {
                "tagStatus": "untagged",
                "countType": "sinceImagePushed",
                "countUnit": "days",
                "countNumber": 10
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}

image.png

sample5-template-ecr-lifecycle-rule.json
{ 
"rules": [
     { 
"rulePriority": 1, 
"description": "prod Expire images older than 100 days",
"selection": { 
              "tagStatus": "tagged", 
              "tagPrefixList": ["prod"],
              "countType": "sinceImagePushed",   
              "countUnit": "days", 
              "countNumber": 100
             },
"action": { "type": "expire" } 
             },
{ "rulePriority": 2, 
"description": "stageanddev Expire images older than 10 days", 
"selection": { 
                       "tagStatus": "tagged", 
                       "tagPrefixList": ["stage","dev"],
                       "countType": "sinceImagePushed",   
                        "countUnit": "days", 
                        "countNumber": 10
                     }, 
"action": { "type": "expire" } 
                    }
          ]
 }

###承認プロセスの利用

CodePipeline には承認プロセスを追加する機能が存在します。

CI/CD パイプライン経由でプロダクション環境を新しいリジョンで適用する際に、承認プロセスを設けてリリース可否を判断させる仕組みを設ける事で、開発者/運用者と承認者の間でリリースの影響下をお互いに共有する事ができ、予期せぬアクシデント未然に防ぐ、あるいは自動化に意思決定の判断を設ける、ガバナンスの強化といった様々な観点を保護します。

image.png

Code Pipeline のGUIとApproval アクションを追加する際の設定項目です。

image.png

image.png

設定項目 説明
アクション名 承認アクションの任意の名前
アクションプロバイダー 承認プロセスでは手動承認を選択
SNS トピックの ARN 承認アクションの通知を送るために使用するトピック
レビュー用 URL レビュー担当者に提供する URL
コメント メールやコンソールでレビュアーに向けて表示出来るコメント内容
変数の名前空間 パイプラインアクションで使用できる変数

AWS CI/CDの各サービスの概要はこちらに少しまとめています。

Logging

コンテナのログ出力は、ドライバーにより異なります。

  • Fargate 起動タイプを使用するタスクの場合、サポートされるログドライバーは awslogssplunkawsfirelens です。

  • EC2 起動タイプを使用するタスクの場合、サポートされるログドライバーは awslogsfluentdgelfjson-filejournaldlogentriessyslogsplunkawsfirelens です。

今回は AWSに標準で使用される awslogsawsfirelensについて記載していきます。

###Cloudwatch Logs によるログ運用

awslogsは、コンテナのログをCloudwatch Logsへ転送します。
Cloudwatch Logs に転送されたログをエラーハンドリングする事も、ログストレージとして使用する事も可能です。

image.png

使用方法は、Task Definition のコンテナ定義に定義された logConfiguration パラメーターから logDriver:awslogs を指定し、有効化します。タスク定義から作成された各コンテナのログはCloudWatch Logs へ転送されます。

sample6-task-Definition.json

{
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "awslogs-wordpress",
                    "awslogs-region": "us-west-2",
                    "awslogs-stream-prefix": "awslogs-example"
                }
            },
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "awslogs-mysql",
                    "awslogs-region": "us-west-2",
                    "awslogs-stream-prefix": "awslogs-example"
                }
            }
        }
    ],
    "family": "awslogs-example"
}

Cloudwatch Container Insightsを有効化した場合にも CloudWatch Logsロググループが生成され、転送を行います。サンプルを以下に表示します。

sample7-Cloudwatch-Container-Insights.json
{
    "Version": "0",
    "Type": "Task",
    "TaskId": "xxxxxxxxxxxx",
    "TaskDefinitionFamily": "xxxxxx",
    "TaskDefinitionRevision": "4",
    "ClusterName": "fargate-cluster",
    "AccountID": "xxxxxxxx",
    "Region": "ap-northeast-1",
    "AvailabilityZone": "ap-northeast-1d",
    "KnownStatus": "RUNNING",
    "LaunchType": "FARGATE",
    "PullStartedAt": 1643191009843,
    "PullStoppedAt": 1643191018055,
    "CreatedAt": 1643190996073,
    "StartedAt": 1643191019944,
    "Timestamp": 1643659440000,
    "CpuUtilized": 0.032220646540323895,
    "CpuReserved": 256,
    "MemoryUtilized": 15,
    "MemoryReserved": 512,
    "StorageReadBytes": 0,
    "StorageWriteBytes": 0,
    "NetworkRxBytes": 0,
    "NetworkRxDropped": 0,
    "NetworkRxErrors": 0,
    "NetworkRxPackets": 129716,
    "NetworkTxBytes": 4,
    "NetworkTxDropped": 0,
    "NetworkTxErrors": 0,
    "NetworkTxPackets": 30343,
    "EphemeralStorageReserved": 21.47,
    "CloudWatchMetrics": [
        {
            "Namespace": "ECS/ContainerInsights",
            "Metrics": [
                {
                    "Name": "CpuUtilized",
                    "Unit": "None"
                },
                {
                    "Name": "CpuReserved",
                    "Unit": "None"
                },
                {
                    "Name": "MemoryUtilized",
                    "Unit": "Megabytes"
                },
                {
                    "Name": "MemoryReserved",
                    "Unit": "Megabytes"
                },
                {
                    "Name": "StorageReadBytes",
                    "Unit": "Bytes/Second"
                },
                {
                    "Name": "StorageWriteBytes",
                    "Unit": "Bytes/Second"
                },
                {
                    "Name": "NetworkRxBytes",
                    "Unit": "Bytes/Second"
                },
                {
                    "Name": "NetworkTxBytes",
                    "Unit": "Bytes/Second"
                },
                {
                    "Name": "EphemeralStorageReserved",
                    "Unit": "Gigabytes"
                }
            ],
            "Dimensions": [
                [
                    "ClusterName"
                ],
                [
                    "ClusterName",
                    "TaskDefinitionFamily"
                ]
            ]
        }
    ]
}

ログの転送は、ECS Task Role、ECS Task execution Role上に CloudwatchLogsのアクセス権限を付与する必要があります。

###AWS FireLens によるログ運用

FireLensは、コンテナから直接Cloudwatch Logsへ転送せず、FireLensコンテナをTaskへ追加する事でFireLensコンテナを経由したログ送信を行います。FireLensは、CloudWatch Logs への転送経路だけではなく、S3Redshiftなどにも転送が可能です。

image.png

FireLensを使用する場合、ログルーティングとしての機能を果たすため、 Fluentd または Fluent Bitのコンテナイメージを使用する必要がありますが、ECR Public Gallery上にfluent bitのイメージが公開されているため、タスク定義に他のアプリケーション用のコンテナと同梱する事が可能です。
なお、Fluent Bit は、リソース使用率が Fluentd よりも低いとされています。

タスク定義で FireLensの設定を指定する場合、logDriver:awsfirelens を指定して、Name:cloudwatch_logs/kinesis_firehose/kinesis_streamsを指定します。

sample8-task-definition.json

			 "logConfiguration": {
				 "logDriver":"awsfirelens",
				 "options": {
					"Name": "kinesis_firehose",
					"region": "us-west-2",
					"delivery_stream": "my-stream"
				}
			}

なお、FireLensを使用して出力先を分岐する場合、fluent Bit conf を変更する必要があります。

sample9-firelens.conf

[INPUT]
    Name xxxxx
    Listen xxxx
    Port xxxxx

[FILTER]
    Name xxxxxxxx
    Match xxxx
    Record xxxxx

[OUTPUT]
    Name firehose
    Match xxx-firelens*
    delivery_stream xxx
    region ap-northeast-1

ECS Task Role、ECS Task execution Role上に各サービスのアクセス権限を付与する必要があります。

Trace

コンテナサービスでは、サービス間の通信や、アプリケーションへのリクエストを処理する情報が煩雑します。
X-Rayは、アプリケーションへのリクエストとレスポンスの情報、呼び出しの詳細な情報などを収集し、問題の特定や可視化を行うサービスとなります。
ECS上でX-Rayを使用する場合、FireLens同様にサイドカー構成として、X-rayコンテナをタスク定義にコンポーネントします。

image.png

X-ray デーモンからX-rayに対してデータを送信するためには以下の点をクリアにする事で実装が可能です。

  • デーモンからX-Rayにアクセス許可を与えるには、SDK でAWS認証情報(credentials)を許可します。
  • ECS Task Roleから、X-rayの書き込み権限を許可する必要があります。
  • X-ray への到達経路にはVPC エンドポイントが必要となります。

なお、X-ray にはインサイトと呼ばれる機能があります。
インサイトでは、アプリケーションパフォーマンスの異常を自動的に検出します。
これにより、Amazon EventBridge イベントを経由して特定の閾値に対して発生した問題をメッセージレベルで確認する事が出来ます。

image.png

今回は、Service Discovery や Appmesh について触れられていませんでしたが、別の機会の記事を作成しようと思います。

参考文献

本記事は、以下の文献を参考とさせていただきました。

  • AWSコンテナ設計・構築[本格]入門

  • Amazon Elastic Container Service ドキュメント

119
97
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
119
97

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?