4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Elasticseachの動的なロギング基盤をパソコン上のKubernetesで検証

Posted at

CNCFチュートリアル Example: Add logging and metrics to the PHP / Redis Guestbook example をトレースしながら、ログを読み取ってElasticsearchに蓄積して、Kibana でログ分析が実施できるまでの仕組み確認する。

このチュートリアルを実行には 15Stepで習得 Dockerから入るKubernetes コンテナ開発からK8s本番運用まで の 学習環境2ために開発した パソコン上のKubernetesクラスタを使用する。 これはGitHubで公開して誰でも利用できる。そして、Vagrant + VirtualBox + Ansible とアップストリーム Kubernetesで構築するため、誰でも無料で自由に扱うことできる学習環境である。Vagrant と VirtualBoxをで、Windows10,macOS,Linuxで同じコード、同じ操作で実行できる。

アップストリーム Kubernetes のコードは、クラウドベンダー、ソフトウェア製品のコアとなっているため、この基本部分を抑えておくことで、様々なKubernetesを理解するための基礎知識にすることができる。

このチュートリアルでは、Elasticseach のBEATSを利用する。これはライトウェイトのデータシッパーと表現されるツール群で、データの発生源 GusetBook や ワーカーノードからElasticseachLogstashへデータを送り届けるためのツールである。このチュートリアルで利用するツールは、以下の三種類である。

  • Filebeat : auditd、Apache、NGINX、System、MySQLなどのログ形式の対応したログファイル転送することで一括管理を実現
  • Metricbeat : システムレベルでのCPU使用状況、メモリ、ファイルシステム、ディスクI/O、ネットワークI/Oなど、システム上で実行中のすべてのプロセスの統計情報を一括収集。Apache、Jolokia、NGINX、MongoDB、MySQL、PostgreSQL、Prometheusをはじめ、さまざまなサービスからメトリックを収集する専用モジュールも提供
  • Packetbeat : HTTPのようなネットワークプロトコルでは、アプリケーションの遅延やエラー、応答時間、SLA、ユーザーアクセスのパターン、傾向などの状況を把握

これらのツールを、Kubernetesクラスタ上でセットアップして、GuestBookやKubernetes Cluster基盤からデータを収集する基盤を構築して確認する。

overview.png

仮想マシンの起動

今回は、Elasteicsearchは、デフォルトで3ノードにデプロイする仕様となっているので、ワーカー・ノードを一つ増やして、ワーカーノード x3 と マスターノード x1 の構成を組む。そして、Elasteicsearchのポッドは、メモリ2GBを必要とするので、各ワーカーノードのメモリも増強する。

メモリを大量に利用するので、Vagrant + VirtualBox の仮想マシンのホストには Linuxサーバーを使用することにした。GitHubから次のコマンドで、コードをローカル環境へコピーする。

$ git clone -b 1.16_3n https://github.com/takara9/vagrant-kubernetes k8s-1.16-3nodes

書籍では、Kubernetes 1.14 基準にしていたが、このバージョンのサポートも終了することから、gitのブランチとして作成している Kubernetes 1.16 で 3ノード構成で起動するインフラ構築のコードである。

$ cd k8s-1.16-3nodes
$ vi Vagrantfile 

自身で実行したい人は、ファイルを編集して、外部LAN側にI/Fを追加とCPUコア数とメモリサイズを調整をお願いする。ちなみに、ワーカーノードのメモリは4GB、vCPU x2 を使用する。マスターノードは、メモリ2GB、vCPU x2 となるので、合計 RAM 16GB、vCPU x8 を使用する。稼働後の状態で、実メモリ使用量として15GBであった。

コマンド vagrant up で起動に、約12分を要した。

$ vagrant up
<中略>

$ kubectl get node
NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   87s   v1.16.3
node1    Ready    <none>   48s   v1.16.3
node2    Ready    <none>   61s   v1.16.3
node3    Ready    <none>   48s   v1.16.3

HELM v3 のインストール

