この記事は Kubernetes Advent Calendar 2016 の 15 日目の記事です. この記事では Kubernetes でのメトリクスを監視する方法について考えてみます.
Kubernetes を利用する際に気にすべきメトリクスは, Kubernetes クラスタの土台となるシステムのメトリクス, クラスタ自体のメトリクス, そしてクラスタ上で動作するアプリケーションのメトリクスに分類することができます. この記事ではこれらのメトリクスを Prometheus を利用して監視する方法について考えていきます.
なお, この記事の検証には coreos-kubernetes を利用して Vagrant 上に Kubernetes クラスタを構築しています. また, Kubernetes と Prometheus のバージョンは下記のとおりです.
プロダクト | バージョン |
---|---|
Kubernetes | v1.4.6 |
Prometheus | v1.4.0 |
また, Prometheus 自体は監視対象の Kubernetes クラスタ上に構築するものとします.
Prometheus の構築
始めに Kubernetes クラスタ上に Prometheus を構築します.
$ kubectl create -f https://raw.githubusercontent.com/kkohtaka/kubernetes-metrics/master/prometheus/service.yml
$ kubectl create -f https://raw.githubusercontent.com/kkohtaka/kubernetes-metrics/master/prometheus/deployment.yml
$ kubectl create -f https://raw.githubusercontent.com/kkohtaka/kubernetes-metrics/master/prometheus/configmap.yml
検証に利用した Kubernetes リソースは次のとおりです.
Service
kkohtaka/kubernetes-metrics/prometheus/service.yml
Kubernetes クラスタ内に構築した Prometheus に外部からアクセスするために NodePort タイプの Service を作成します. これにより http://${NODE_IP_ADDRESS}:30090
のような URL で Prometheus にアクセスできるようにします.
Deployment
kkohtaka/kubernetes-metrics/prometheus/deployment.yml
Prometheus の Pod をデプロイするためのリソースです.
ConfigMap
kkohtaka/kubernetes-metrics/prometheus/configmap.yml
Prometheus の設定ファイルを Pod から読めるように ConfigMap として作成します.
特に注目すべきなのは設定ファイル中のサービスディスカバリに関する設定です. <scrape_config>
に <kubernetes_sd_config>
を記述することで Prometheus が kube-apiserver を通じてクラスタに状態変化 (Pod の追加など) を監視するようになり, Kubernetes の Pod や Service がエクスポートするメトリクスなど収集するようになります.
設定ファイルの記述の仕方は追って説明します.
システムのメトリクス
続いて Kubernetes クラスタの土台となるシステムのメトリクスを監視する方法について考えてみます. 今回はシステムのメトリクスのうち, ホストマシンのメトリクスの取得には Node exporter を利用し, コンテナのメトリクスの取得には cAdvisor を利用してみようと思います.
ホストマシンのシステムメトリクス
Node exporter は CPU やメモリの使用量など, ホストマシンのメトリクスをエクスポートするための Prometheus の公式なツールです. Prometheus からメトリクスを収集する場合には, 各ホストマシン一台につき一つの Node exporter が動作することが必要なため, Kubernetes クラスタ上では DaemonSet としてデプロイすることにします. これにより一つの Node (=ホストマシン) につき一つの Node expoter プロセスを実行することができます.
この検証では次のような DaemonSet を利用しています.
kkohtaka/kubernetes-metrics/node-exporter/daemonset.yml
$ kubectl create -f https://raw.githubusercontent.com/kkohtaka/kubernetes-metrics/master/node-exporter/daemonset.yml
DaemonSet によりデプロイされた Node exporter の Pod で取得したメトリクスを収集するためには, Prometheus 側の設定を行う必要があります. 次の例では Pod からエクスポートされたメトリクスを収集するように設定しています.
# /etc/prometheus.yml
# ...省略...
scrape_configs:
# ...省略...
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: (.+):(?:\d+);(\d+)
replacement: ${1}:${2}
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
# ...省略...
上記のような設定を Prometheus に施した上で, PodTemplateSpec の metadata に次のような annotation を記述すると, Pod がメトリクスをエクスポートするポートとパスを指定することができます.
# ...省略...
template:
metadata:
# ...省略...
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '9100'
prometheus.io/path: /metrics
spec:
containers:
- name: node-exporter
image: prom/node-exporter:v0.13.0
# ...省略...
Prometheus が Node exporter から収集しているメトリクスの一覧は次のようなコマンドで確認できます.
$ curl -g "http://${NODE_IP_ADDRESS}:30090/api/v1/series?match[]={app=\"node-exporter\"}" \
| jq -r '.data[].__name__' \
| sort \
| uniq
...
node_boot_time
node_context_switches
node_cpu
node_disk_bytes_read
node_disk_bytes_written
node_disk_io_now
node_disk_io_time_ms
node_disk_io_time_weighted
node_disk_read_time_ms
node_disk_reads_completed
...
コンテナのシステムメトリクス
コンテナのシステムメトリクスの取得には cAdvisor が有名なのでこれを利用してみたいと思います. Kubernetes の場合, cAdvisor は Kubelet に組み込まれているため cAdvisor 自体を新たに導入する必要はありません.
また, cAdvisor の取得したメトリクスを Prometheus で収集するためには次のような記述を Prometheus の設定ファイルに追加します.
# /etc/prometheus.yml
# ...省略...
scrape_configs:
# ...省略...
- job_name: 'kubernetes-nodes'
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
# ...省略...
これにより各 Node に配置されている Kubelet を通じて, cAdvisor により取得されたメトリクスを Prometheus が収集するようになります.
$ curl -g "http://${NODE_IP_ADDRESS}:30090/api/v1/series?match[]={container_name=\"heapster\"}" \
| jq -r '.data[].__name__' \
| sort \
| uniq
...
container_cpu_cfs_periods_total
container_cpu_cfs_throttled_periods_total
container_cpu_cfs_throttled_seconds_total
container_cpu_system_seconds_total
container_cpu_usage_seconds_total
container_cpu_user_seconds_total
container_fs_inodes_free
container_fs_inodes_total
container_fs_io_current
container_fs_io_time_seconds_total
...
Kubernetes クラスタのメトリクス
クラスタのメトリクスの取得には kube-state-metrics を利用することにします.
この検証では次のような Deployment を利用しています.
kkohtaka/kubernetes-metrics/kube-state-metrics/deployment.yml
$ kubectl create -f https://raw.githubusercontent.com/kkohtaka/kubernetes-metrics/master/kube-state-metrics/deployment.yml
kube-state-metrics の Pod が取得したメトリクスを収集するための Prometheus 側の設定は, Node exporter の利用よるシステムメトリクスの収集時に設定したもので問題ありません. また, kube-state-metrics の PodTemplateSpec にも Node exporter の場合と同様に次のような設定が必要です.
# ...省略...
template:
metadata:
# ...省略...
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '8080'
spec:
containers:
- name: kube-state-metrics
image: gcr.io/google_containers/kube-state-metrics:v0.3.0
ports:
- containerPort: 8080
# ...省略...
Prometheus が kube-state-metrics から収集しているメトリクスの一覧は次のようなコマンドで確認できます.
$ curl -g "http://${NODE_IP_ADDRESS}:30090/api/v1/series?match[]={app=\"kube-state-metrics\"}" \
| jq -r '.data[].__name__' \
| sort \
| uniq
...
kube_deployment_metadata_generation
kube_deployment_spec_paused
kube_deployment_spec_replicas
kube_deployment_status_observed_generation
kube_deployment_status_replicas
kube_deployment_status_replicas_available
kube_deployment_status_replicas_unavailable
kube_deployment_status_replicas_updated
kube_node_info
kube_node_spec_unschedulable
...
アプリケーションのメトリクス
最後にアプリケーションのメトリクスの監視について考えます. この場合は監視対象のアプリケーションが次のいずれかの状態にあるかで対応方法が変わってきます.
- アプリケーションが Prometheus 形式のメトリクスのエクスポートをサポートしている
- メトリクスのエクスポートをサポートしていないが, 改修することができる
- メトリクスのエクスポートをサポートしておらず, 改修することもできない
メトリクスのエクスポートをサポートしている場合
Etcd や SkyDNS などはアプリケーションそのものが Prometheus 形式のメトリクスエクスポートをサポートしているため, 上述した Node expoter や kube-state-metrics と同様の方法でメトリクスを収集することができます.
次の Deployment の例では Etcd のメトリクス収集を設定しています.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: etcd
spec:
replicas: 1
template:
metadata:
labels:
app: etcd
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '2379'
prometheus.io/metrics: /metrics
spec:
containers:
- name: etcd
image: quay.io/coreos/etcd:v3.0.15
args:
- etcd
- -listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001
- -advertise-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001
ports:
- name: etcd
containerPort: 2379
protocol: TCP
Prometheus が Etcd から収集しているメトリクスの一覧は次のようなコマンドで確認できます.
$ curl -g "http://${NODE_IP_ADDRESS}:30090/api/v1/series?match[]={app=\"etcd\"}" \
| jq -r '.data[].__name__' \
| sort \
| uniq
...
etcd_disk_backend_commit_duration_seconds_bucket
etcd_disk_backend_commit_duration_seconds_count
etcd_disk_backend_commit_duration_seconds_sum
etcd_disk_wal_fsync_duration_seconds_bucket
etcd_disk_wal_fsync_duration_seconds_count
etcd_disk_wal_fsync_duration_seconds_sum
etcd_network_client_grpc_received_bytes_total
etcd_network_client_grpc_sent_bytes_total
etcd_server_has_leader
etcd_server_leader_changes_seen_total
...
アプリケーションを改修することができる場合
アプリケーションが Prometheus 形式のメトリクスのエクスポートをサポートしていないものの, 手を入れて改修することが可能である場合には, Prometheus のクライアントライブラリを利用して, アプリケーションにメトリクスのエクスポート機能を実装することも可能です.
クライアントライブラリは多数のプログラミング言語向けのものが提供されているため, ほとんどの場合で対応が可能であると考えられます.
アプリケーションを改修することができない場合
アプリケーションに手を入れることができない場合には, アプリケーションとは異なるプログラムを用意してアプリケーションを監視させ, さらにそのプログラムに Prometheus 形式のメトリクスをエクスポートさせるというアプローチが可能な場合があります. Prometheus ではこのようなプログラムを Exporter と呼んでいます.
すでに多数の Exporter がサードパーティから提供されており, その一覧がここにあります.
また, 目的のアプリケーションの Exporter が提供されていない場合でも, 上述した Prometheus のクライアントライブラリを利用することで Exporter を開発することも可能です.
次の Deployment の例では Exporter を利用して Apache HTTP Server のメトリクス収集を設定しています.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: apache
spec:
replicas: 1
template:
metadata:
labels:
app: apache
annotations:
prometheus.io/scrape: 'true'
prometheus.io/port: '9117'
prometheus.io/path: /metrics
spec:
containers:
- name: apache-exporter
image: jecnua/apache-exporter
- name: apache
image: httpd:2.4
ports:
- name: http
containerPort: 80
protocol: TCP
volumeMounts:
- name: config-volume
mountPath: /usr/local/apache2/conf
# ...省略...
Expoter を通じて Prometheus が Apache HTTP Server から収集するメトリクスは次のようなコマンドで確認できます.
$ curl -g "http://${NODE_IP_ADDRESS}:30090/api/v1/series?match[]={app=\"apache\"}" \
| jq -r '.data[].__name__' \
| sort \
| uniq
...
apache_accesses_total
apache_connections
apache_exporter_scrape_failures_total
apache_scoreboard
apache_sent_kilobytes_total
apache_up
apache_uptime_seconds_total
apache_workers
...
まとめ
Prometheus を利用して Kubernetes の様々なレイヤーにおけるメトリクスを収集することができました. 各レイヤーでメトリクスを取得するために利用したツールや手法は次の表のとおりです.
対象レイヤー | メトリクス取得のためのツール・手法
--- | --- | ---
システム (ホストマシン) | Node expoter + DaemonSet
システム (コンテナ) | cAdvisor (Kubelet)
Kubernetes クラスタ | kube-state-metrics
アプリケーション (Prometheus 対応) | そのまま取得可能
アプリケーション (Prometheus 未対応, 改修可) | Prometheus クライアントライブラリで実装
アプリケーション (Prometheus 未対応, 改修不可) | Prometheus Exporter を利用
メトリクスを監視するというタイトルで記事を書き始めましたが, メトリクスを収集するところまでで終わってしまいました. 次は今回収集したメトリクスをどのように可視化するかについてまとめたいと思います.