DockerベースイメージのAmazon Linux 2023移行に伴い、cloudwatch-agentを利用してログを送信する
はじめに
弊社では、9月にPHPのバージョンを8.2->8.4にバージョンアップしました。
このPHPバージョンアップに伴い、ランサーズで利用しているDockerfileのベースイメージをAmazon Linux 2023にアップグレードする必要がありました。
Amazon Linux 2023では今までログ出力に利用していたawslogs
パッケージが利用できないため、CloudWatch Agentを導入することとしました。
本記事では、このCloudWatch Agentの導入についてお話しさせていただきます。
(PHP 7.3->8.4 までバージョンアップをしていただいた、keiさんの記事はこちらから)
参考
AL2 で廃止され、AL2023 で削除された機能
前提
※ 記事の中でコードを記載させていただいておりますが、実際に変更した内容の抜粋となっているため
あくまで参考例にしていただけますと幸いです。
- インフラの構成管理にはTerraformを利用
- アプリケーションは、ECS on Fargateでホスト
- コンテナイメージは、ECRで管理
- リリース時に問題が起きた時のため、ECSにはデプロイサーキットブレーカーが設定済み
方針
- cloudwatch-agentへのリソース配分を決定
- FargateタスクのSidecarコンテナとして、
cloudwwatch-agent
コンテナを導入
手順
cloudwatch-agentへのリソース配分を決定
cloudwatch-agent
コンテナを導入するにあたって、どれくらいのリソースを割り当てるべきか有用な情報が見つけられませんでした。
そこで、下記の手順で現状のリソースを把握しつつ進めることとしました。
- ECSタスクの各コンテナについて、リソース使用状況を可視化
- 推測でリソースを割り振り、検証環境でテスト
- 検証環境でテストした値をもとに、本番環境の設定を決定
ECSタスクの各コンテナについて、リソース使用状況を可視化
コンテナのCPU使用率・メモリ使用量を可視化するにあたっては、Datadogを利用しました。
可視化に仕様したメトリクスは下記の通りです。
- CPU使用率:
ecs.fargate.cpu.percent
- メモリ使用量:
ecs.fargate.mem.usage
また、Sidecarコンテナの各コンテナごとにCPU使用率・メモリ使用率の最大値をグラフ化し、
一覧表示できるdashboardを作成しました。
完成したDashboardを確認したところ、使用量に対してリソースが余っているコンテナがあったため、
そのコンテナのリソースをcloudwatch-agent
に割り振る形で修正を行いました。
リソースの余剰やその他SideCarコンテナの設定値を参考に、下記のとおりリソース配分を行うこととしました。
- cpu: 128
- memory: 256MiB
ex. DatadogでのCPU使用率可視化の例
推測でリソースを割り振り、検証環境でテスト & 検証環境でテストした値をもとに、本番環境の設定を決定
検証したところ、概ね仮の設定値で進められそうでした。(検証内容は下記画像参照)
メモリに関しては、もう128MiBほど割り振っても問題なさそうですが、
下記の理由から仮の設定値のままで進めることとしました。
- ピーク時のメトリクスであること(平均的には使用率がもっと低い)
- メモリ使用率の増減が緩やかであること
実装
ECSタスク定義
主な変更内容は下記の通りです。
- CloudWatch Agent稼働用のsidecarコンテナ追加
- CloudWatch Agent設定ファイルはSSM Parameter Storeから読み取る
- 費用削減のため、
cloudwatch-agent
のイメージはPull Through Cacheを利用
-
cloudwatch-agent
コンテナがログを読み取れるよう、共有ボリュームを追加- 意図しない変更を防ぐため、
cloudwatch-agent
からのボリュームアクセスはReadOnly
に指定
- 意図しない変更を防ぐため、
ex.
[
{
"name": "app",
"image": "xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/app:latest",
"cpu": 1024,
"memory": 2048,
"mountPoints": [
{
"sourceVolume": "system-logs",
"containerPath": "/var/log",
"readOnly": false
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/app",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
},
"ulimits": [
{
"name": "nofile",
"softLimit": 1000000,
"hardLimit": 1000000
}
]
},
{
"name": "cloudwatch-agent",
"image": "xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-public/cloudwatch-agent/cloudwatch-agent:x.xxxxx.xxxxx",
"cpu": 128,
"memory": 256,
"secrets": [
{
"name": "CW_CONFIG_CONTENT",
"valueFrom": "${cw_config_content}"
}
],
"mountPoints": [
{
"sourceVolume": "system-logs",
"containerPath": "/var/log",
"readOnly": true
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/cloudwatch-agent",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
CloudWatch設定ファイル
今回はログのみ収集するため、メトリクス収集の設定は入れていません。
また、費用削減のためVPCエンドポイント経由でのログ送信設定を行っています。
ex.
{
"agent": {
"logfile": "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log",
"debug": false
},
"logs": {
"endpoint_override": "{your_vpc_endpoint_name}",
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/access.log",
"log_group_name": "/lancers/access.log",
"log_stream_name": "{local_hostname}",
"timestamp_format": "%d/%b/%Y:%H:%M:%S %z",
"timezone": "Local"
}
},
"force_flush_interval": 5
}
}
結果
- 上記の設定を本番反映したところ、問題なくCloudWatch Logsにログが出力されました 🥳
- 想像していたより少ないリソースで、CloudWatch Agentが導入できることに気づきました(下記画像参照)
- 赤線がタスク定義で設定している値、青線が実際の使用量を表すグラフになります
- 赤線がタスク定義で設定している値、青線が実際の使用量を表すグラフになります
終わりに
ここまでご覧いただきありがとうございました。
見落としがちですが、Pull Through Cacheの設定が漏れると費用面でのインパクトが大きくなる可能性があるため、忘れず設定するようにしましょう!
(私は見事に失念して余計な費用を発生させてしまいましたので、皆さんは同じ轍を踏まないよう願っております🙏)
Discussion