ElasticSearch のGitリポジトリには、HELM v3に対応していないと記載されているが、筆者が試したところ問題がなかったので、インストールが簡単な HELM v3を利用することにした。前述のようにLinuxを利用しているので、以下の方法でHELMのクライアントをインストールする。

Linuxへのインストール例

$ curl https://get.helm.sh/helm-v3.0.2-linux-amd64.tar.gz  | tar zx
$ sudo mv linux-amd64/helm /usr/local/bin

Ubuntu Linux 18.04 のパッケージマネージャーを利用する場合のインストール例

$ sudo snap install helm --classic
helm 3.0.2 from Snapcrafters installed

インストール後の確認、HELMのバージョンは、3.0.2 を利用した。

$ helm version
version.BuildInfo{Version:"v3.0.2", GitCommit:"19e47ee3283ae98139d98460de796c1be1e3975f", GitTreeState:"clean", GoVersion:"go1.13.5"}

動作確認もかねて、HELMチャートリポジトリの追加する。helmコマンドが動作するには、kubectlコマンドが利用できる状態になっていることなので、もし、kubectlコマンドのセットアップのあとにhelmコマンドを使用しなければならない。

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

名前空間の作成

このチュートリアルでは、監視対象のアプリケーションとして、GustBook チュートリアルを使用するため、二つの名前空間に、それぞれ配置することにする。そのため、以下の様に名前空間を作成する。

kubectl create ns elasticsearch
kubectl create ns guestbook

コンテキストの作成

コマンドを実行するたびに名前空間を指定するのは面倒なので、コンテキストを作成して、デフォルトの名前空間を切り替えて使用する。そのために、kubectl configを使って、コンテキストを作成する。

kubectl config set-context es --namespace=elasticsearch --cluster=kubernetes --user=kubernetes-admin
kubectl config set-context gs --namespace=guestbook --cluster=kubernetes --user=kubernetes-admin
kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
          es                            kubernetes   kubernetes-admin   elasticsearch
          gs                            kubernetes   kubernetes-admin   guestbook
*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin 

Guestbookの導入

GustBookをインストールする。ここでは目的ではないので解説はしない。このチュートリアルについて記事を書いたので合わせて参照してもらいたい。

名前空間をguestbookへ切り替え、必要なマニフェストを全て適用する。

kubectl config use-context gs
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-deployment.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-service.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-slave-deployment.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-slave-service.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
kubectl get svc,po

全てのポッドがRunning状態となれば、準備完了となる。

NAME                   TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/frontend       NodePort    10.32.0.188   <none>        80:32213/TCP   12s
service/redis-master   ClusterIP   10.32.0.74    <none>        6379/TCP       50s
service/redis-slave    ClusterIP   10.32.0.194   <none>        6379/TCP       32s

NAME                                READY   STATUS    RESTARTS   AGE
pod/frontend-6cb7f8bd65-9kjhp       1/1     Running   0          22s
pod/frontend-6cb7f8bd65-wkrt5       1/1     Running   0          22s
pod/frontend-6cb7f8bd65-xt2mt       1/1     Running   0          22s
pod/redis-master-7db7f6579f-7pgjl   1/1     Running   0          60s
pod/redis-slave-7664787fbc-76zn9    1/1     Running   0          40s
pod/redis-slave-7664787fbc-qxg6x    1/1     Running   0          40s

GuestBookのウェブページは、NodePortで公開するので、上記service/frontendの30000番台のポート番号と仮想サーバーのLAN側IPアドレスを利用してアクセスする。以下は、コマンドで試した例であるが、パソコンのブラウザからアクセスをお勧めする。

$ curl http://192.168.1.93:32213
<html ng-app="redis">
  <head>
    <title>Guestbook</title>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.12/angular.min.js"></script>
<以下省略>

ElasticSearch の導入

チュートリアル実施の準備として、Elasticsearch と Kibana が起動させる必要がある。その為に、HELMのリポジトリを追加する。

