サービスが期待通りに動作することを保証するためにモニタリングは重要です。Kubernetes 上で動作するアプリケーションのモニタリングには OSS ( Prometheus など) 、SaaS ( Datadog など )、プラットフォームのコンソール ( GCP など) を使う方法があります。

プラットフォームに縛られないモニタリング環境を構築したいので、本記事ではモニタリング用の OSS である Prometheus と Grafana を使って Kubernetes クラスタとクラスタ上で動作するアプリケーションをモニタリングするダッシュボードを構築する方法を紹介します。

目次

本記事で構築するモニタリング環境

下図のような、クラスタの稼働状況とアプリケーションのパフォーマンスを監視するモニタリング環境を作ります。

使用するツール

Prometheus

Prometheus はシステムやシステム上で動作するアプリケーションの監視ツールです。導入が簡単かつ、様々なツールと連携して監視用のメトリクスを収集可能な点が特徴です。CNCFGraduated Project で、開発が盛んで広く使われています

Grafana

Grafana は時系列データの可視化ツールです。Prometheus,ElasticSearch, 各種DBなど様々なツールのデータの可視化や、データを元に通知を飛ばす事が可能です

Helm

Helm は Kubernetesのパッケージマネージャです。Kubernetes のリソースを一纏めにして1つのアプリケーションのように扱うことが可能です。helm/charts で公式で提供されているパッケージ(これをChart と呼びます)の一覧を見ることができます。

環境構築

下記ツールをインストールしてください。

Prometheus と Grafana をセットアップ

クラスタに Helm をインストール

helm init を実行します。kubectlが参照しているクラスタにhelmの利用に必要なリソースがデプロイされます。

> helm init
> kubectl get po,deploy,svc  -n kube-system -l name=tiller

NAME                                READY   STATUS    RESTARTS   AGE
pod/tiller-deploy-c48485567-jf82k   1/1     Running   0          25s

NAME                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/tiller-deploy   1/1     1            1           25s

NAME                    TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)     AGE
service/tiller-deploy   ClusterIP   10.107.207.6   <none>        44134/TCP   25s

Prometheus をデプロイ

クラスタへ Helm で Prometheus をデプロイします。今回は stable/prometheusを使います。

Helm では values.yaml に chart のデフォルト設定パラメータを記述します。例えば、stable/prometheus の values.yaml はこのようになります。 helm inspect stable/prometheus で確認することもできます。デプロイ時に上書きしたいパラメータを yaml ファイルに記述して与えることができます。

クラスタやアプリケーションのメトリクスを正しく取得するため、下記のyamlファイルを helm/prometheus-customize-values.yaml に作成してください。

server:
  ingress:
    enabled: true
    hosts:
      - prometheus.minikube
  persistentVolume:
    size: 1Gi
    storageClass: "standard"
  retention: "12h"
nodeExporter: # Grafanaのダッシュボードにnode-exporterのバージョンをあわせる
  image:
    repository: prom/node-exporter
    tag: v0.17.0
    pullPolicy: IfNotPresent
pushgateway:
  enabled: false
alertmanager:
  ingress:
    enabled: false

下記コマンドで stable/prometheus をデプロイします。 -f で先程作成した yaml ファイルを指定しています。

helm install --name prometheus -f helm/prometheus-customize-values.yaml stable/prometheus

Grafanaをデプロイ

次に Grafana をデプロイします。前節と同様に、下記の yaml ファイルを helm/granfana-customize-values.yaml に作成してください。

ingress:
  enabled: true
  hosts:
    - grafana.minikube
persistence:
  enabled: true
  storageClassName: "standard"
  accessModes:
    - ReadWriteOnce
  size: 1Gi

下記コマンドで stable/grafana をデプロイします。

helm install --name grafana -f helm/grafana-customize-values.yaml stable/grafana

これで Prometheus と Grafana がデプロイされました。

> kube get deploy,svc,ing

NAME                                                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/grafana                         1/1     1            1           10m
deployment.extensions/prometheus-kube-state-metrics   1/1     1            1           10m
deployment.extensions/prometheus-server               1/1     1            1           10m

