ECSメインにAWSサービスを利用してコンテナの運用設計を考えてみます。
コンテナの運用設計
ECS 上で稼働するWebアプリケーションを前提に運用の要件を考えてみます。
コンテナを使用したマイクロサービスの運用は、モノシリックなシステム運用とは少し異なります、以下の項目を運用項目としてピックアップします。
- 可用性/スケーリング
- CI/CD
- ロギング
- トレース
- モニタリング
ECS/ECR のアーキテクチャ
まずはECS/ECR のアーキテクチャについて触れます。
Amazon ECSはコンテナの作成、実行、停止といった管理をメインとしたサービスであり、Amazon ECRは Dockerのレジストリサービスとなります。リポジトリにあるイメージをプッシュしたり、イメージの保管等を行います。
全体的なイメージを以下のように理解をしています。
ECSの機能
まずECSです。
ECSは複数のエンティティから機能を果たすため、各々どのような役割を担うかを理解する必要があるかと思います。以下は包含関係と関係性を図解として描いています。
Task definition(タスク定義)
task definition
とは起動するtask
の情報が定義されたもので、
docker-compose.yml
のようなイメージです。
起動するタイプ(EC2
or Farate
)をタスク定義から定義し、1つのタスク定義上に複数のコンテナを定義する事が可能です。
task definitionのimage
パラメーター上で、後述のECR image
に対してアクセスし、ECR image をそのままTask
として実行する事も出来ます。
また、後述するService
はtask definition
を指定する必要があります。
サンプルとしてtask definition
が保持するデータを表示させてみます。
イメージ情報やコンピューティングリソース、通信プロトコルなどが定義されている事が判ります。
{
"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 definition
はJSON
にて定義出来ます。
なお、AWS CLI を使用してタスク定義のテンプレートを生成する事が可能で、
空のタスク定義のテンプレートがAWSドキュメントに記載されています。
aws ecs register-task-definition --generate-cli-skeleton
タスク定義テンプレート
以下に示しているのは、空のタスク定義テンプレートです。このテンプレートを使用してタスク定義を作成します。これにより、コンソールの JSON 入力領域に貼り付けるか、ファイルに保存して AWS CLI の --cli-input-json オプションで使用できるようになります。詳細については、「タスク定義パラメータ」を参照してください。
ECS Cluster
クラスター自体は、後述するACTIVE
なService
、Task
が実行される論理的なグループという理解で良いかと思います。
また、クラスターを作成する際に、VPC/サブネット
などのネットワーク情報を定義します。
サンプルとしてECSクラスター
が保持するデータを表示させてみます。
{
"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ファイルからサービスの作成も可能です。
{
"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は、起動/停止
が可能です。
ECRの機能
ECR の主要コンポーネントである レジストリ
/ リポジトリ
/ イメージ
についてです。
Registry
レジストリ内にイメージリポジトリを作成し、イメージを保存します。
レジストリ自体は認証
(Dockerクライアントとの認証許可を行う事で、レジストリ内のリポジトリとの間でイメージをプッシュ、プルできるようにする)、レプリケーション
(AWSのクロスリージョン、クロスアカウントに対するイメージのレプリケーション)等によるものなので、設定情報という理解で良いかと思います。
Repository
後述のコンテナイメージ
は Amazon ECRリポジトリ
に保存されます。
また、2020年12月以降、ECRはパブリック領域としての利用が可能となり、コンテナイメージをパブリックに公開する事も、ダウンロードすることが可能になりました。
image
docker image
のようなもので、イメージをリポジトリ内へpush(docker push)
して、登録を行います。イメージはURI形式
で連携が可能で、ECSのタスク定義として使用出来ます。実態はS3
へ配置されます。
稼動システムの全体像
コンテナの運用をするために複数のAWSサービスを使用します。
今回は、一般的なWebアプリケーションを想定し、以下の構成図から運用を考えていきます。
Monitoring
ECSに対して監視を行う場合、Cloudwatch メトリクス
とCloudwatch Container Insights
の二種類の機能を使用する状況を把握する事が出来ます。
いずれもメトリクスと呼ばれる指標となるデータポイント
を一定期間で集計したもので、対象のメトリクスが閾値を超えた場合、アラームを送信するなどの対策も可能です。
Cloudwatch メトリクス
Cloudwatch メトリクスは、ECSのサービス単位で MemoryUtilization
/ CPUUtilization
の2つの指標をモニターします。
メトリクス | 説明 |
---|---|
MemoryUtilization | クラスター、サービス単位で使用されているメモリーの割合(%) |
CPUUtilization | クラスター、サービスで使用されている CPU の割合(%) |
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 インスタンスレベルのメトリクスの収集を開始します。
メトリクス | 対象 | 説明 |
---|---|---|
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 インスタンスと同じネットワークプロパティが与えられます。
-
bridge
タスクは、タスクをホストする各 Amazon EC2 インスタンス内で実行される Docker の組み込み仮想ネットワーク
を利用します。
-
host
タスクは Docker の組み込み仮想ネットワークをバイパスし、タスクをホストしている Amazon EC2 インスタンスの ENI にコンテナポートを直接マッピングします。その結果、ポートマッピングが使用されている場合、1 つの Amazon EC2 インスタンスで同じタスクのインスタンスを複数実行することはできません。
可用性とScaling
ECSの可用性とScalingはServiceの機能がカバーします。
それぞれの観点から見ていきます。
可用性
ECSのService にはサービススケジューラ(schedulingStrategy)
というパラメーターが存在します。
schedulingStrategy
では、以下の2つを指定出来ます。
- REPLICA
クラスター全体で必要な数のタスク(DesiredCount)を配置して維持します。デフォルトでは、サービススケジューラによってタスクはアベイラビリティーゾーン間で分散する構成を自動で行います。
- DAEMON
クラスター内のアクティブなコンテナインスタンスごとに、1 つのタスクのみをデプロイします。サービススケジューラは、実行中のタスクのタスク配置制約(後述の参考URL)を評価し、配置制約を満たさないタスクを停止します。
つまりインスタンス数とタスク数が 1対1で実行するように維持します。
DAEMONタイプの設定は、Fargate 起動タイプでは利⽤が出来ません。
Scaling
ECS上で機能するスケーリングについて考えていきます。
スケーリングには、スケールアップ
(タスクサイズと呼ばれるtaskのCPU/memoryの増強)とスケールアウト/イン
が考えられますが、今回はTaskの停止を伴わないスケールアウト/インについて触れていきます。
AutoScaling
ECSでは、ServiceへAuto Scalingを設定する事が出来ます。(Service Auto Scaling)
これはサービスの必要タスク数(DesiredCount)を⾃動的に増減させるというものです。
タスクの必要数
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つへスケールアウトなどという設定が可能です。
また、クールダウン
と呼ばれるスケールアウト/インアクティビティが完了してから別のアクティビティが開始されるまでの時間を指定する事が可能です。
なお、スケールインのクールダウンの場合、クールダウン期間中に別のアラームによってスケールアウトがトリガーされると、Service Auto Scaling によって即座にスケールアウトされます。
スケーリングイベントが発生している最中に、別のスケーリングイベント(80%から更に90%以上になった場合)が発生し得る場合、クールダウン時間を減らす事で突如発生するスパイク
にも対応が可能となります。
- ターゲット追跡スケーリング
特定の CloudWatch メトリクスのターゲット値に基づいてリソースをスケールします。
ステップスケーリング同様に以下3つのメトリクスを選択し、ターゲット値を指定します。
ECSServiceAverageCPUUtilization
サービスの平均 CPU 使用率ECSServiceAveregemorutilization
サービスのメモリ平均使用率ALBRequestCountPerTarget
Application Load Balancer ターゲットグループ内のターゲットごとに完了したリクエスト数
ターゲット追跡スケーリング
では、選択したメトリクスのターゲット値を標準としたアラームの自動生成が行われます。
例えばECSServiceAverageCPUUtilization
のターゲット値を60%
とした場合、スケールアウト/インの閾値(%)が、自動で作成され、60%を保とうとする仕組みです。
サービス可用性の影響を軽減させるため、スケールインポリシーは長期間にわたって実行されるようです。(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にて起動します。
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内で完結させることが出来ます。
今回はECSを使用したシステムのため、ECSへ特記した事項として2点あります。
1. CodeBuildでビルドしたイメージはbuildspec.ymlで定義した情報からECRへイメージをpushが出来ます。(ECRのサービスロールからCodeBuildからのアクセスを許可する必要があります)
2. ECR に格納されているイメージへの変更を検出し、CodeDeployを使用して、ECS クラスターとロードバランサーにルーティングしてデプロイする事が出来ます。
これらを踏まえて、運用観点からどのような設計を行うかを考えていきます。
パイプライン設計とイメージのメンテナンス
CI/CD パイプラインからイメージの更新がある場合、ECRへイメージを自動プッシュ
する流れとなります。プロダクションを意識したCI/CD パイプラインでは、本番・検証・開発環境が共存するサービス、分離すべきサービスが混雑する可能性が高いため、環境単位、タスク単位などの細かなパイプライン設計が事前に必要となってくると思います。
その一つとして、ECRリポジトリ
をどのように分けるなども考慮が必要です。
ECRのリポジトリにプッシュされたイメージの実態はS3
へ保存されますが、このリポジトリに対して、ライフサイクルポリシー
を設定する事が可能です。
ライフサイクルはルール
に沿って解釈され、イメージのタグ
に基づいたポリシーを設定する事も可能です。開発規模が大きければ大きいほど、イメージの更新頻度は上がりますので、ライフサイクルも同時に踏まえた上で全体のリポジトリの設計を行い、不要なファイルをメンテナンスする仕組みを設けた方がよさそうです。
{
"rules": [
{
"rulePriority": 1,
"description": "Expire images older than 10 days",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 10
},
"action": {
"type": "expire"
}
}
]
}
{
"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 パイプライン経由でプロダクション環境を新しいリジョンで適用する際に、承認プロセスを設けてリリース可否を判断させる仕組みを設ける事で、開発者/運用者と承認者の間でリリースの影響下をお互いに共有する事ができ、予期せぬアクシデント未然に防ぐ、あるいは自動化に意思決定の判断を設ける、ガバナンスの強化といった様々な観点を保護します。
Code Pipeline のGUIとApproval アクションを追加する際の設定項目です。
設定項目 | 説明 |
---|---|
アクション名 | 承認アクションの任意の名前 |
アクションプロバイダー | 承認プロセスでは手動承認を選択 |
SNS トピックの ARN | 承認アクションの通知を送るために使用するトピック |
レビュー用 URL | レビュー担当者に提供する URL |
コメント | メールやコンソールでレビュアーに向けて表示出来るコメント内容 |
変数の名前空間 | パイプラインアクションで使用できる変数 |
AWS CI/CDの各サービスの概要はこちらに少しまとめています。
Logging
コンテナのログ出力は、ドライバーにより異なります。
Fargate 起動タイプを使用するタスクの場合、サポートされるログドライバーは
awslogs
、splunk
、awsfirelens
です。EC2 起動タイプを使用するタスクの場合、サポートされるログドライバーは
awslogs
、fluentd
、gelf
、json-file
、journald
、logentries
、syslog
、splunk
、awsfirelens
です。
今回は AWSに標準で使用される awslogs
とawsfirelens
について記載していきます。
Cloudwatch Logs によるログ運用
awslogs
は、コンテナのログをCloudwatch Logs
へ転送します。
Cloudwatch Logs に転送されたログをエラーハンドリングする事も、ログストレージとして使用する事も可能です。
使用方法は、Task Definition
のコンテナ定義に定義された logConfiguration
パラメーターから logDriver:awslogs
を指定し、有効化します。タスク定義から作成された各コンテナのログはCloudWatch Logs へ転送されます。
{
"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ロググループが生成され、転送を行います。サンプルを以下に表示します。
{
"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 への転送経路だけではなく、S3
やRedshift
などにも転送が可能です。
FireLensを使用する場合、ログルーティングとしての機能を果たすため、 Fluentd
または Fluent Bit
のコンテナイメージを使用する必要がありますが、ECR Public Gallery
上にfluent bitのイメージが公開されているため、タスク定義に他のアプリケーション用のコンテナと同梱する事が可能です。
なお、Fluent Bit は、リソース使用率が Fluentd よりも低いとされています。
タスク定義で FireLensの設定を指定する場合、logDriver:awsfirelens
を指定して、Name:cloudwatch_logs/kinesis_firehose/kinesis_streamsを指定します。
"logConfiguration": {
"logDriver":"awsfirelens",
"options": {
"Name": "kinesis_firehose",
"region": "us-west-2",
"delivery_stream": "my-stream"
}
}
なお、FireLensを使用して出力先を分岐する場合、fluent Bit 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コンテナをタスク定義にコンポーネントします。
X-ray デーモンからX-rayに対してデータを送信するためには以下の点をクリアにする事で実装が可能です。
- デーモンからX-Rayにアクセス許可を与えるには、SDK で
AWS認証情報(credentials)
を許可します。 -
ECS Task Role
から、X-rayの書き込み権限を許可する必要があります。 - X-ray への到達経路にはVPC エンドポイントが必要となります。
なお、X-ray にはインサイト
と呼ばれる機能があります。
インサイトでは、アプリケーションパフォーマンスの異常を自動的に検出します。
これにより、Amazon EventBridge イベントを経由して特定の閾値に対して発生した問題をメッセージレベルで確認する事が出来ます。
今回は、Service Discovery や Appmesh について触れられていませんでしたが、別の機会の記事を作成しようと思います。
参考文献
本記事は、以下の文献を参考とさせていただきました。
- AWSコンテナ設計・構築[本格]入門
- Amazon Elastic Container Service ドキュメント