k8s.io/metrics/pkg/client/clientset/versioned を使ってPod で利用している Memory を確認する

kubectl top poddocker statsモリー使用量の違いは、メモリー使用量にPage Cache(active)が含まれているためですがメモリを基準にさまざまな制御を行う事ってありますよね。これはライブアップ実施後の確認の間に書いてランチを食べれていない。

はじめに

kubernetes API にアクセスする時には様々な方法がある。kubectlcurl などでも行う事ができる。でも、kubectl 使うことが一般的だとは思う。しかし、もう少し複雑な事をさせたいと思ったらのなら何かしらのプログラミング言語で実施したくなります。Kubernetes APIにアクセスするにはk8s.io/client-goを使うのはわりと自然な流れかと思います。今回、やりたいこととしてはkubernetes APIから取得したデーターを基にメモリの使用量を取得したいと思ってます。

さっそく、本題

今回は本当にお腹空いてる。

 kubectl top pod -n <ns> 

ちなみに詳細を知りたい場合には

kubectl  top pod -n <ns> -v9

などを記載しているといい感じになる。

今回は GitHub - kubernetes/metrics: Kubernetes metrics-related API types and clients を利用してメモリの使用量を確認したいと思います。最終的なコードはこちらになります。

package main

import (
        "fmt"
        "os"
        "path/filepath"

        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/client-go/tools/clientcmd"
        "k8s.io/client-go/util/homedir"
        metrics "k8s.io/metrics/pkg/client/clientset/versioned"
)

func main() {
        var kubeconfig string //empty, assuming inClusterConfig
        kubeconfig, ok := os.LookupEnv("KUBECONFIG")
        if !ok {
                kubeconfig = filepath.Join(homedir.HomeDir(), ".kube", "config")
        }
        config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
        if err != nil {
                panic(err)
        }

        mc, err := metrics.NewForConfig(config)
        if err != nil {
                panic(err)
        }
        podMetrics, err := mc.MetricsV1beta1().PodMetricses(metav1.NamespaceAll).List(metav1.ListOptions{})

        if err != nil {
                fmt.Println("Error:", err)
                return
        }

        for _, podMetric := range podMetrics.Items {
                podContainers := podMetric.Containers
                for _, container := range podContainers {
                        memQuantity, ok := container.Usage.Memory().AsInt64()
                        if !ok {
                                return
                        }
                        msg := fmt.Sprintf("Container Name: %s \n Memory usage: %d", container.Name, memQuantity)
                        fmt.Println(msg)
                }
        }
}

遊ぶ

環境情報

環境構築はとても大切です。kubeadmminikube など他にも様々な手段がある。が 今回は Kindを利用します。

$ go version
go version go1.14.5 linux/amd64
$ docker version                                                                                                                                                                                                                  4290ms
Client:
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.13.8
 Git commit:        afacb8b7f0
 Built:             Tue Jun 23 22:26:12 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          19.03.11
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.12
  Git commit:       77e06fd
  Built:            Mon Jun  8 20:24:59 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
$ kind --version # https://kind.sigs.k8s.io/docs/user/quick-start/
kind version 0.8.1

環境構築

クラスタ-の構築

$ kind create cluster --name metrics
Creating cluster "metrics" ...
 ✓ Ensuring node image (kindest/node:v1.18.2) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-metrics"
You can now use your cluster with:

kubectl cluster-info --context kind-metrics

Not sure what to do next? 😅  Check out https://kind.sigs.k8s.io/docs/user/quick-start/
# kubeconfig の書き込み
$ kind get kubeconfig --name metrics  > kubeconfig.yaml
# kubeconfing の確認
$ kubectl version  --kubeconfig=kubeconfig.yaml 
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:58:59Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.2", GitCommit:"52c56ce7a8272c798dbc29846288d7cd9fbae032", GitTreeState:"clean", BuildDate:"2020-04-30T20:19:45Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}

metrics-server の導入

観測用のPodのデプロイ

$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
nginx-f89759699-k2vc7   1/1     Running   0          39s

kubernetes v1.11からはmetrics serverを動かしてやればいいのですが いまいち上手く取得できないので こちらのIssue を参考にしたのがこちらです。

$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.7/components.yaml
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator configured
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader configured
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io unchanged
serviceaccount/metrics-server unchanged
deployment.apps/metrics-server configured
service/metrics-server configured
clusterrole.rbac.authorization.k8s.io/system:metrics-server configured
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server unchanged

実行

$  kubectl top pod -A 
NAMESPACE            NAME                                            CPU(cores)   MEMORY(bytes)
default              nginx-f89759699-k2vc7                           0m           3Mi
kube-system          coredns-66bff467f8-k85lw                        3m           8Mi
kube-system          coredns-66bff467f8-xlnz5                        3m           8Mi
kube-system          etcd-metrics-control-plane                      24m          55Mi
kube-system          kindnet-55z2v                                   2m           9Mi
kube-system          kube-apiserver-metrics-control-plane            41m          260Mi
kube-system          kube-controller-manager-metrics-control-plane   15m          39Mi
kube-system          kube-proxy-whtdr                                1m           12Mi
kube-system          kube-scheduler-metrics-control-plane            4m           15Mi
kube-system          metrics-server-697bddf786-55sq9                 1m           13Mi
local-path-storage   local-path-provisioner-bd4bb6b75-8qfzn          11m          9Mi

$ go run main.go
Container Name: coredns Memory usage: 9060352
Container Name: kube-proxy Memory usage: 13139968
Container Name: etcd Memory usage: 57958400
Container Name: kube-controller-manager Memory usage: 40906752
Container Name: local-path-provisioner Memory usage: 9605120
Container Name: kube-apiserver Memory usage: 273580032
Container Name: kube-scheduler Memory usage: 16199680
Container Name: coredns Memory usage: 8982528
Container Name: kindnet-cni Memory usage: 9945088
Container Name: nginx Memory usage: 3526656
Container Name: metrics-server Memory usage: 14118912

コード解説

は後で書くのと取得値がkubectl top pod と違う件はラーメン屋から帰ってきてから書きます。とりあえず、公開しておきます。

最終成果物

workspace_2020/blog/metrics at master · nwiizo/workspace_2020 · GitHub