ログ集約
オブザーバビリティのベストプラクティスガイドのこのセクションでは、AWS ネイティブサービスを使用した Amazon EKS ロギングに関連する以下のトピックについて詳しく説明します:
- Amazon EKS ロギングの概要
- Amazon EKS コントロールプレーンのロギング
- Amazon EKS データプレーンのロギング
- Amazon EKS アプリケーションのロギング
- AWS ネイティブサービスを使用した Amazon EKS と他のコンピューティングプラットフォームからの統合ログ集約
- まとめ
はじめに
Amazon EKS のログは、コントロールプレーンのログ、ノードのログ、アプリケーションのログの 3 つのタイプに分類できます。Kubernetes コントロールプレーン は、Kubernetes クラスターを管理し、監査と診断目的のログを生成するコンポーネントのセットです。Amazon EKS では、異なるコントロールプレーンコンポーネントのログを有効化し、CloudWatch に送信できます。
Kubernetes は、Pod を実行する各 Kubernetes ノードで kubelet や kube-proxy などのシステムコンポーネントも実行します。これらのコンポーネントは各ノード内にログを書き込み、CloudWatch と Container Insights を設定して各 Amazon EKS ノードのログを取得できます。
コンテナは Kubernetes クラスター内で Pod としてグループ化され、Kubernetes ノードで実行されるようにスケジュールされます。ほとんどのコンテナ化されたアプリケーションは標準出力と標準エラーに書き込みを行い、コンテナエンジンはその出力をログドライバーにリダイレクトします。Kubernetes では、コンテナログはノードの /var/log/pods ディレクトリにあります。CloudWatch と Container Insights を設定して、各 Amazon EKS Pod のログを取得できます。
Kubernetes でコンテナログを集中ログ集約システムに送信する一般的なアプローチには、以下の 3 つがあります:
- Fluentd DaemonSet のようなノードレベルのエージェント。これが推奨パターンです。
- Fluentd サイドカーコンテナのようなサイドカーコンテナ。
- ログ収集システムへの直接書き込み。このアプローチでは、アプリケーションがログの送信を担当します。これは最も推奨されないオプションです。なぜなら、Fluentd のようなコミュニティが構築したソリューションを再利用する代わりに、アプリケーションコードにログ集約システムの SDK を含める必要があるためです。このパターンは、関心の分離 の原則にも反します。この原則によれば、ログの実装はアプリケーションから独立しているべきです。これにより、アプリケーションに影響を与えたり変更したりすることなく、ログインフラストラクチャを変更できます。
これから、Amazon EKS ログの各カテゴリについて詳しく見ていき、Amazon EKS と他のコンピューティングプラットフォームからの統合ログ集約についても説明します。
Amazon EKS コントロールプレーンのロギング
Amazon EKS クラスターは、Kubernetes クラスター用の高可用性のシングルテナントコントロールプレーンと、コンテナを実行する Amazon EKS ノードで構成されています。 コントロールプレーンノードは AWS が管理するアカウントで実行されます。 Amazon EKS クラスターのコントロールプレーンノードは CloudWatch と統合されており、特定のコントロールプレーンコンポーネントのロギングを有効にすることができます。 各 Kubernetes コントロールプレーンコンポーネントインスタンスのログが提供されます。 AWS はコントロールプレーンノードの健全性を管理し、Kubernetes エンドポイントのサービスレベルアグリーメント (SLA) を提供します。
Amazon EKS コントロールプレーンのロギング は、以下のクラスターコントロールプレーンのログタイプで構成されています。 各ログタイプは、Kubernetes コントロールプレーンのコンポーネントに対応しています。 これらのコンポーネントの詳細については、Kubernetes ドキュメントの Kubernetes Components を参照してください。
- API サーバー (
api) – クラスターの API サーバーは、Kubernetes API を公開するコントロールプレーンコンポーネントです。クラスター起動時またはその直後に API サーバーのログを有効にすると、API サーバーの起動に使用されたフラグがログに含まれます。詳細については、Kubernetes ドキュメントのkube-apiserverと 監査ポリシー を参照してください。 - 監査 (
audit) – Kubernetes 監査ログは、クラスターに影響を与えた個々のユーザー、管理者、またはシステムコンポーネントの記録を提供します。詳細については、Kubernetes ドキュメントの Auditing を参照してください。 - 認証機能 (
authenticator) – 認証機能のログは Amazon EKS 固有のものです。これらのログは、IAM 認証情報を使用して Kubernetes の ロールベースアクセス制御 (RBAC) 認証を行うために Amazon EKS が使用するコントロールプレーンコンポーネントを表します。詳細については、クラスター管理 を参照してください。 - コントローラーマネージャー (
controllerManager) – コントローラーマネージャーは、Kubernetes に付属するコアコントロールループを管理します。詳細については、Kubernetes ドキュメントの kube-controller-manager を参照してください。 - スケジューラー (
scheduler) – スケジューラーコンポーネントは、クラスター内の Pod をいつどこで実行するかを管理します。詳細については、Kubernetes ドキュメントの kube-scheduler を参照してください。
コントロールプレーンログの有効化と無効化 のセクションに従って、AWS コンソールまたは AWS CLI を使用してコントロールプレーンログを有効にしてください。
CloudWatch コンソールからコントロールプレーンログを照会する
Amazon EKS クラスターでコントロールプレーンのログ記録を有効にすると、/aws/eks/cluster-name/cluster ロググループで EKS コントロールプレーンログを確認できます。詳細については、クラスターコントロールプレーンログの表示 を参照してください。cluster-name をクラスターの名前に置き換えてください。
CloudWatch Logs Insights を使用して、EKS コントロールプレーンのログデータを検索できます。詳細については、CloudWatch Insights を使用したログデータの分析 を参照してください。重要な点として、クラスターでコントロールプレーンのログ記録を有効にした後でのみ、CloudWatch Logs でログイベントを表示できます。CloudWatch Logs Insights でクエリを実行する時間範囲を選択する前に、コントロールプレーンのログ記録が有効になっていることを確認してください。以下のスクリーンショットは、ク エリ出力を含む EKS コントロールプレーンログのクエリ例を示しています。