$ helm repo add elastic https://helm.elastic.co

コンテキストを切り替えて、名前空間 elasticsearch をデフォルトにする。

$ kubectl config use-context es

ここでは永続ボリュームを使用しないで、各ノードの一時ボリュームを使用する。学習用環境のGlusterFsでは要求に対応できず ElasticSearchのポッドが障害となるため、一時ボリュームを使用する。そのために、--set persistence.enabled=falseを設定する。

helm install elasticsearch elastic/elasticsearch --set persistence.enabled=false

以下はターミナルでの実行結果である。デプロイが完了しないうちに、helmコマンドは終了するので、kubectl get pods --namespace=default -l app=elasticsearch-master -wを使って、このアプリケーションのポッドが Running 状態になるのを待って、次へすすむ。

$ helm install elasticsearch elastic/elasticsearch  --set persistence.enabled=false
NAME: elasticsearch
LAST DEPLOYED: Mon Jan 13 00:40:29 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Watch all cluster members come up.
  $ kubectl get pods --namespace=default -l app=elasticsearch-master -w
2. Test cluster health using Helm test.
  $ helm test elasticsearch

$ kubectl get pods --namespace=default -l app=elasticsearch-master -w
NAME                     READY   STATUS    RESTARTS   AGE
elasticsearch-master-0   0/1     Running   0          10s
elasticsearch-master-1   0/1     Running   0          10s
elasticsearch-master-2   0/1     Running   0          10s
elasticsearch-master-2   1/1     Running   0          49s
elasticsearch-master-1   1/1     Running   0          49s
elasticsearch-master-0   1/1     Running   0          50s

次にテストを実施して確認する。

^tkr@luigi:~/k8s-1.16-3nodes/gfs/k8s-yaml$ helm test elasticsearch
Pod elasticsearch-wispd-test pending
Pod elasticsearch-wispd-test succeeded
NAME: elasticsearch
LAST DEPLOYED: Mon Jan 13 00:40:29 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE:     elasticsearch-wispd-test
Last Started:   Mon Jan 13 00:41:59 2020
Last Completed: Mon Jan 13 00:42:00 2020
Phase:          Succeeded
<以下省略>

Kibanaの導入

フロントエンド側UIツールとして、Kibanaをインストールする。ロードバランサーと連動しなないので、--set service.type=NodePortによって、NodePortを設定して、ポート番号が固定されるように--set service.nodePort=31920を付与して、インストールする。

tkr@luigi:~/k8s-1.16$ helm install kibana elastic/kibana --set service.type=NodePort --set service.nodePort=31920 
NAME: kibana
LAST DEPLOYED: Sun Jan 12 15:40:55 2020
NAMESPACE: elasticsearch
STATUS: deployed
REVISION: 1
TEST SUITE: None

起動が完了するのに、1〜2分程度必要と思うが、起動後は、仮想サーバーの外部LAN側のIPアドレスと、先に指定したポート番号で、アクセスできる。

http://192.168.1.92:31920/app/kibana

表示される初期画面は以下のようになる。ここでは特に設定することがないので、次へすすむ。

kibana-1.png

パラメータ等の参考URL

チュートリアル

ここまでの作業で、ようやく、Example: Add logging and metrics to the PHP / Redis Guestbook example を進める準備が整った。

チュートリアルに沿って、クラスタのロール・バインディングを実施しておく。この作業は、Google GCP で利用する場合に、GCPのユーザーに対して、実行権限を付与するためであるが、デスクトップのオンプレ環境で実行して問題なので、そのまま実行しておく。

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=takara9@gmail.com

kube-state-metrics のデプロイ

kube-state-metricsは、Kubernetes APIオブジェクトからメトリック・データを提供するREST APIを提供する。これによって追加されたAPIによって Kubernetes APIから生の稼働データを公開する。ユーザーはすべての稼働データを取得でき、ヒューリスティックに状況を把握できる。

