kOpsで構築したKubernetesクラスターにContainer Insightsを設定する

kOpsで構築したKubernetesクラスターにContainer Insightsを設定する

2025.12.22

はじめに

こんにちは、コンサルティング部のぐっさんです。
kOpsを使ってAWS上に構築したKubernetesクラスターで、AWS Container Insightsを利用してメトリクスとログを可視化してみたいと思い、導入手順を検証しました。

Container Insightsとは

Container Insightsは、コンテナ化されたアプリケーションやマイクロサービスからメトリクスとログを収集・集約・要約するAWSのフルマネージドサービスです。以下のプラットフォームで利用可能です。

  • Amazon ECS
  • Amazon EKS
  • Kubernetes on Amazon EC2(kOps含む)
  • Red Hat OpenShift on AWS (ROSA)

参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/ContainerInsights.html

https://dev.classmethod.jp/articles/cloudwatch-container-insights/

https://dev.classmethod.jp/articles/amazon-ecs-container-insights-enhanced-observability-awsreinvent-ga/

料金について

Container Insightsには2つの料金体系があります。

項目 Standard Enhanced Observability(拡張可観測性)
課金単位 CloudWatchメトリクス数 観測データ数
メトリクス粒度 クラスター/ノード/Pod/サービス + ワークロード/コンテナレベル
特徴 基本的な監視 詳細なトラブルシューティング、コンテナ単位の分析

現在Quick Startで導入されるCloudWatch Agentはバージョン1.300035.0以降のため、自動的にEnhanced Observabilityが適用される想定です。

Note: コンテナログは別途CloudWatch Logs料金(取り込み・保存)が発生します。検証後は不要なリソースを削除してコストを抑えましょう。

詳細は料金ページを参照してください。

https://aws.amazon.com/cloudwatch/pricing/

前提条件

