エンジニアリング

FilebeatとMetricbeatを活用したElastic流の方法でKubernetesを監視する

以前のブログ記事「Elastic StackをPrometheusとFluentdと組み合わせてKubernetesを監視する」で、PrometheusとFluentdをElastic Stackと組み合わせて使用して、Kubernetesを監視する方法をご紹介しました。既に利用しているオープンソースベースの監視ツールが組織内にある場合は、このような方法も有効ですが、これから新規でKubernetesを監視したい場合や、あるいはElastic Observabilityをフル活用したい場合は、もっと簡単で包括的な方法があります。本ブログでは、FilebeatとMetricbeatを使ったElastic流の方法で、Kubernetesを監視する方法を解説します。

FilebeatとMetricbeatを使う

Beatsは、ご存知の通り、データシッピングに特化した無料かつオープンなプラットフォームです。Beatsを活用することで、何百、何千ものマシンからLogstashやElasticsearchにデータを転送できます。

Filebeatは、軽量なログシッパーとして知られていますが、コンテナを多く使うアーキテクチャーにも対応しています。FilebeatはDockerやKubernetes、クラウド環境にもデプロイ可能で、全てのログストリーム収集に加え、コンテナ、ポッド、ノード、仮想環境、ホストやその他のメタデータも取得し、自動でログイベントと関連付けします。また、Metricbeatは、軽量なメトリックシッパーで、Filebat同様、コンテナにも対応しています。 Kubernetes環境では、コンテナは利用可能なワーカーノードにポッドとして、動的にデプロイされます。この「動的」というのが肝心ですが、FilebeatとMetricbeatには、Autodiscoverという便利な機能が備わっています。コンテナでアプリケーションを実行すると、それらは監視システムにとって移動する対象になります。Filebeat、MetricbeatのKubernetes Autodiscover Providerは、Kubernetesノード、ポッド、サービスの開始、更新、および停止を監視します。Filebeat、Metricbeatはこれらのイベントを検知すると、それぞれのイベントに適切なメタデータを利用可能にします。また、起動されたKubernetesポッドのアノテーションに応じて、処理対象のログ、メトリックに対して、適切な設定を適用します。 ヒントベースのAutodiscoverについては、Beatsを使用したDockerおよびKubernetesのヒントベースの自動探知機能(Autodiscover)で詳細について説明されていますので、参考にしてみてください。

モニタリングアーキテクチャ

前回同様、Cloud-Voting-Appというシンプルな、マルチコンテナアプリケーションをKubernetesクラスター上にデプロイし、そのアプリケーションを含めたKubernetes環境を監視します。今回は、Filebeatを使ってログを収集し、Metricbeatを使ってメトリックを収集し、直接Elasticsearchに投入し、Kibanaを使って監視する手順を説明していきます。また、Elastic APMを活用した、Promethuesカスタムメトリックの取得についても解説します。大まかなアーキテクチャは以下の図のようになります。また、ここでご紹介するコードは、GitHubレポに掲載していますので、完全な手順はそちらを参照してください。

enter image description here

それでは、各手順を見ていきましょう。

FilebeatをDaemonSetとしてデプロイする

Filebeatのインスタンスは、Kubernetesノード1つにつき1つデプロイします。DaemonSetのManifestは、elastic/filebeat-kubernetes.yamlに定義されていますが、キーとなる設定を見ていきましょう。

まず、Kubernetes Autodiscover Providerを利用して、アプリケーションポッドのアノテーション設定を使ってログを処理できるように構成します。Autodiscoverの設定については、filebeat.autodiscoverセクションに定義しますが、ヒントを有効にして、コンテナログのデフォルトパスを設定しているだけです。FilebeatのAutodiscoverの設定の詳細については、Filebeatドキュメントを参照してください。