REST-APIとして、リスニングポートのHTTPエンドポイント /metrics で提供する。これによって、Prometheusクライアントや互換性のあるスクレーパーによって利用できるように設計されている。https://github.com/kubernetes/kube-state-metrics

git clone https://github.com/kubernetes/kube-state-metrics.git kube-state-metrics
cd kube-state-metrics
kubectl create -f examples/standard

次のように、kube-state-metrics のポッドが、Runningとなれば、起動ができたとみなせる。

kubectl get pods -n kube-system -l app.kubernetes.io/name=kube-state-metrics
NAME                                  READY   STATUS    RESTARTS   AGE
kube-state-metrics-7b678f986c-kd7bq   1/1     Running   0          63s

ダイナミック・ロギングツールの導入準備

これらは便利なツールで、例えば、GuestBookを構成するhttpdサーバー、Redisなどから、自動的にアクセスログ、エラーログ、メトリックス情報、ネットワークトラフィック情報を収集して、ElastiSearchに集めてくれる。このチュートリアルでは、このツールを利用して、Kibanaにログ、メトリックス、トラフィックを表示する。

Gitからツールのダウンロードして、ディレクトリを移動する。

$ git clone https://github.com/elastic/examples.git
cd ../examples/beats-k8s-send-anywhere

以下、大文字の四つのファイルを編集して、シークレット(secret)を生成する。

kubectl create secret generic dynamic-logging \
  --from-file=./ELASTICSEARCH_HOSTS \
  --from-file=./ELASTICSEARCH_PASSWORD \
  --from-file=./ELASTICSEARCH_USERNAME \
  --from-file=./KIBANA_HOST \
  --namespace=kube-system

それぞれのファイルの中身を表示しておく。詳細はチュートリアル本文を参照ください。

$ cat ELASTICSEARCH_PASSWORD 
<>:
$ cat ELASTICSEARCH_USERNAME 
<>:
$ cat ELASTICSEARCH_HOSTS 
["http://elasticsearch-master.elasticsearch.svc.cluster.local:9200"]
$ cat KIBANA_HOST 
"kibana-kibana.elasticsearch.svc.cluster.local:5601"

Filebeat のデプロイ

最初にFilebeatをデプロイする。このツールから先のシークレットは参照され、情報が送られる。

kubectl create -f filebeat-kubernetes.yaml

このマニフェストは、Kubenetes 1.16 よりだいぶ前のAPI仕様となっているので、マニフェストの書き換える必要がある。

---
apiVersion: apps/v1 #extensions/v1beta1  <-- apps/v1へ変更
kind: DaemonSet
metadata:
  name: filebeat-dynamic
  namespace: kube-system
  labels:
    k8s-app: filebeat-dynamic
    kubernetes.io/cluster-service: "true"
spec:
  selector:            <-- ここから3行を追加
    matchLabels:
      k8s-app: filebeat-dynamic  <-- このキーと値は、metadata.labelsからコピーする
  template:
    metadata:
      labels:

適用してた後に、STATUSが Runningとなれば、次へすすむ。

$ kubectl get pods -n kube-system -l k8s-app=filebeat-dynamic
NAME                     READY   STATUS    RESTARTS   AGE
filebeat-dynamic-kstlx   1/1     Running   0          2m27s
filebeat-dynamic-lxzms   1/1     Running   0          2m27s
filebeat-dynamic-vx65n   1/1     Running   0          2m27s

Filebeatの動作

Filebeat のポッドは、/var/lib/docker/containers 以下をマウントして、ワーカーノードのコンテナ実行環境から、コンテナ内のファイルを読み取る。この方法によって、ポッドのサイドカーを利用することなく、ワーカーノードにエージェントを導入することなく、ポッド内のミドルウェアのファイルやログを読み取ることができる。
OpenShiftでは、コンテナを特権で動かす必要のためマニフェストに追加の設定が必要となる。

FileBeat参考URL:

障害対応の例

もし、以下のようなFilebeatのポッドが、ErrorとRunningを繰り返す場合の原因判別の方法について補足する。