図: CloudWatch Logs Insights
CloudWatch Logs Insights での一般的な EKS ユースケースのサンプルクエリ
クラスター作成者を見つけるには、kubernetes-admin ユーザーにマッピングされている IAM エンティティを検索します。
fields @logStream, @timestamp, @message| sort @timestamp desc
| filter @logStream like /authenticator/
| filter @message like "username=kubernetes-admin"
| limit 50
出力例:
@logStream, @timestamp @messageauthenticator-71976 ca11bea5d3083393f7d32dab75b,2021-08-11-10:09:49.020,"time=""2021-08-11T10:09:43Z"" level=info msg=""access granted"" arn=""arn:aws:iam::12345678910:user/awscli"" client=""127.0.0.1:51326"" groups=""[system:masters]"" method=POST path=/authenticate sts=sts.eu-west-1.amazonaws.com uid=""heptio-authenticator-aws:12345678910:ABCDEFGHIJKLMNOP"" username=kubernetes-admin"
この出力では、IAM ユーザー arn:aws:iam::12345678910:user/awscli が kubernetes-admin ユーザーにマッピングされています。
特定のユーザーが実行したリクエストを見つけるには、kubernetes-admin ユーザーが実行した操作を検索します。
fields @logStream, @timestamp, @message| filter @logStream like /^kube-apiserver-audit/
| filter strcontains(user.username,"kubernetes-admin")
| sort @timestamp desc
| limit 50
出力例:
@logStream,@timestamp,@messagekube-apiserver-audit-71976ca11bea5d3083393f7d32dab75b,2021-08-11 09:29:13.095,"{...""requestURI"":""/api/v1/namespaces/kube-system/endpoints?limit=500";","string""verb"":""list"",""user"":{""username"":""kubernetes-admin"",""uid"":""heptio-authenticator-aws:12345678910:ABCDEFGHIJKLMNOP"",""groups"":[""system:masters"",""system:authenticated""],""extra"":{""accessKeyId"":[""ABCDEFGHIJKLMNOP""],""arn"":[""arn:aws:iam::12345678910:user/awscli""],""canonicalArn"":[""arn:aws:iam::12345678910:user/awscli""],""sessionName"":[""""]}},""sourceIPs"":[""12.34.56.78""],""userAgent"":""kubectl/v1.22.0 (darwin/amd64) kubernetes/c2b5237"",""objectRef"":{""resource"":""endpoints"",""namespace"":""kube-system"",""apiVersion"":""v1""}...}"
特定の userAgent が行った API コールを見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, userAgent, verb, requestURI, @message| filter @logStream like /kube-apiserver-audit/
| filter userAgent like /kubectl\/v1.22.0/
| sort @timestamp desc
| filter verb like /(get)/
短縮された出力例:
@logStream,@timestamp,userAgent,verb,requestURI,@messagekube-apiserver-audit-71976ca11bea5d3083393f7d32dab75b,2021-08-11 14:06:47.068,kubectl/v1.22.0 (darwin/amd64) kubernetes/c2b5237,get,/apis/metrics.k8s.io/v1beta1?timeout=32s,"{""kind"":""Event"",""apiVersion"":""audit.k8s.io/v1"",""level"":""Metadata"",""auditID"":""863d9353-61a2-4255-a243-afaeb9183524"",""stage"":""ResponseComplete"",""requestURI"":""/apis/metrics.k8s.io/v1beta1?timeout=32s"",""verb"":""get"",""user"":{""username"":""kubernetes-admin"",""uid"":""heptio-authenticator-aws:12345678910:AIDAUQGC5HFOHXON7M22F"",""groups"":[""system:masters"",""system:authenticated""],""extra"":{""accessKeyId"":[""ABCDEFGHIJKLMNOP""],""arn"":[""arn:aws:iam::12345678910:user/awscli""],""canonicalArn"":[""arn:aws:iam::12345678910:user/awscli""],""sourceIPs"":[""12.34.56.78""],""userAgent"":""kubectl/v1.22.0 (darwin/amd64) kubernetes/c2b5237""...}"
aws-auth ConfigMap に対して行われた変更を見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, @message| filter @logStream like /^kube-apiserver-audit/
| filter requestURI like /\/api\/v1\/namespaces\/kube-system\/configmaps/
| filter objectRef.name = "aws-auth"
| filter verb like /(create|delete|patch)/
| sort @timestamp desc
| limit 50
短縮された出力例:
@logStream,@timestamp,@messagekube-apiserver-audit-f01c77ed8078a670a2eb63af6f127163,2021-10-27 05:43:01.850,{""kind"":""Event"",""apiVersion"":""audit.k8s.io/v1"",""level"":""RequestResponse"",""auditID"":""8f9a5a16-f115-4bb8-912f-ee2b1d737ff1"",""stage"":""ResponseComplete"",""requestURI"":""/api/v1/namespaces/kube-system/configmaps/aws-auth?timeout=19s"",""verb"":""patch"",""responseStatus"": {""metadata"": {},""code"": 200 },""requestObject"": {""data"": { contents of aws-auth ConfigMap } },""requestReceivedTimestamp"":""2021-10-27T05:43:01.033516Z"",""stageTimestamp"":""2021-10-27T05:43:01.042364Z"" }
拒否されたリクエストを見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, @message| filter @logStream like /^authenticator/
| filter @message like "denied"
| sort @timestamp desc
| limit 50
出力例:
@logStream,@timestamp,@messageauthenticator-8c0c570ea5676c62c44d98da6189a02b,2021-08-08 20:04:46.282,"time=""2021-08-08T20:04:44Z"" level=warning msg=""access denied"" client=""127.0.0.1:52856"" error=""sts getCallerIdentity failed: error from AWS (expected 200, got 403)"" method=POST path=/authenticate"
Pod がスケジュールされたノードを見つけるには、kube-scheduler ログをクエリします。
fields @logStream, @timestamp, @message| sort @timestamp desc
| filter @logStream like /kube-scheduler/
| filter @message like "aws-6799fc88d8-jqc2r"
| limit 50
出力例:
@logStream,@timestamp,@messagekube-scheduler-bb3ea89d63fd2b9735ba06b144377db6,2021-08-15 12:19:43.000,"I0915 12:19:43.933124 1 scheduler.go:604] ""Successfully bound pod to node"" pod=""kube-system/aws-6799fc88d8-jqc2r"" node=""ip-192-168-66-187.eu-west-1.compute.internal"" evaluatedNodes=3 feasibleNodes=2"
この出力例では、Pod aws-6799fc88d8-jqc2r がノード ip-192-168-66-187.eu-west-1.compute.internal にスケジュールされました。
Kubernetes API サーバーリクエストの HTTP 5xx サーバーエラーを見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, responseStatus.code, @message| filter @logStream like /^kube-apiserver-audit/
| filter responseStatus.code >= 500
| limit 50
短縮された出力例:
@logStream,@timestamp,responseStatus.code,@messagekube-apiserver-audit-4d5145b53c40d10c276ad08fa36d1f11,2021-08-04 07:22:06.518,503,"...""requestURI"":""/apis/metrics.k8s.io/v1beta1?timeout=32s"",""verb"":""get"",""user"":{""username"":""system:serviceaccount:kube-system:resourcequota-controller"",""uid"":""36d9c3dd-f1fd-4cae-9266-900d64d6a754"",""groups"":[""system:serviceaccounts"",""system:serviceaccounts:kube-system"",""system:authenticated""]},""sourceIPs"":[""12.34.56.78""],""userAgent"":""kube-controller-manager/v1.21.2 (linux/amd64) kubernetes/d2965f0/system:serviceaccount:kube-system:resourcequota-controller"",""responseStatus"":{""metadata"":{},""code"":503},..."}}"
CronJob のアクティベーションをトラブルシューティングするには、cronjob-controller が行った API コールを検索します。
fields @logStream, @timestamp, @message| filter @logStream like /kube-apiserver-audit/
| filter user.username like "system:serviceaccount:kube-system:cronjob-controller"
| display @logStream, @timestamp, @message, objectRef.namespace, objectRef.name
| sort @timestamp desc
| limit 50
短縮された出力例:
{ "kind": "Event", "apiVersion": "audit.k8s.io/v1", "objectRef": { "resource": "cronjobs", "namespace": "default", "name": "hello", "apiGroup": "batch", "apiVersion": "v1" }, "responseObject": { "kind": "CronJob", "apiVersion": "batch/v1", "spec": { "schedule": "*/1 * * * *" }, "status": { "lastScheduleTime": "2021-08-09T07:19:00Z" } } }
この出力例では、default 名前空間の hello ジョブが毎分実行され、最後のスケジュール時刻は 2021-08-09T07:19:00Z でした。
replicaset-controller が行った API コールを見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, @message| filter @logStream like /kube-apiserver-audit/
| filter user.username like "system:serviceaccount:kube-system:replicaset-controller"
| display @logStream, @timestamp, requestURI, verb, user.username
| sort @timestamp desc
| limit 50
出力例:
@logStream,@timestamp,requestURI,verb,user.usernamekube-apiserver-audit-8c0c570ea5676c62c44d98da6189a02b,2021-08-10 17:13:53.281,/api/v1/namespaces/kube-system/pods,create,system:serviceaccount:kube-system:replicaset-controller
kube-apiserver-audit-4d5145b53c40d10c276ad08fa36d1f11,2021-08-04 0718:44.561,/apis/apps/v1/namespaces/kube-system/replicasets/coredns-6496b6c8b9/status,update,system:serviceaccount:kube-system:replicaset-controller
Kubernetes リソースに対して行われた操作を見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, @message| filter @logStream like /^kube-apiserver-audit/
| filter verb == "delete" and requestURI like "/api/v1/namespaces/default/pods/my-app"
| sort @timestamp desc
| limit 10
上記のクエリ例は、Pod my-app の default 名前空間に対する delete API コールをフィルタリングします。 短縮された出力例:
@logStream,@timestamp,@messagekube-apiserver-audit-e7b3cb08c0296daf439493a6fc9aff8c,2021-08-11 14:09:47.813,"...""requestURI"":""/api/v1/namespaces/default/pods/my-app"",""verb"":""delete"",""user"":{""username""""kubernetes-admin"",""uid"":""heptio-authenticator-aws:12345678910:ABCDEFGHIJKLMNOP"",""groups"":[""system:masters"",""system:authenticated""],""extra"":{""accessKeyId"":[""ABCDEFGHIJKLMNOP""],""arn"":[""arn:aws:iam::12345678910:user/awscli""],""canonicalArn"":[""arn:aws:iam::12345678910:user/awscli""],""sessionName"":[""""]}},""sourceIPs"":[""12.34.56.78""],""userAgent"":""kubectl/v1.22.0 (darwin/amd64) kubernetes/c2b5237"",""objectRef"":{""resource"":""pods"",""namespace"":""default"",""name"":""my-app"",""apiVersion"":""v1""},""responseStatus"":{""metadata"":{},""code"":200},""requestObject"":{""kind"":""DeleteOptions"",""apiVersion"":""v1"",""propagationPolicy"":""Background""},
..."
Kubernetes API サーバーへのコールに対する HTTP レスポンスコードの数を取得するには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, @message| filter @logStream like /^kube-apiserver-audit/
| stats count(*) as count by responseStatus.code
| sort count desc
出力例:
responseStatus.code,count200,35066
201,525
403,125
404,116
101,2
kube-system 名前空間の DaemonSets/Addons に対して行われた変更を見つけるには、以下のクエリ例を使用できます:
filter @logStream like /^kube-apiserver-audit/| fields @logStream, @timestamp, @message
| filter verb like /(create|update|delete)/ and strcontains(requestURI,"/apis/apps/v1/namespaces/kube-system/daemonsets")
| sort @timestamp desc
| limit 50
出力例:
{ "kind": "Event", "apiVersion": "audit.k8s.io/v1", "level": "RequestResponse", "auditID": "93e24148-0aa6-4166-8086-a689b0031612", "stage": "ResponseComplete", "requestURI": "/apis/apps/v1/namespaces/kube-system/daemonsets/aws-node?fieldManager=kubectl-set", "verb": "patch", "user": { "username": "kubernetes-admin", "groups": [ "system:masters", "system:authenticated" ] }, "userAgent": "kubectl/v1.22.2 (darwin/amd64) kubernetes/8b5a191", "objectRef": { "resource": "daemonsets", "namespace": "kube-system", "name": "aws-node", "apiGroup": "apps", "apiVersion": "v1" }, "requestObject": { "REDACTED": "REDACTED" }, "requestReceivedTimestamp": "2021-08-09T08:07:21.868376Z", "stageTimestamp": "2021-08-09T08:07:21.883489Z", "annotations": { "authorization.k8s.io/decision": "allow", "authorization.k8s.io/reason": "" } }
この出力例では、kubernetes-admin ユーザーが kubectl v1.22.2 を使用して aws-node DaemonSet にパッチを適用しました。
ノードを削除したユーザーを見つけるには、以下のクエリ例を使用できます:
fields @logStream, @timestamp, @message| filter @logStream like /^kube-apiserver-audit/
| filter verb == "delete" and requestURI like "/api/v1/nodes"
| sort @timestamp desc
| limit 10
短縮された出力例:
@logStream,@timestamp,@messagekube-apiserver-audit-e503271cd443efdbd2050ae8ca0794eb,2022-03-25 07:26:55.661,"{"kind":"Event","
最後に、コントロールプレーンのロギング機能の使用を開始した場合は、Understanding and Cost Optimizing Amazon EKS Control Plane Logs についてさらに学ぶことを強くお勧めします。
Amazon EKS データプレーンのロギング
Amazon EKS のログとメトリクスを取得するには、CloudWatch Container Insights の使用をお勧めします。Container Insights は、CloudWatch エージェントを使用してクラスター、ノード、Pod レベルのメトリクスを実装し、Fluent Bit または Fluentd を使用して CloudWatch にログを取得します。Container Insights は、取得した CloudWatch メトリクスの階層化されたビューを持つ自動ダッシュボードも提供します。Container Insights は、すべての Amazon EKS ノードで実行される CloudWatch DaemonSet と Fluent Bit DaemonSet としてデプロイされます。Fargate ノードは AWS によって管理され、DaemonSet をサポートしていないため、Container Insights ではサポートされていません。Amazon EKS の Fargate ロギングについては、このガイドで別途説明します。
以下の表は、Amazon EKS のデフォルトの Fluentd または Fluent Bit ログ取得設定によって取得される CloudWatch ロググループとログを示しています。
/aws/containerinsights/Cluster_Name/host | /var/log/dmesg、/var/log/secure、/var/log/messages からのログ |
|---|---|
/aws/containerinsights/Cluster_Name/dataplane | kubelet.service、kubeproxy.service、docker.service の /var/log/journal 内のログ |
ロギングに Container Insights と Fluent Bit または Fluentd を使用したくない場合は、Amazon EKS ノードにインストールされた CloudWatch エージェントを使用してノードとコンテナのログを取得できます。Amazon EKS ノードは EC2 インスタンスであるため、Amazon EC2 の標準的なシステムレベルのロギングアプローチに含める必要があります。Distributor と State Manager を使用して CloudWatch エージェントをインストールする場合、Amazon EKS ノードも CloudWatch エージェントのインストール、設定、更新に含まれます。以下の表は、ロギングに Container Insights と Fluent Bit または Fluentd を使用していない場合に取得する必要がある Kubernetes 固有のログを示しています。
var/log/aws-routed-eni/ipamd.log``/var/log/aws-routed-eni/plugin.log | L-IPAM デーモンのログはここにあります |
|---|
データプレーンのロギングについて詳しくは、Amazon EKS ノードロギングのプリスクリプティブガイダンスを参照してください。