kOpsで構築したKubernetesクラスターにContainer Insightsを設定する
はじめに
こんにちは、コンサルティング部のぐっさんです。
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)
参考
料金について
Container Insightsには2つの料金体系があります。
| 項目 | Standard | Enhanced Observability(拡張可観測性) |
|---|---|---|
| 課金単位 | CloudWatchメトリクス数 | 観測データ数 |
| メトリクス粒度 | クラスター/ノード/Pod/サービス | + ワークロード/コンテナレベル |
| 特徴 | 基本的な監視 | 詳細なトラブルシューティング、コンテナ単位の分析 |
現在Quick Startで導入されるCloudWatch Agentはバージョン1.300035.0以降のため、自動的にEnhanced Observabilityが適用される想定です。
Note: コンテナログは別途CloudWatch Logs料金(取り込み・保存)が発生します。検証後は不要なリソースを削除してコストを抑えましょう。
詳細は料金ページを参照してください。
前提条件
本記事の手順を実行する前に、以下が必要です。
- 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) |
アーキテクチャ
簡単な構成イメージです。

kOpsクラスターの構築
Note: 本記事では、AWS認証情報を平文で保存しないために
aws-vaultを使用しています。以降の手順では、必要な部分でaws-vault exec <profile-name> --を各コマンドの前に付与していますが環境に応じて読み替えてください。aws-vault exec <profile-name> -- kops create cluster ...
参考
なお、kOpsでのクラスター構築については以下の記事でチュートリアルを試しているので基本の構築方法はこちらを参照ください。本記事では、作成時のコマンドのみ記載し詳細までは触れません。
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で管理するための設定参考はこちら
| オプション | 説明 |
|---|---|
--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関連のポリシーを追加する必要があります。
変更前のロールは以下のカスタマーインラインポリシーが付与されています。

{
"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
ポリシーが追加されていますね!

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コンソールでクラスターのメトリクスを確認できます。

サマリにデータが載っていますね!
確認手順
- AWSコンソールで CloudWatch を開く
- 左メニューから インサイト → Container Insights を選択
- リソース でクラスター
container-insights.k8s.localを選択
クラスター全体のパフォーマンスモニタリングが可能です。

確認できるビュー
さらに、以下のビューで各リソース詳細のパフォーマンスを確認できます。
| ビュー | 説明 |
|---|---|
| クラスター | クラスター全体のCPU/メモリ使用率、ノード数、Pod数 |
| 名前空間 | Kubernetes Namespaceごとのリソース使用状況 |
| ノード | 各EC2インスタンス(Master/Worker)のリソース使用状況 |
| Pod | Kubernetes Podごとのリソース使用状況 |
| コンテナ | Pod内の個々のコンテナのリソース使用状況 |




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クラスターにも使えるのは嬉しいですね。
この記事が誰かの参考になったら幸いです。お読みいただきありがとうございました!