$ kubectl get pods -n kube-system -l k8s-app=filebeat-dynamic
NAME                     READY   STATUS   RESTARTS   AGE
filebeat-dynamic-g48gv   0/1     Error    0          44s
filebeat-dynamic-kzkbd   0/1     Error    0          44s
filebeat-dynamic-zmqpb   0/1     Error    0          44s

$ kubectl get pods -n kube-system -l k8s-app=filebeat-dynamic
NAME                     READY   STATUS             RESTARTS   AGE
filebeat-dynamic-g48gv   0/1     CrashLoopBackOff   1          53s
filebeat-dynamic-kzkbd   0/1     CrashLoopBackOff   1          53s
filebeat-dynamic-zmqpb   0/1     CrashLoopBackOff   1          53s

次のように、ポッドを指定して、ログをダンプする。この中で、ERRORを探して原因を探る。

ここでは、lookup elasticsearch-master.elasticsearch.svc.cluster.local: no such host と表示され、Kubernetesの内部DNSに登録されていないことが読み取れる。このケースでは、ElasticSearchが 名前空間 default へデプロイされていたために、この様な問題が起きていた。

$ kubectl logs filebeat-dynamic-g48gv
<中略>
al": lookup elasticsearch-master.elasticsearch.svc.cluster.local: no such host
2020-01-12T16:18:44.805Z	ERROR	elasticsearch/elasticsearch.go:252	Error connecting to Elasticsearch at http://elasticsearch-master.elasticsearch.svc.cluster.local:9200: Get http://elasticsearch-master.elasticsearch.svc.cluster.local:9200: lookup elasticsearch-master.elasticsearch.svc.cluster.local: no such host
2020-01-12T16:18:44.807Z	INFO	[monitoring]	log/log.go:152	Total non-zero metrics	{"monitoring": {"metrics": {"beat":{"cpu":{"system":{"ticks":10,"time":{"ms":12}},"total":{"ticks":50,"time":{"ms":60},"value":50},"user":{"ticks":40,"time":{"ms":48}}},"handles":{"limit":{"hard":1048576,"soft":1048576},"open":9},"info":{"ephemeral_id":"f62e797e-0fd8-4f61-bfcd-6def1894bca7","uptime":{"ms":45}},"memstats":{"gc_next":4779472,"memory_alloc":2494672,"memory_total":6717840,"rss":27881472}},"filebeat":{"harvester":{"open_files":0,"running":0}},"libbeat":{"config":{"module":{"running":0}},"output":{"type":"elasticsearch"},"pipeline":{"clients":0,"events":{"active":0}}},"registrar":{"states":{"current":0}},"system":{"cpu":{"cores":3},"load":{"1":0.38,"15":0.27,"5":0.32,"norm":{"1":0.1267,"15":0.09,"5":0.1067}}}}}}
2020-01-12T16:18:44.807Z	INFO	[monitoring]	log/log.go:153	Uptime: 46.059403ms
2020-01-12T16:18:44.807Z	INFO	[monitoring]	log/log.go:130	Stopping metrics logging.
2020-01-12T16:18:44.807Z	INFO	instance/beat.go:393	filebeat stopped.
2020-01-12T16:18:44.807Z	ERROR	instance/beat.go:906	Exiting: Error importing Kibana dashboards: fail to create the Elasticsearch loader: Error creating Elasticsearch client: Couldn't connect to any of the configured Elasticsearch hosts. Errors: [Error connection to Elasticsearch http://elasticsearch-master.elasticsearch.svc.cluster.local:9200: Get http://elasticsearch-master.elasticsearch.svc.cluster.local:9200: lookup elasticsearch-master.elasticsearch.svc.cluster.local: no such host]
Exiting: Error importing Kibana dashboards: fail to create the Elasticsearch loader: Error creating Elasticsearch client: Couldn't connect to any of the configured Elasticsearch hosts. Errors: [Error connection to Elasticsearch http://elasticsearch-master.elasticsearch.svc.cluster.local:9200: Get http://elasticsearch-master.elasticsearch.svc.cluster.local:9200: lookup elasticsearch-master.elasticsearch.svc.cluster.local: no such host]