本記事の手順を実行する前に、以下が必要です。

  • kOps、kubectlのインストール
  • AWS CLIのインストールと設定
  • SSHキーペアの作成済み(~/.ssh/id_rsa.pub

本記事の検証環境

項目 バージョン/構成
Kubernetes 1.32(kOps 1.33.1 デフォルト)
OS Amazon Linux 2023
インスタンスタイプ t3.medium
ノード構成 マスター1台 + ワーカー2台
Container Insights導入方式 Quick Start(CloudWatch Agent Operator + Fluent Bit)

アーキテクチャ

簡単な構成イメージです。

ar

kOpsクラスターの構築

Note: 本記事では、AWS認証情報を平文で保存しないためにaws-vaultを使用しています。以降の手順では、必要な部分でaws-vault exec <profile-name> --を各コマンドの前に付与していますが環境に応じて読み替えてください。

aws-vault exec <profile-name> -- kops create cluster ...

参考

https://dev.classmethod.jp/articles/aws-vault/

なお、kOpsでのクラスター構築については以下の記事でチュートリアルを試しているので基本の構築方法はこちらを参照ください。本記事では、作成時のコマンドのみ記載し詳細までは触れません。

https://dev.classmethod.jp/articles/kops-tutorial-aws/

Step 1: S3バケットの作成(State Store用)

kOpsはクラスターの状態をS3に保存します。

# バケット名を設定(タイムスタンプで一意な名称とする)
BUCKET_NAME=kops-state-$(date +%Y%m%d-%H%M%S)
echo $BUCKET_NAME

# バケット作成
aws-vault exec <profile-name> -- aws s3 mb s3://${BUCKET_NAME} --region ap-northeast-1

Step 2: 環境変数の設定

# State Storeの設定
export KOPS_STATE_STORE=s3://${BUCKET_NAME}
echo $KOPS_STATE_STORE
# クラスター名(.k8s.local でゴシップモード=Route53不要)
export CLUSTER_NAME=container-insights.k8s.local
echo $CLUSTER_NAME

Step 3: クラスターの作成

aws-vault exec <profile-name> -- kops create cluster \
  --name=${CLUSTER_NAME} \
  --state=${KOPS_STATE_STORE} \
  --zones=ap-northeast-1a \
  --topology=private \
  --networking=calico \
  --master-size=t3.medium \
  --master-count=1 \
  --node-size=t3.medium \
  --node-count=2 \
  --ssh-public-key=<(op read "op://Vault名/アイテム名/public key")

現在私の環境ではSSHキーを1Passwordで管理しているため、1Password CLIを使用して公開鍵を取得しています。

Note: SSHキーの場所は op item list --categories "SSH Key" で確認できます。
Vault名・アイテム名は実際の値に置き換えてください。

  • SSHキーを1Passwordで管理するための設定参考はこちら

https://dev.classmethod.jp/articles/save-ssh-private-key-in-1password/

オプション 説明
--name クラスター名。.k8s.local で終わるとゴシップモード(Route53不要)
--state kOpsの状態を保存するS3バケット
--zones クラスターを作成するAZ
--topology private でマスター/ワーカーをプライベートサブネットに配置
--networking CNIプラグイン。calico はネットワークポリシーをサポート
--master-size マスターノードのインスタンスタイプ
--master-count マスターノードの数
--node-size ワーカーノードのインスタンスタイプ
--node-count ワーカーノードの数
--ssh-public-key ノードへのSSHアクセス用公開鍵

なお、従来のSSHキーファイルを使用する場合はMacOSの環境の場合以下のように指定します。

--ssh-public-key=~/.ssh/id_rsa.pub

Step 4: クラスターの確認とデプロイ

# 作成される構成を確認
aws-vault exec <profile-name> -- kops get cluster ${CLUSTER_NAME} -o yaml

# クラスターをデプロイ
aws-vault exec <profile-name> -- kops update cluster ${CLUSTER_NAME} --yes

# クラスターが準備完了になるまで待機(5〜10分程度)
aws-vault exec <profile-name> -- kops validate cluster --wait 10m

# kubeconfigに接続情報と認証情報を設定
aws-vault exec <profile-name> -- kops export kubecfg ${CLUSTER_NAME} --admin

# Kubernetesバージョンを確認
kubectl version

kops validate clusterコマンドの結果は以下のようになればOKです。

INSTANCE GROUPS
NAME				ROLE		MACHINETYPE	MIN	MAX	SUBNETS
control-plane-ap-northeast-1a	ControlPlane	t3.medium	1	1	ap-northeast-1a
nodes-ap-northeast-1a		Node		t3.medium	2	2	ap-northeast-1a

NODE STATUS
NAME			ROLE		READY
i-03xxxxxxxxxxxxxxx	node		True
i-09xxxxxxxxxxxxxxx	node		True
i-0axxxxxxxxxxxxxxx	control-plane	True

Your cluster container-insights.k8s.local is ready

Container Insightsの設定

Step 5: IAMポリシーの設定

kOps環境では、ワーカーノードのIAMロールにCloudWatch関連のポリシーを追加する必要があります。

変更前のロールは以下のカスタマーインラインポリシーが付与されています。

iam_1

{
    "Statement": [
        {
            "Action": [
                "autoscaling:DescribeAutoScalingInstances",
                "ec2:DescribeInstanceTypes",
                "ec2:DescribeInstances",
                "ec2:DescribeRegions",
                "ec2:ModifyNetworkInterfaceAttribute",
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:DescribeRepositories",
                "ecr:GetAuthorizationToken",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetRepositoryPolicy",
                "ecr:ListImages",
                "iam:GetServerCertificate",
                "iam:ListServerCertificates",
                "kms:GenerateRandom"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ],
    "Version": "2012-10-17"
}

ロールにAWS管理ポリシー CloudWatchAgentServerPolicy をアタッチします。

# クラスター設定を編集
aws-vault exec <profile-name> -- kops edit cluster ${CLUSTER_NAME}

spec: の中に以下を追加:

spec:
  externalPolicies:
    node:
      - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy

変更を適用:

aws-vault exec <profile-name> -- kops update cluster ${CLUSTER_NAME} --yes
# IAMポリシーのアタッチは即座に有効になるため、rolling-updateは不要の可能性あり
# aws-vault exec <profile-name> -- kops rolling-update cluster ${CLUSTER_NAME} --yes

ポリシーが追加されていますね!

iam_2

Step 6: cert-managerのインストール

CloudWatch AgentオペレーターはTLS証明書管理にcert-managerを必要とします。

# cert-managerをインストール
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.2/cert-manager.yaml

# インストール確認(Podがすべて Running になるまで待機)
kubectl get pods -n cert-manager

以下のような結果であればOKです。

NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-7b8b89f89d-9zdbk              1/1     Running   0          21s
cert-manager-cainjector-7f9fdd5dd5-w24hq   1/1     Running   0          21s
cert-manager-webhook-769f6b94cb-x5s6f      1/1     Running   0          21s

Step 7: CloudWatch Agent CRDのインストール

CRD(Custom Resource Definition)をインストールすることで、AmazonCloudWatchAgentというカスタムリソースが使えるようになり、CloudWatch AgentをKubernetesネイティブに管理できます。

curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/main/k8s-quickstart/cwagent-custom-resource-definitions.yaml | kubectl apply --server-side -f -

Step 8: CloudWatch Agentオペレーターのデプロイ

環境変数を設定してデプロイします。

# クラスター名とリージョンを設定
ClusterName='container-insights.k8s.local'
RegionName='ap-northeast-1'  # 適切なリージョンに変更

# オペレーターをデプロイ (※このコマンドは失敗しました)
curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/main/k8s-quickstart/cwagent-operator-rendered.yaml | sed 's/{{cluster_name}}/'${ClusterName}'/g;s/{{region_name}}/'${RegionName}'/g' | kubectl apply -f -

これを実行した際に以下のようなエラーが出ました。

error: error parsing STDIN: error converting YAML to JSON: yaml: invalid map key: map[interface {}]interface {}{"region_name":""}

原因確認

サンプルYAMLファイルの中身を確認してみます。

curl -s https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/main/k8s-quickstart/cwagent-operator-rendered.yaml | grep -n "region_name"

結果:

748:              value: {? {region_name: ''} : ''}
866:              value: {? {region_name: ''} : ''}
991:  config: "{\"agent\":{\"region\":\"{{region_name}}\"},..."
1108:  config: "{\"agent\":{\"region\":\"{{region_name}}\"},..."
1155:  config: "{\"agent\":{\"region\":\"{{region_name}}\"},..."

748行目と866行目に、テンプレート変数が壊れた形式 {? {region_name: ''} : ''} で記載されています。この形式はsedの置換パターン {{region_name}} にマッチしないため、YAMLパースエラーが発生しているようです。

解決策

壊れた形式を先に修正するsedを追加します。

# namespaceを削除(既に作成されている場合)
kubectl delete namespace amazon-cloudwatch
sleep 10

# 修正版でデプロイ
curl -s https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/main/k8s-quickstart/cwagent-operator-rendered.yaml | sed "s/{? {region_name: ''} : ''}/\"{{region_name}}\"/g" | sed 's/{{cluster_name}}/'${ClusterName}'/g;s/{{region_name}}/'${RegionName}'/g' | kubectl apply -f -

Step 9: デプロイの確認

# CloudWatch Agent Podの確認
kubectl get pods -n amazon-cloudwatch

CloudWatch AgentとFluent Bitが正常に動作していますね!

NAME                                                              READY   STATUS    RESTARTS   AGE
amazon-cloudwatch-observability-controller-manager-67fbc49sgpbn   1/1     Running   0          21s
cloudwatch-agent-m7m67                                            1/1     Running   0          7s
cloudwatch-agent-s9j2f                                            1/1     Running   0          7s
cloudwatch-agent-z25k5                                            1/1     Running   0          7s
fluent-bit-89lzg                                                  1/1     Running   0          22s
fluent-bit-mbqfs                                                  1/1     Running   0          22s
fluent-bit-pnj6v                                                  1/1     Running   0          22s
# DaemonSetの確認
kubectl get daemonset -n amazon-cloudwatch

cloudwatch-agentとfluent-bitが各ノードに配置されていることがわかります。

NAME                                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR              AGE
cloudwatch-agent                              3         3         3       3            3           kubernetes.io/os=linux     86s
cloudwatch-agent-windows                      0         0         0       0            0           kubernetes.io/os=windows   86s
cloudwatch-agent-windows-container-insights   0         0         0       0            0           kubernetes.io/os=windows   85s
dcgm-exporter                                 0         0         0       0            0           kubernetes.io/os=linux     86s
fluent-bit                                    3         3         3       3            3           kubernetes.io/os=linux     101s
fluent-bit-windows                            0         0         0       0            0           kubernetes.io/os=windows   100s
neuron-monitor                                0         0         0       0            0           kubernetes.io/os=linux     86s
# ログの確認
kubectl logs -n amazon-cloudwatch -l app.kubernetes.io/name=cloudwatch-agent

CloudWatch Agentのログが出力されていてエラーなどがなければ問題ないです。

CloudWatchコンソールで動作確認

Container Insightsが正しく設定されていれば、CloudWatchコンソールでクラスターのメトリクスを確認できます。

CI_1

サマリにデータが載っていますね!

確認手順

  1. AWSコンソールで CloudWatch を開く
  2. 左メニューから インサイトContainer Insights を選択
  3. リソース でクラスター container-insights.k8s.local を選択

クラスター全体のパフォーマンスモニタリングが可能です。

CI_3

確認できるビュー

さらに、以下のビューで各リソース詳細のパフォーマンスを確認できます。

ビュー 説明
クラスター クラスター全体のCPU/メモリ使用率、ノード数、Pod数
名前空間 Kubernetes Namespaceごとのリソース使用状況
ノード 各EC2インスタンス(Master/Worker)のリソース使用状況
Pod Kubernetes Podごとのリソース使用状況
コンテナ Pod内の個々のコンテナのリソース使用状況

CI_4

CI_5

CI_6

CI_7

CPUやメモリの使用状況に加えてコンテナ再起動数など固有のメトリクスが一覧で確認でき、これらへアラームの追加が可能になっており運用効率化に繋がります。

お片付け

Container Insightsを削除する場合

# CloudWatch Agentの削除
kubectl delete namespace amazon-cloudwatch

# cert-managerの削除(他で使用していない場合)
kubectl delete -f https://github.com/cert-manager/cert-manager/releases/download/v1.19.2/cert-manager.yaml

# IAMポリシーの削除(kops edit clusterで追加したexternalPolicies/additionalPoliciesを削除)
aws-vault exec <profile-name> -- kops edit cluster ${CLUSTER_NAME}
aws-vault exec <profile-name> -- kops update cluster ${CLUSTER_NAME} --yes

クラスター自体を削除する場合

# クラスターの削除(EC2、VPC、ELBなどすべてのリソースが削除されます)
aws-vault exec <profile-name> -- kops delete cluster ${CLUSTER_NAME} --yes

# State Store用S3バケットの削除(必要に応じて)
aws-vault exec <profile-name> -- aws s3 rb s3://${BUCKET_NAME} --force

まとめ

kOpsで構築したKubernetesクラスターでも、AWS Container Insightsを活用することで以下のような運用を実現できます。

  • クラスター全体のリソース使用状況を一元管理
  • 問題の早期発見とトラブルシューティングの効率化
  • コスト最適化のためのリソース分析

追加のIAMポリシー設定等は必要ですが、手順自体はシンプルで導入しやすいものかと思いました。
ノードの中身のパフォーマンスまで詳細に可視化できることに加え、そのままアラームまで設定可能な便利機能でした。
EKSやECSだけでなく、お手製のk8sクラスターにも使えるのは嬉しいですね。
この記事が誰かの参考になったら幸いです。お読みいただきありがとうございました!

参考リンク

この記事をシェアする

FacebookHatena blogX

関連記事