A Day In The Life

とあるプログラマの備忘録

Prometheus を使って Kubernetes 上に構築した Redis を監視する

PrometheusからRedisの状態を取得する

私は普段 Redis を GKE 上に構築して使用していますが、GCP コンソール画面から得られる情報が Pod の CPU 使用率、メモリ使用率、ディスク使用率くらいしかなくもう少し細かい情報を得たいと考えていました。そこで Prometheus を使って Redis の状態を監視してしてみたところとても良い感じだったのでその方法を紹介してみたいと思います。 Prometheus を使うと Redis の INFO コマンドで得られる情報を時系列に見ることができます。Prometheus は機能が豊富でいろいろできるのですが、この記事では必要最低限の設定でサクッとPrometheusを使った監視環境を構築をしてみたいと思います。

Prometheusって何?

Prometheus は SoundCloud が中心になって開発しているプル型の監視ツールです。既存のプログラムコードを変えることなくサクッと導入できるのでおすすめです。詳細は本家サイト Prometheus - Monitoring system & time series database か、 最近は専門の書籍も出ていますのでその辺りをチェックしてみてください 。

構成

以下の3つを Kubernetes 上に構築します。

  • Master/Slave構成のRedis
    • 監視対象のコンテナ
  • Exporter
    • Redisのメトリクス情報をPrometheusが読み込める形式に変換するコンテナ
  • Prometheus
    • 収集したRedisのメトリクス情報を時系列DBに保存して公開してくれるコンテナ

PrometheusはPull型の監視ツールのため、被監視対象のサーバからメトリクスを取得する必要があります。Prometheus は Redis から直接メトリクス情報を取得することができません。代わりに Exporterと呼ばれる Redis のメトリクス情報取得するためのアダプタ的なコンテナを Reids と同じ Pod に配置してそこから監視に必要な情報を取得します。

sequence dialog

Exporter はただの HTTP サーバです。Redis の各種メトリクス情報を Prometheus が解釈できるフォーマットに変換してくれます。Prometheus は Exporter が公開している /metrics にアクセスしてメトリクスを収集します。

構築の手順

構築の流れは以下のようになります。

  1. Prometheus を単体で構築する
  2. マスタースレーブ構成の Redis を構築する
  3. Redis の配置された Pod に Exporter を追加する
  4. Prometheus が Exporter からデータを収集できるように設定を修正する

前準備

本記事では Kubernetes 関連の yaml ファイルのデプロイに Kustomize を使います。以下のように k8s 関連の yaml を base という名前のディレクトリに格納するようにしてください。

base/
  ├ deployment.yaml
  ├ service.yaml
  └ ...etc

Prometheusを単体でk8s上に構築してみる

Prometheus を Kubernetes 上に構築するには Deployment と Service に加えて専用のコンフィグファイルをマウントする必要があります。

Deploymentの作成

はじめに Prometheus 本体の Pod リソースの設定をするため Deployment を作成します。Prometheus のコンテナは Docker Hub の prom/prometheus を使用します。 コンテナのポートは 9090 に設定します。stats という名前の Namespace 上に構築します(Namespaceの設定はあとでサービスと一緒に実施します)。

収集したメトリクス情報を保存するためのボリューム(data-volume)とConfigMap を読み込むためのボリューム(config-volume)をマウントしています。レプリカ数は1に設定します。

サービスの作成

Deployment が作成できたので Prometheus にアクセスするためのサービスを作成します。

今回は Service と一緒に Prometheus 専用の stats という名前の Namespace の定義もします。Service のタイプが LoadBalancer になっていますが、実際に運用する場合はロードバランサを internal にするか NodePort あたりを使ってください。

prometheus.yamlの作成

最後に Prometheus の設定をするためのコンフィグファイル(prometheus.yaml)を作成します。10秒間隔で Prometheus コンテナ自体の情報を収集するように設定してみます。この yaml ファイルは ConfigMap として読み込みます。

global:
  scrape_interval:     10s
  evaluation_interval: 10s
scrape_configs:
- job_name: 'prometheus'
  static_configs:
  - targets: ['localhost:9090']

global に Prometheus が情報を収集する時間間隔を定義し、scrape_configs に実施するジョブを定義しています。Prometheus は指定された間隔でジョブを実行してメトリクスデータを収集してくれます。

Prometheusをデプロイする

ここまで作成できるとファイル構成は以下のようになっています。

base/
  ├ prom-deployment.yaml
  ├ prom-service.yaml
  └ prometheus.yaml

base ディレクトリ以下に kustomize用のファイル kustomization.yaml を作成します。

resources:
- prom-service.yaml
- prom-deployment.yaml
configMapGenerator:
- name: prometheus-config
  files:
    - prometheus.yaml

kubectl コマンドを使って Prometheus をデプロイします。

kubectl apply -k base

ブラウザにURLhttp://35.1x9.1x0.XXX:9090/graphを入力して以下の画面が表示されればデプロイ成功です(35.1x9.1x0.XXXはサービスのIPアドレスです)。

f:id:glass-_-onion:20200421153349p:plain
Prometheus管理画面

Master/Slave構成のRedisを構築する

監視対象の Redis を Kubernetes 上に構築します。Headless Service を使ったシンプルなマスタースレーブ構成にしています。以前このブログで紹介した Redis Sentinel 構成から Sentinel 部分を取り払った構成になっています。Headless Service の説明もこちらの記事に書いてあります。

redis.confとRedisの起動ファイルを作成する

Redisの設定ファイル redis.conf ファイルを作成します。

bind 0.0.0.0
port 6379
maxclients 50000
dir /redis-data

Redisの起動時に実行されるスクリプトファイル launch.sh を作成します。

#!/bin/bash

