1 メトリクスサーバーとは?
メトリクスサーバーは、Kubernetes クラスタ内のノードや Pod のリソース使用状況(CPU・メモリ使用率など)を収集するサーバです。収集したメトリクス(システムの状態や性能を数値で表したデータ)は、主に HPA(Horizontal Pod Autoscaler) や VPA(Vertical Pod Autoscaler) などのオートスケーリング機能で利用され、Pod の数やリソース量を自動的に調整するために使われます。
2 検証環境
2.1 ネットワーク構成
検証環境は、VMware Workstation Pro上に構築した3台の仮想マシンでKubernetesクラスタを構成しています。各仮想マシンはブリッジ接続により、PCと同じネットワーク(192.168.1.0/24)に接続されています。
一方、10.244.0.0/16 は、CalicoのCNIプラグインによってクラスタ内に作成されるPodネットワークです。各Podにはこのアドレス帯からIPアドレスが割り当てられ、異なるノード上のPod同士が相互に通信する際に使用されます。Calicoは各ノードに経路を設定することで、Pod間通信を透過的に実現しています。
+--- control ---+ +--- worker1 ---+ +--- worker2 ---+
|AlmaLinux 10.2 | |AlmaLinux 10.2 | |AlmaLinux 10.2 |
| | | | | |
| Pod | | Pod | | Pod |
| | | | | | | | |
| 10.244.x.0/24 | | 10.244.y.0/24 | | 10.244.z.0/24 |
| ------------- | | ------------- | | ------------- |
| | | | | |
+-------+-------+ +-------+-------+ +-------+-------+
|.19 |.20 |.22
| | |
| 192.168.1.0/24 | |
+--------------------------------------------------------+
| VMware Workstation Pro(Bridged networking) |
+--------------------------------------------------------+
|
+---------------+
| |
| PC |
| |
+---------------+
それぞれの役割は以下のとおりです。
1台をコントロールノード、2台をワーカーノードとして使用します。
| ホスト名 | 名称 | 役割 |
|---|---|---|
| control | コントロールノード | クラスタ(control、worker1、worker2)の状態を管理し、Pod をどのノードで実行するかを決定するノード |
| worker1 | ワーカーノード | Pod を実行するノード |
| worker2 | ワーカーノード | Pod を実行するノード |
2.2 ソフトウェアのバージョン
各ノードのAlmaLinuxバージョンは以下のとおりです。
[root@control ~]# cat /etc/redhat-release
AlmaLinux release 10.2 (Lavender Lion)
各ノードのカーネルバージョンは以下のとおりです。
[root@control ~]# uname -r
6.12.0-211.7.3.el10_2.x86_64
Kubernetesのバージョンは以下のとおりです。
[root@contol ~]# kubectl version
Client Version: v1.36.3
Kustomize Version: v5.8.1
Server Version: v1.36.3
2.3 ノードのリソース
各ノードには4GBのメモリを割り当てています。
[root@control ~]# free -h
total used free shared buff/cache available
Mem: 3.6Gi 1.3Gi 1.0Gi 5.8Mi 1.5Gi 2.3Gi
Swap: 0B 0B 0B
各ノードは 4コアのCPU(4 vCPU) を搭載しています。
[root@control ~]# lscpu -xe
CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE
0 0 0 0 0:0:0:0 yes
1 0 1 1 1:1:1:1 yes
2 0 2 2 2:2:2:2 yes
3 0 3 3 3:3:3:3 yes
lscpuコマンドの詳しい使い方は、以下のページをご覧ください。
3 事前準備
3.1 検証ツールのインストール
CPU負荷をあげる検証をするため、stress-ngパッケージをインストールします。
[root@control ~]# dnf -y install stress-ng
stress-ngコマンドのバージョンを確認します。
[root@contol ~]# stress-ng --version
stress-ng, version 0.19.03 (gcc 14.3.1, x86_64 Linux 6.12.0-211.7.3.el10_2.x86_64) ??
stress-ngコマンドの使い方は、以下を参照してください。
3.2 Kubelet のサーバ証明書の再作成
Metrics Server は、メトリクスを取得するために、各ノード上で動作している Kubelet に対して HTTPS 接続を行います。
このとき、Kubelet が使用するサーバ証明書には、デフォルトでは自身のノード IP アドレスが Subject Alternative Name(SAN)として設定されていません。
一方、Metrics Server は Kubelet から送信されたサーバ証明書を検証する際、接続先として指定した IP アドレスが証明書の SAN に含まれているかを確認します。しかし、Kubelet のサーバ証明書の SAN にノード IP アドレスが設定されていないため、証明書検証に失敗します。
この問題を解決するため、Kubelet のサーバ証明書を再発行します。再発行することで、サーバ証明書の SAN に各ノードの IP アドレスが設定され、Metrics Server は Kubelet の証明書を正しく検証できるようになります。
3.2.1 全てのノードで実施
まず、設定変更に備えて Kubelet の設定ファイルをバックアップします。
[root@control ~]# cp /var/lib/kubelet/config.yaml /var/lib/kubelet/config.yaml.org
kubeletの設定ファイルを編集します。
[root@control ~]# vi /var/lib/kubelet/config.yaml
設定ファイルの末尾に serverTLSBootstrap: true を追加します。この設定を有効にすると、Kubelet はサーバ証明書の Certificate Signing Request(CSR)を Kubernetes API Server に送信し、Kubernetes CA からサーバ証明書を取得できるようになります。
[root@control ~]# diff -Nur /var/lib/kubelet/config.yaml.org /var/lib/kubelet/config.yaml
--- /var/lib/kubelet/config.yaml.org 2026-08-03 20:20:36.010789515 +0900
+++ /var/lib/kubelet/config.yaml 2026-08-03 20:25:53.212588088 +0900
@@ -46,3 +46,4 @@
streamingConnectionIdleTimeout: 0s
syncFrequency: 0s
volumeStatsAggPeriod: 0s
+serverTLSBootstrap: true
設定を反映するため、Kubelet を再起動します。
[root@control ~]# systemctl restart kubelet
3.2.2 コントロールノードで実施
Kubelet を再起動すると、各ノードの Kubelet は CSR(Certificate Signing Request)を Kubernetes API Server に送信します。CSR の状態を確認すると、CONDITION 列が Pending なので、CSR がまだ承認されておらず、サーバ証明書が発行されていない状態を示しています。
[root@control ~]# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-bdgn5 6s kubernetes.io/kubelet-serving system:node:worker2 <none> Pending
csr-ds5zx 8s kubernetes.io/kubelet-serving system:node:control <none> Pending
csr-n8k2p 12s kubernetes.io/kubelet-serving system:node:worker1 <none> Pending
kubectl certificate approve コマンドを実行して CSR を承認します。承認されると、Kubernetes CA の秘密鍵を使用して CSR に署名し、Kubelet のサーバ証明書を発行します。
[root@control ~]# kubectl certificate approve csr-bdgn5
certificatesigningrequest.certificates.k8s.io/csr-bdgn5 approved
[root@control ~]# kubectl certificate approve csr-ds5zx
certificatesigningrequest.certificates.k8s.io/csr-ds5zx approved
[root@control ~]# kubectl certificate approve csr-n8k2p
certificatesigningrequest.certificates.k8s.io/csr-n8k2p approved
承認後、CSR の状態を確認します。Approved,Issued と表示されれば、Kubernetes CA によってサーバ証明書が発行され、各ノードの Kubelet が新しいサーバ証明書を取得したことを示しています。
[root@control ~]# kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-bdgn5 4m9s kubernetes.io/kubelet-serving system:node:worker2 <none> Approved,Issued
csr-ds5zx 4m11s kubernetes.io/kubelet-serving system:node:control <none> Approved,Issued
csr-n8k2p 4m15s kubernetes.io/kubelet-serving system:node:worker1 <none> Approved,Issued
3.2.3 Kubelet サーバ証明書の確認
Kubelet のサーバ証明書に、各ノードの IP アドレスが Subject Alternative Name(SAN)として設定されていることを確認します。serverTLSBootstrap を有効化し、CSR を承認すると、Kubelet は Kubernetes CA によって署名されたサーバ証明書を取得します。この証明書には、Kubelet が待ち受けるノードの DNS 名および IP アドレスが SAN として設定されます。
まず、コントロールノードで Kubelet のサーバ証明書を確認します。
[root@control ~]# openssl x509 -in /var/lib/kubelet/pki/kubelet-server-current.pem -text -noout | grep -A5 "Subject Alternative Name"
X509v3 Subject Alternative Name:
DNS:control, IP Address:192.168.1.15
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
8c:ad:a9:af:7e:16:0b:21:91:69:94:0f:fd:40:ea:49:57:4b:
75:d5:94:fe:28:89:e0:bf:a6:b2:96:f9:a1:fb:4d:5e:0f:7c:
出力結果から、コントロールノードのホスト名である control と IP アドレス 192.168.1.15 が SAN に設定されていることを確認できます。
次に、ワーカノード(worker1)で Kubelet のサーバ証明書を確認します。
[root@worker1 ~]# openssl x509 -in /var/lib/kubelet/pki/kubelet-server-current.pem -text -noout | grep -A5 "Subject Alternative Name"
X509v3 Subject Alternative Name:
DNS:worker1, IP Address:192.168.1.16
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
7e:f1:47:49:8c:fe:b0:b2:05:3b:5f:2d:12:60:97:48:d5:93:
61:f9:58:92:72:00:e1:8b:f4:3a:73:74:17:7b:fc:c4:90:48:
同様に、ワーカノード(worker2)でも Kubelet のサーバ証明書を確認します。
[root@worker2 ~]# openssl x509 -in /var/lib/kubelet/pki/kubelet-server-current.pem -text -noout | grep -A5 "Subject Alternative Name"
X509v3 Subject Alternative Name:
DNS:worker2, IP Address:192.168.1.17
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
8c:e3:f8:57:e3:7b:0c:0d:45:89:47:0b:79:1f:bf:02:d5:e5:
28:4b:90:db:5a:76:92:4c:f7:9d:b4:bc:79:5b:72:99:50:83:
4 メトリクスサーバのインストール
(1) リポジトリの追加
メトリクスサーバーのチャートが公開されているリポジトリを、Helmで利用できるように追加します。
[root@control ~]# helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server
"metrics-server" has been added to your repositories
helm コマンドの詳しい使い方は、以下のページをご覧ください。
追加したリポジトリの一覧を確認します。
[root@control ~]# helm repo list
NAME URL
metrics-server https://kubernetes-sigs.github.io/metrics-serve
ローカルにキャッシュされているチャート情報を最新の状態に更新します。この操作を行わないと、最新のチャート情報がローカルに反映されず、最新バージョンの検索や取得ができない場合があるため、事前に実行します。
[root@contol ~]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "metrics-server" chart repository
Update Complete. ?Happy Helming!?
(2) チャートのインストール
メトリクスサーバーのHelmチャートをクラスタにインストールします。このとき、kube-system 名前空間にデプロイするよう指定します。
[root@control ~]# helm install metrics-server metrics-server/metrics-server --namespace kube-system
NAME: metrics-server
LAST DEPLOYED: Tue Aug 4 14:13:06 2026
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
***********************************************************************
* Metrics Server *
***********************************************************************
Chart version: 3.13.1
App version: 0.8.1
Image tag: registry.k8s.io/metrics-server/metrics-server:v0.8.1
***********************************************************************
Podの状態を確認します。コマンドを実行すると、出力結果の一覧に metrics-server のPodが表示され、正常に動作していることを確認できます(この実行例では、一番下の行)。
[root@control ~]# kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-58f68d56d9-7mh9c 1/1 Running 0 3h47m 10.244.42.194 control <none> <none>
calico-node-bw49k 1/1 Running 0 3h38m 192.168.1.16 worker1 <none> <none>
calico-node-pmt6s 1/1 Running 0 3h38m 192.168.1.17 worker2 <none> <none>
calico-node-x9gmw 1/1 Running 0 3h47m 192.168.1.15 control <none> <none>
coredns-589f44dc88-bm7dp 1/1 Running 0 3h50m 10.244.42.193 control <none> <none>
coredns-589f44dc88-pgrks 1/1 Running 0 3h50m 10.244.42.195 control <none> <none>
etcd-control 1/1 Running 0 3h50m 192.168.1.15 control <none> <none>
kube-apiserver-control 1/1 Running 0 3h50m 192.168.1.15 control <none> <none>
kube-controller-manager-control 1/1 Running 0 3h50m 192.168.1.15 control <none> <none>
kube-proxy-hqvsc 1/1 Running 0 3h38m 192.168.1.16 worker1 <none> <none>
kube-proxy-nnnl6 1/1 Running 0 3h38m 192.168.1.17 worker2 <none> <none>
kube-proxy-wrgcs 1/1 Running 0 3h50m 192.168.1.15 control <none> <none>
kube-scheduler-control 1/1 Running 0 3h50m 192.168.1.15 control <none> <none>
metrics-server-5846d89996-lf78z 1/1 Running 0 36s 10.244.235.129 worker1 <none> <none>
5 動作確認
(1) 初期状態の確認
ノードのリソース使用状況を確認します。
[root@control ~]# kubectl top node
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
control 159m 3% 1949Mi 55%
worker1 46m 1% 1029Mi 29%
worker2 46m 1% 972Mi 27%
(2) CPU0 に負荷をかける
CPU0 に対して、CPU 使用率を高める負荷(CPU 負荷)をかけます。
[root@control ~]# stress-ng -c 1 --taskset 0 -q &
[1] 75755
CPU使用率を確認すると、CPU0(PSR列が 0)の CPU使用率が96%になっていることが分かります。
[root@control ~]# ps -C stress-ng,stress-ng-cpu -o comm,pid,ppid,%cpu,psr,wchan
COMMAND PID PPID %CPU PSR WCHAN
stress-ng 75755 3885 0.0 0 do_wait
stress-ng-cpu 75756 75755 96.0 0 -
control ノードの CPU 使用率を確認すると、28% に増加していることが分かります。
[root@control ~]# kubectl top node
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
control 1138m 28% 1989Mi 56%
worker1 54m 1% 1045Mi 29%
worker2 52m 1% 987Mi 28%
(3) CPU1 に負荷をかける
CPU1 に対して、CPU 使用率を高める負荷(CPU 負荷)をかけます。
[root@control ~]# stress-ng -c 1 --taskset 1 -q &
[2] 76990
CPU使用率を確認すると、CPU1(PSR列が 0)の CPU使用率が102%になっていることが分かります。
[root@control ~]# ps -C stress-ng,stress-ng-cpu -o comm,pid,ppid,%cpu,psr,wchan
COMMAND PID PPID %CPU PSR WCHAN
stress-ng 75755 3885 0.0 0 do_wait
stress-ng-cpu 75756 75755 98.9 0 -
stress-ng 76990 3885 0.0 1 do_wait
stress-ng-cpu 76991 76990 102 1 -
control ノードの CPU 使用率を確認すると、53% に増加していることが分かります。
[root@control ~]# kubectl top node
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
control 2137m 53% 2005Mi 56%
worker1 57m 1% 1045Mi 29%
worker2 63m 1% 987Mi 28%
(4) CPU2 に負荷をかける
CPU2 に対して、CPU 使用率を高める負荷(CPU 負荷)をかけます。
[root@control ~]# stress-ng -c 1 --taskset 2 -q &
[3] 77977
CPU使用率を確認すると、CPU2(PSR列が 0)の CPU使用率が102%になっていることが分かります。
[root@control ~]# ps -C stress-ng,stress-ng-cpu -o comm,pid,ppid,%cpu,psr,wchan
COMMAND PID PPID %CPU PSR WCHAN
stress-ng 75755 3885 0.0 0 do_wait
stress-ng-cpu 75756 75755 99.0 0 -
stress-ng 76990 3885 0.0 1 do_wait
stress-ng-cpu 76991 76990 99.6 1 -
stress-ng 77977 3885 0.0 2 do_wait
stress-ng-cpu 77978 77977 102 2 -
control ノードの CPU 使用率を確認すると、78% に増加していることが分かります。
[root@control ~]# kubectl top node
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
control 3140m 78% 2021Mi 57%
worker1 81m 2% 1044Mi 29%
worker2 75m 1% 987Mi 28%
(5) CPU3 に負荷をかける
CPU3 に対して、CPU 使用率を高める負荷(CPU 負荷)をかけます。
[root@control ~]# stress-ng -c 1 --taskset 3 -q &
[4] 78856
CPU 使用率を確認すると、すべての CPU コアがほぼ 100% の状態で動作していることが分かります。
[root@control ~]# ps -C stress-ng,stress-ng-cpu -o comm,pid,ppid,%cpu,psr,wchan
COMMAND PID PPID %CPU PSR WCHAN
stress-ng 75755 3885 0.0 0 do_wait
stress-ng-cpu 75756 75755 98.8 0 -
stress-ng 76990 3885 0.0 1 do_wait
stress-ng-cpu 76991 76990 99.0 1 -
stress-ng 77977 3885 0.0 2 do_wait
stress-ng-cpu 77978 77977 98.9 2 -
stress-ng 78856 3885 0.1 3 do_wait
stress-ng-cpu 78857 78856 90.5 3 -
control ノードの CPU 使用率を確認すると、99% に増加していることが分かります。
[root@control ~]# kubectl top node
NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%)
control 3998m 99% 2037Mi 57%
worker1 92m 2% 1045Mi 29%
worker2 84m 2% 987Mi 28%
(6) あと始末
起動した stress-ng のプロセスを終了します。
[root@control ~]# jobs
[1] 実行中 stress-ng -c 1 --taskset 0 -q &
[2] 実行中 stress-ng -c 1 --taskset 1 -q &
[3]- 実行中 stress-ng -c 1 --taskset 2 -q &
[4]+ 実行中 stress-ng -c 1 --taskset 3 -q &
[root@control ~]# kill %1
[root@control ~]# kill %2
[root@control ~]# kill %3
[root@control ~]# kill %4
6 まとめ
kubectl top node で表示される CPU(cores) は、CPU 使用量をコア数換算で表した値です。1000m が CPU 1コア分に相当します。
本環境は 4 コア構成のため、CPU(cores) が 3998m の場合は、約 4 コアすべてを使用している状態を示します。
CPU(%) は、ノードが持つ CPU 全体に対する使用率を示します。4 コアすべてに負荷をかけた結果、CPU(%) は約 99% となり、ノード全体の CPU がほぼ使い切られていることを確認できました。
今回の実験では、stress-ng を使用して CPU 0~3 に対して段階的に負荷をかけ、その変化を kubectl top node で確認しました。負荷の増加に合わせて CPU 使用量(CPU(cores)、CPU(%))が増加したことから、Metrics Server が Kubelet からメトリクスを正常に取得できていることを確認できました。
また、負荷をかけた control ノードのみ CPU 使用率が上昇し、worker ノードの CPU 使用率には大きな変化がないことも確認できました。