NAME                                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/grafana                         ClusterIP   10.103.119.133   <none>        80/TCP     10m
service/kubernetes                      ClusterIP   10.96.0.1        <none>        443/TCP    9h
service/prometheus-kube-state-metrics   ClusterIP   None             <none>        80/TCP     10m
service/prometheus-node-exporter        ClusterIP   None             <none>        9100/TCP   10m
service/prometheus-server               ClusterIP   10.96.168.192    <none>        80/TCP     10m

NAME                                   HOSTS                 ADDRESS   PORTS   AGE
ingress.extensions/grafana             grafana.minikube                80      10m
ingress.extensions/prometheus-server   prometheus.minikube             80      10m

ingressの有効化

minikubeではデフォルトでingressが無効になっているので、下記コマンドを実行し、ingressコントローラをデプロイします。これでingressからserviceにルーティングされるようになります。

minikube addons enable ingress

ドメインの割り当て

ingress で接続先サービスを見分けられるよう、Minikube の ip にドメインを割り当てます。

minikube ip で取得した ip を /etc/hosts に指定してください。

192.168.99.102  prometheus.minikube grafana.minikube app.minikube

これで http://prometheus.minikube で Prometheus へ、http://grafana.minikube で Grafana にアクセスできるようになりました。Grafana へのログインは、ID:admin, Passwordは下記コマンドで得られる文字列を与えることでログインできます( Grafana デプロイ時のログで説明されています )。

kubectl get secret --namespace default grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

ダッシュボードの作成

それではダッシュボードを作っていきましょう。まず Grafana にログインします。すると設定ページが開かれます。

まずデータソースを設定します。Add datasource をクリックし、下記のように入力し、Save & Test をクリックします。

Prometheus が正常にデプロイされており、ingressの設定がうまく行っていれば、 Data source is working が表示されます。

次にダッシュボードを作成します。左タブの + マークから Import を選びます。

ダッシュボードには、Grafana Labs のテンプレートを利用します。今回は Kubernetes Clusterダッシュボードを利用します。

ダッシュボードID の入力か JSON ファイルの入力を求められるので、Kubernetes Cluster ダッシュボードのID、7249を入力し、Loadをクリックします。すると下記のようにダッシュボードが表示されます。ダッシュボードではクラスタ全体のリソースの使用状況などが確認できます。

以上でクラスタのモニタリング環境が整いました。

サンプルアプリケーションのモニタリング環境の構築

次に Kubernetes 上で動作するアプリケーションのモニタリングの設定を行っていきます。

サンプルアプリケーションのデプロイ

サンプルアプリケーションをデプロイします。下記コマンドを実行してください。サンプルアプリケーションは soichisumi-sandbox/k8s-monitoring-sample を使用します。

> https://raw.githubusercontent.com/soichisumi-sandbox/k8s-monitoring-sample/master/deployments/deployment.yaml | kubectl apply -f -
> https://raw.githubusercontent.com/soichisumi-sandbox/k8s-monitoring-sample/master/deployments/service.yaml | kubectl apply -f -
> https://raw.githubusercontent.com/soichisumi-sandbox/k8s-monitoring-sample/master/deployments/ingress.yaml | kubectl apply -f -

curl app.minikube/app/ で動作確認ができます。

ダッシュボードの修正

minikube の addon でデプロイされる nginx-ingress コントローラはバージョンが新しいので、ダッシュボードのパネルのうちConnections と Request Time の値は表示されていないと思います。パネルの編集画面からクエリを下記のように編集してください。

Connections

nginx_ingress_controller_nginx_process_connections_total{state="active"}

Request Time

histogram_quantile(
 0.99,
 sum by (le)(
   rate(
     nginx_ingress_controller_request_duration_seconds_bucket{
       service="k8s-monitoring-sample",
       status="200"
     }[1h]
   )
 )
)

以上で、下図のようにConnection と 99 パーセンタイルの Response Time が取得できるようになりました。

Response Time が NaN の場合は 1 時間以内にサンプルアプリケーションへのリクエストが 1 つもないので、curl app.minikube/app を数回実行して少し待ってみてください。

まとめ