SERVICE=redis
MASTER=${SERVICE}-0

if [ ${HOSTNAME} == ${MASTER} ]; then
    redis-server /config/redis.conf
else
    redis-server /config/redis.conf --slaveof ${MASTER}.${SERVICE} 6379
fi

StatefulSet の作成

Redis の Pod リソースの設定をするため StatefulSet を作成します。マスター1台、スレーブ2台構成にするのでレプリカ数は3に設定します。

StatefulSetを使うことで redis-0, redis-1, redis-2 という名前の Pod が生成されます。

Serviceの作成

Redis にアクセスするための Service を作成します。clusterIP に None を指定して Headless Service にします。

Headless Service にすることでクラスタ内から Pod名.サービス名 でアクセスすることが可能になります(今回の構成だとredis-0.redisのようになります)。

Redis をデプロイしてみる

以下の Kustomize ファイルを作成してデプロイしてみます。

resources:
- redis-service.yaml
- redis-ss.yaml
configMapGenerator:
- name: redis-config
  files:
    - launch.sh
    - redis.conf

kustomize.yaml を base ディレクトリに保存して以下のコマンドを実行します。

kubectl apply -k base

Redis にアクセスしてみる

redis-2 にアクセスして IP アドレスが返ってくるか確認します。

$ kubectl exec redis-2 -c redis \
-- redis-cli -p 26379 sentinel get-master-addr-by-name master

10.0.9.6
6379

Redis Exporterを追加する

ここまでで Prometheus 単体と Redis のマスタ/スレーブ がそれぞれ構築できました。ただこのままでは Prometheus は Redis のメトリクス情報を取得できません。そこで Redis の StatefulSet に Prometheus 用の Exporter コンテナを追加して Prometheus が Redis のメトリクスを取得できるようにします。頑張れば Redis の Exporter を自前で開発することもできますが割と大変なのでオープンソースの Redis Exporter を使います。Redis の Exporter は redis_exporter が有名なのでそちらを使ってみます。

先ほど作成した Redis の StatefulSet のファイル redis-ss.yaml を以下のように修正します。Redis の Pod に Redis Exporter をサイドカーとして配置します。

...省略...
      containers:
      - name: redis
        command: [sh, -c, source /config/launch.sh]
        image: redis:5-alpine
        ports:
        - containerPort: 6379
        volumeMounts:
        - mountPath: /config
          name: config
        - mountPath: /redis-data
          name: data
      - name: redis-exporter
        image: oliver006/redis_exporter:latest
        ports:
        - containerPort: 9121
...省略...

Exporter のポートは9121にします。Redis Exporter のコンテナの配置ができたので Prometheus が Exporter アクセスできるように Service にポートの設定を追加します。redis-service.yaml に以下の設定を追加します。

apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  type: ClusterIP
  clusterIP: None
  ports:
  - port: 6379
    name: port-redis
  - port: 9121
    name: port-redis-exporter
  selector:
    redis-app: redis

PrometheusからExporterの情報を収集する

ここまでで Redis 側の準備は整いました。あとは Prometheus が Redis Exporter にアクセスしてメトリクスを収集できるように設定するだけです。 Prometheus が Exporter からデータを取得するための設定を prometheus.yaml ファイルに書きます。Redis Exporter には Pod名.サービス名.ネームスペース名.svc:ポート番号 でアクセスすることができるようになります。prometheus.yaml の static_configs の targets を以下のように修正してください。

global:
  scrape_interval:     10s
  evaluation_interval: 10s
scrape_configs:
- job_name: redis_exporter
  static_configs:
  - targets:
    - redis-0.redis.default.svc:9121
    - redis-1.redis.default.svc:9121
    - redis-2.redis.default.svc:9121

Prometheus に Exporter を認識させる方法は static_configs とサービスディスカバリがありますが、今回は static_configs を使いました。サービスディスカバリの方が実用的ではあるものの RBAC の設定やサービスアカウントの作成が必要になり設定が複雑になるので static_configs にしました。

デプロイして Prometheus の管理画面から Redis の状態を確認する

Kustomize のファイルを以下のように修正して

resources:
- redis-service.yaml
- redis-ss.yaml
- prom-service.yaml
- prom-deployment.yaml
configMapGenerator:
- name: redis-config
  files:
    - launch.sh
    - redis.conf
- name: prometheus-config
  namespace: stats
  files:
    - prometheus.yaml

kustomize.yaml を base ディレクトリに保存して以下のコマンドを実行します。

kubectl apply -k base

デプロイが終わったら、ブラウザから Prometheus の管理画面(http://35.1x9.1x0.XXX:9090)にアクセスして Targets 画面に移動します。

f:id:glass-_-onion:20200421195319p:plain
Targets画面に移動する

以下のように Redis Exporter が認識されて入れば成功です。

f:id:glass-_-onion:20200421195357p:plain
Targets画面

試しに Redis の connected clients の情報を取得してみます。テキストボックスに redis_connected_clients と入力してから(またはドロップダウンから選択) Execute ボタンを押します。

f:id:glass-_-onion:20200421195714p:plain
redis_connected_clients

Redis の クライアント接続数が表示されました。取得したデータをグラフで見たい時は Graph タブを押すとグラフをみることができます。

f:id:glass-_-onion:20200421195859p:plain
グラフ

まとめ

Redis のコンテナと一緒に Redis Exporter のコンテナを配置すると Prometheus から Redis のメトリクスを取得することができます。Prometheusの コンフィグ設定は static_config を使うとお手軽です。

サンプルコード

今回のサンプルコードはこちらに置いています。

github.com

参考書籍

Prometheus について一番詳しく書かれている書籍です。

アダプタパターンとして Redis Exporter を使った事例が紹介されていました。

参考記事

関連記事