...
    # To enable hints based autodiscover, remove `filebeat.inputs` configuration and uncomment this:
    filebeat.autodiscover:
      providers:
        - type: kubernetes
          node: ${NODE_NAME}
          hints.enabled: true
          hints.default_config:
            type: container
            paths:
              - /var/log/containers/*${data.kubernetes.container.id}.log
...

それ以外では、基本的に出力先のElasticsearchのクラスターURLとクレデンシャル情報を追加するだけでOKです。

...
     containers:
      - name: filebeat
        image: docker.elastic.co/beats/filebeat:7.13.0
        args: [
          "-c", "/etc/filebeat.yml",
          "-e",
        ]
        env:
        - name: ELASTICSEARCH_HOST
          value: elasticsearch
        - name: ELASTICSEARCH_PORT
          value: "9200"
        - name: ELASTICSEARCH_USERNAME
          value: elastic
        - name: ELASTICSEARCH_PASSWORD
          value: changeme
        - name: ELASTIC_CLOUD_ID
          value:
        - name: ELASTIC_CLOUD_AUTH
          value:
...

kube-state-metricsをデプロイする

kube-state-metricsは、Kubernetesにストアされているオブジェクトを監視するためのアドオンです。kube-state-metricsは、Kubernetesクラスター上のオブジェクトの状態を識別することに焦点を当てています。例えば、ある時点において、いくつポッドがクラスターにデプロイされているのか、割り当て可能なCPUコアはいくつあるのか、いくつジョブが失敗しているのか、などです。kube-state-metricsは、デフォルトではKubernetesクラスタにデプロイされていないので、自身でデプロイする必要があります。kube-state-metricsのサンプルManifestは、examples/standard配下に定義されていますので、これを使ってデプロイすることができます。kube-state-metricsの詳細については、こちらのGitHubレポを参照ください。

MetricbeatをDaemonSetとしてデプロイする

Metricbeatのインスタンスは、Filebeatと同様に、Kubernetesノード1つにつき1つデプロイします。DaemonSetのManifestは、elastic/metricbeat-kubernetes.yamlに定義されていますが、Filebeatに較べて少しトリッキーです。キーとなる設定を見ていきましょう。

Autodiscoverについての設定は、metricbeat.autodiscoverセクションに定義します。最初の- type: kubernetesの設定は、Kubernetesクラスター全体に対するものです。ここでは、MetricbeatのKubernetesモジュールを使って、Kubernetesクラスター全体にかかるメトリックについて設定しています。最初の- module: kubernetesの構成は、前述のkube-state-metricsから取得するメトリックについて設定しています。二番目の- module: kubernetesの構成は、Kubernetes APIを公開する、Kubernetesコントロールプレーンの中心となるKubernetes APIサーバー(kube-apiserver)を監視するための設定です。MetricbeatのKubernetesモジュールについての詳細は、Metricbeatドキュメントを参照ください。

metricbeat.autodiscover:
  providers:
    - type: kubernetes
      scope: cluster
      node: ${NODE_NAME}
      unique: true
      templates:
        - config:
            - module: kubernetes
              hosts: ["kube-state-metrics:8080"]
              period: 10s
              add_metadata: true
              metricsets:
                - state_node
                - state_deployment
                - state_daemonset
                - state_replicaset
                - state_pod
                - state_container
                - state_cronjob
                - state_resourcequota
                - state_statefulset
                - state_service
            - module: kubernetes
              metricsets:
                - apiserver
              hosts: ["https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"]
              bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
              ssl.certificate_authorities:
                - /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
              period: 30s

さらに、ヒントを有効にして、Kubernetes Autodiscover Providerを利用して、アプリケーションポッドのアノテーション設定を使ってメトリックを処理できるように設定します。MetricbeatのAutodiscoverの設定の詳細については、Metricbeatドキュメントを参照してください。

    # To enable hints based autodiscover uncomment this:
    - type: kubernetes
      node: ${NODE_NAME}
      hints.enabled: true

以下のConfigMapの設定は、MetricbeatのKubernetesモジュールのデフォルトのMetricsetである、node/system/pod/container/volumeについてのものです。これらのメトリックは、各ノードのkubelet endpointから取得されます。

kubernetes.yml: |-
  - module: kubernetes
    metricsets:
      - node
      - system
      - pod
      - container
      - volume
    period: 10s
    host: ${NODE_NAME}
    hosts: ["https://${NODE_NAME}:10250"]
    bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    ssl.verification_mode: "none"

あとは、Filebeat同様、基本的に出力先のElasticsearchのクラスターURLとクレデンシャル情報を追加するだけでOKです。

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

前回ブログと同様、Cloud Votingアプリケーションをデプロイします。Cloud Votingアプリケーションは、ユーザーインターフェースをPython/Flask、データ層にRedisを使った、マルチコンテナの非常にシンプルなアプリケーションです。アプリケーションは、Prometheusのカスタムメトリックを公開するようにPrometheus Python Clientでインストゥルメントされていたことを思い出してください。今回、Prometheusをデプロイしていないのに、どうやってPromehteusのカスタムメトリックを収集するのでしょう?7.12から、Elastic APM Agentを使ってPrometheusのカスタムメトリックが取得できるようになったのです!

まず、アプリケーションコードでは、ElasticAPMをインポートし、Elasitc APM Agentに必要な設定を環境変数からセットしています。SERVICE_NAMEは、アプリケーションを識別するための任意の文字列、ENVIRONMENTは、アプリケーション環境を識別するための任意の文字列、SECRET_TOKENSERVER_URLは、APM Serverと通信するためのものです。最後のPROMETHEUS_METRICSは、prometheus_clientからメトリックを取得するか否かを指示するパラメータです。

from elasticapm.contrib.flask import ElasticAPM
...
app = Flask(__name__)
...
# Elastic APM Configurations
app.config['ELASTIC_APM'] = {
# Set required service name. Allowed characters:
# a-z, A-Z, 0-9, -, _, and space
'SERVICE_NAME': os.environ['SERVICE_NAME'],
#
# Use if APM Server requires a token
'SECRET_TOKEN': os.environ['SECRET_TOKEN'],
#
# Set custom APM Server URL (default: http://localhost:8200)
'SERVER_URL': os.environ['SERVER_URL'],
#
# Set environment
'ENVIRONMENT': os.environ['ENVIRONMENT'],
#
# Set prometheus_metrics
'PROMETHEUS_METRICS': os.environ['PROMETHEUS_METRICS'],
}
apm = ElasticAPM(app)

次に示すのは、Cloud VotingアプリケーションをKubernetesクラスタにデプロイするためのManifestです。ファイルは、elastic/cloud-vote-all-in-one-redis-aks.yamlに定義されています。まず、ユーザーインターフェースのcloud-vote-frontですが、container specで環境変数として、前述のAPM Agentに必要な変数を設定しています。ここでは、ポッド固有のアノテーションは指定せず、ログ、メトリック共にデフォルトの設定で取得します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cloud-vote-front
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cloud-vote-front
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: cloud-vote-front
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: cloud-vote-front
        image: your image name
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 250m
          limits:
            cpu: 500m
        env:
        - name: REDIS
          value: "cloud-vote-back"
        - name: SERVICE_NAME
          value: "cloud-voting"
        - name: SECRET_TOKEN
          value: "APM Server secret token"
        - name: SERVER_URL
          value: "APM Server URL"
        - name: ENVIRONMENT
          value: "Production"
        - name: PROMETHEUS_METRICS
          value: "True"

一方、バックエンドのcloud-vote-redisですが、ポッドのannotationsにより、ログについてはFilebeatのredisモジュールを、メトリックについてはMetricbeatのredisモジュールをそれぞれ有効にして、必要な設定をしています。この設定により、cloute-vote-frontがデフォルト設定のまま、ログやメトリックをBeatsで収集するのに対して、cloud-vote-backについては、Beatsのredisモジュールを使って、ログやメトリックを収集することが可能になります。また、このようにBeats側のManifestではなく、アプリケーション側のManifestで、どのようにログやメトリックを収集するかを設定することで、結果として、アプリケーションのDevチームとObservabilityプラットフォームのチームで責任を分離するという効果も得られます。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cloud-vote-back
spec:
  replicas: 1
  selector:
    matchLabels:
      app: cloud-vote-back
  template:
    metadata:
      labels:
        app: cloud-vote-back
      annotations:
        co.elastic.logs/enabled: "true"
        co.elastic.logs/module: redis
        co.elastic.logs/fileset.stdout: log
        co.elastic.metrics/enabled: "true"
        co.elastic.metrics/module: redis
        co.elastic.metrics/hosts: "${data.host}:6379"
    spec:
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: cloud-vote-back
        image: redis
        ports:
        - containerPort: 6379
          name: redis

Kibanaから見てみよう

さて、これで必要なコンポーネントが全てデプロイできました。早速、Cloud Votingアプリで何度かVoteしてから、Kibanaにアクセスしてみましょう。

オブザーバビリティオーバービュー

まずは、KibanaからObservabilityを開いてみると、Filebeatから投入されたログのログレートや、Metricbeatから投入されたメトリックのサマリが、何もせずとも表示されています。これは、FilebeatやMetricbeatが、データをデフォルトでECSフォーマットで投入しているからこそなせる技です。

enter image description here

ログ

Filebeatから投入されたログは、filebeat-*というインデックスに書き込まれます。通常は、KibanaのLogsアプリを使って、Elasticsearchに収集した全てのログの検索、絞り込み、tailを実行できます。ご覧の通りに、特定の文字列、以下の例ではcloud-vote-frontでハイライト表示したりすることもできます。

enter image description here

メトリック

Metricbeatから投入されたメトリックは、metricbeat-*というインデックスに書き込まれます。KibanaのMetricsアプリを使って、Elasticsearchに収集したメトリックをわかりやすく、直感的に表示することができます。Kubernetes Podsビューで表示すれば、ご覧の通りKubernetesのノードとポッドをマッピングして、各リソースの利用状況を表示してくれます。

enter image description here

さらに特定のポッドをクリックすると、コンテキストを保持しながら、ポッドのログやAPMトレースなど、他のアプリにジャンプすることができます。View details for kubernetes.pod.uid a47d81b1-02d7-481a-91d4-1db9fe82d7a7と画面に表示されていることに着目してください。

enter image description here

Kubernetes Pod logsをクリックすると、このポッドのログにジャンプすることができます。Logsアプリのサーチバーにkubernetes.pod.uid: a47d81b1-02d7-481a-91d4-1db9fe82d7a7と入力済みであることに気づきましたか?このように、Kibanaアプリ間でコンテキストとなる情報を引き継ぐことで、KibanaはElasticsearchで瞬時に検索をして、画面を切り替えているのです。

enter image description here

さて、Promethuesのカスタムメトリックは、どうなったでしょうか?Prometheus Python Clientで保持しているカスタムメトリックは、Elastic APM Agentを介して、apm-*というインデックスに書き込まれます。Kibana Discoverで確認すると、prometheus.metrics.cloud_votesというフィールドで収集されていることがわかります。POST時の変数もlabels.voteとして取得できています。Elastic APM Python AgentによるPromethuesカスタムメトリックの収集についての詳細は、APMドキュメントを参照ください。

enter image description here

Kibana Lensでapm-*インデックスを可視化すれば、この通りです。

enter image description here

事前定義済みのダッシュボード

Redisを使っているcloud-vote-backポッドについては、Filebeat、Metricbeat共にredisモジュールを有効にしていました。これにより、すぐに使えるKibanaダッシュボードも事前作成されます。他に特別な設定をしなくても、すぐにRedisのログやメトリックを可視化できます。

enter image description here enter image description here

さらに、Kubernetesに関するダッシュボードもこの通り、何もしなくても可視化されます。これは、MetricbeatのKubernetesモジュールのお陰です。

enter image description here

まとめ

今回は、FilebeatとMetricbeatを使って、Elastic Stackにログとメトリックを投入し、Kubernetesを監視する、よりElastic流の方法をご紹介しました。Elastic APM Agentを使って、Promethuesカスタムメトリックを取得する方法についても、見てきました。Elastic CloudのElasticsearch Service無料トライアルに登録したり、自前の環境にElastic Stackをダウンロードすれば、今日からお使いのKuberntes環境の監視を始めることができます。Elastic Observabilityを使えば、より効率的かつ効果的な監視が可能であることが、ご理解いただけたかと思います。また、Elasticの機械学習やKibana Alertingと組み合わせて、高度に自動化された、アクションに直結する包括的なオブザーバビリティを確立することも可能になります。お困りのことや、ご質問がおありの場合はディスカッションフォーラムをご活用ください。活発なコミュニティが待っています。

本ブログに続く将来の投稿では、Kubernetes環境の監視にElasticを活用した別の方法に引き続きご注目ください。