Metricbeat

次のメトリックスを収集するツールの導入である。これも同様に導入を実施すれば良い。

kubectl create -f metricbeat-kubernetes.yaml

このマニフェストも、古いバージョンで書かれており、Deployment と DaemonSet が該当するので、API表記、そして、spec.selectorの追加を実施しなければならない。マニフェスト適用後にポッドがRunningになれば完了。

$ kubectl get pods -n kube-system -l k8s-app=metricbeat
NAME                          READY   STATUS    RESTARTS   AGE
metricbeat-585bd7d6c9-kc47c   1/1     Running   0          4m30s
metricbeat-c4q76              1/1     Running   0          4m31s
metricbeat-qcmmg              1/1     Running   0          4m31s
metricbeat-vr5n7              1/1     Running   0          4m31s

Metricbeat参考URL:

Packetbeat

最後のツールで Packetbeat を導入する。DaemonSetのAPIが古い仕様で記述されているので、同じ様に修正してから適用する。適用後に全てのポッドが Running状態になれば完了である。

$ kubectl create -f packetbeat-kubernetes.yaml

これでチュートリアルのセットアップは完了である。

Packetbeat参考URL:

メモリ使用量

ElasticSearch は、Javaで書かれているため、どれくらいメモリを必要とするか心配になる。約2時間強動かしたあとのメモリ使用量は、以下の様になった約3GBである。 よって、ノードに与えるメモリは 4GB が最小ラインになると思われる。

$ kubectl top node
NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master   87m          4%     1141Mi          60%       
node1    134m         6%     2607Mi          67%       
node2    153m         7%     2813Mi          73%       
node3    159m         7%     2743Mi          71%       

Kibanaの画面

カスタマイズなしで、簡単に見れる画面を紹介する。

これは Discover画面 で、単位時間あたりのイベントの発生量と、個々のイベントの内容をリストで見ることができる。インデックスの単語ごとの集計を見ることができる。

kibana-2.png

次はメトリックスの画面である。ElasticSearchと言えば検索エンジンが有名である。この特徴を利用してログ分析ツールとして利用されているが、メトリックスも集計できることを示した画面と言える。GrafanaとPrometheusほどではないが、こちらでも時系列に必要な情報が見れることがわかる。このタイルをクリックすることで、CPUやメモリなどの時系列グラフを参照できる。

kibana-3.png

時系列で、CPU、メモリ、ネットワークなどの使用上がわかる。

kibana-4.png

次は監視対象ファイルをワーカーノード横断で、tail -f ファイル名 に相当する表示である。例えば、Apache2のアクセスログも、Syslogの情報も混在して、同じ画面に表示される。ワーカーノードやポッドが多くても、新たにノードが追加されても、設定を変更することなく、自動的に追加されて、この画面にのってくる。

kibana-5.png

まとめ

CNCF Kubernetesドキュメントのチュートリアルは、GCPなどのパブリッククラウドでの使用を想定して、記載されている。しかし、パソコン上のアップストリーム Kubernetesでも利用できることから、オンプレミス環境でも、OpenShift でも利用できることが期待される。

Elastic社は、サブスクリプションとして、ソフトウェアのサポートを提供している。このチュートリアルで使用したElassticseachとKibanaなど関連ソフトウェアも、無償でも利用できるが、サポートを受けるには、Elastic社とサブスクリプション契約が必要となる。

一方、OpenShiftには、Elasticseachが同梱されており、Red Hatを通じて、OpenShiftの一部としてサポートを受けることが可能である。OpenShiftではこの高機能なログ分析ツールまでが含まれ、OpenShift4では運用をサポートするOperatorも付属しているからOpenShiftはお得なのかもしれない。

その他参考URL:

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?