ROOK Ceph の永続ストレージを利用したアプリケーション利用としてログ分析基盤を導入してみたい。これまで ROOK Ceph のブロックストレージを検証したメモのQiita記事でROOK Cephのストレージを構築して、永続ストレージを利用したアプリケーションとしてKubernetesの監視#1 Promethus & Grafana on ROOK Cephでメトリックス監視を構築した。この記事では、ログ分析 エラスティックサーチ(Elastiecsearch) とブラウザUI キバナ (Kibana)を導入してみたい。
Elastiecsearchとサンプルアプリの名前空間作成
Elastiecsearch や Guestbook など複数のアプリケーションを Kubernetesクラスタへデプロイして運用する場合、必ず専用の名前空間を作成して、その中で動作させるのが良い。名前空間にリソース使用の上限を設定することができるためである。
ここでは名前空間を作成して、コンテキストと対応させて固定的に名前空間をアクセスできるようにする。
kubectl create ns elasticsearch
kubectl create ns guestbook
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
コンテキストを es に切り替えて、--namespace オプションが省略された場合でも、elasticsearchにターゲットが設定されるようにする。
kubectl config use-context es
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
Elastiecsearchのインストール
Elasticsearchのドキュメントには最新版バージョン8が表示されているが、まだGAとなっていない様なので インターネットで入手できる 7.5.2 を使用する。最近までクイックインストールガイドでは バージョン 6.8 が導入されていたが、これでは最近主流の containerd
エンジン環境で動作させることができない。
HelmでStableを指定した場合のサーチ結果、6.8.2 では動作しないので、サーチのパラメータを変更する。
helm search repo stable/elasticsearch
NAME CHART VERSION APP VERSION DESCRIPTION
stable/elasticsearch 1.32.2 6.8.2 Flexible and powerful open source, distributed ...
stable/elasticsearch-curator 2.1.3 5.7.6 A Helm chart for Elasticsearch Curator
stable/elasticsearch-exporter 2.2.0 1.1.0 Elasticsearch stats exporter for Prometheus
リポジトリを追加して、以下の elastic/elasticsearch を利用してセットアップを進める。
helm repo add elastic https://helm.elastic.co
これにより、一番上に表示された 7.5.2 を利用できるようになった。
helm search repo elasticsearch
NAME CHART VERSION APP VERSION DESCRIPTION
elastic/elasticsearch 7.5.2 7.5.2 Official Elastic helm chart for Elasticsearch
stable/elasticsearch 1.32.2 6.8.2 Flexible and powerful open source, distributed ...
stable/elasticsearch-curator 2.1.3 5.7.6 A Helm chart for Elasticsearch Curator
パラメータをファイルに抜き出して編集する。
helm inspect values elastic/elasticsearch > elasticsearch-values.yaml
パラメータの修正箇所は、以下の diff の結果通り一箇所とした。
tkr@luigi:~/sandbox-3/elasticsearch$ diff -c elasticsearch-values.yaml elasticsearch-values.yaml.org
*** elasticsearch-values.yaml 2020-01-26 21:25:07.434287399 +0900
--- elasticsearch-values.yaml.org 2020-02-10 16:45:43.829620681 +0900
***************
*** 82,88 ****
volumeClaimTemplate:
accessModes: [ "ReadWriteOnce" ]
- storageClassName: rook-ceph-block
resources:
requests:
storage: 30Gi
パラメータファイルを指定してデプロイを実行する。ここでも前述のコンテキストが効いているので 名前空間を指定する必要はない。
helm install elasticsearch -f elasticsearch-values.yaml elastic/elasticsearch
NAME: elasticsearch
LAST DEPLOYED: Sun Jan 26 12:37:26 2020
NAMESPACE: elasticsearch
STATUS: deployed
REVISION: 1
NOTES:
1. Watch all cluster members come up.
$ kubectl get pods --namespace=elasticsearch -l app=elasticsearch-master -w
2. Test cluster health using Helm test.
$ helm test elasticsearch
上記のHelmの応答メッセージ通り、ポッドがすべて起動し終わったら、テストを実行しておくと良い。
これで、Elasticsearch本体のインストールは終了となる。ここまでの状態で PVC の確保量は、次の通りになった。
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
elasticsearch-master-elasticsearch-master-0 Bound pvc-40c22ed0-183a-439e-a139-2806260dc4f9 30Gi RWO rook-ceph-block 3m37s
elasticsearch-master-elasticsearch-master-1 Bound pvc-c1382774-007c-402a-bbd9-98de0cfe9256 30Gi RWO rook-ceph-block 3m37s
elasticsearch-master-elasticsearch-master-2 Bound pvc-bf45fd8b-74c6-4a06-9727-1485df232134 30Gi RWO rook-ceph-block 3m37s
Kibanaのインストール
次にUIのKibanaをインストールする。これまでと同様に Helmチャートからパラメータファイルを生成する。
helm inspect values elastic/kibana > kibana-values.yaml
編集する箇所は、以下の差分のように、ClusterIP ー> NodePortに変更、nodePort番号をアサインする。
diff -c kibana-values.yaml kibana-values.yaml.org
*** kibana-values.yaml 2020-01-26 21:53:56.023471404 +0900
--- kibana-values.yaml.org 2020-02-10 16:55:22.029673918 +0900
***************
*** 3,9 ****
elasticsearchURL: "" # "http://elasticsearch-master:9200"
elasticsearchHosts: "http://elasticsearch-master:9200"
-
replicas: 1
# Extra environment variables to append to this nodeGroup
--- 3,8 ----
***************
*** 78,86 ****
type: "Recreate"
service:
! type: NodePort
port: 5601
! nodePort: 31920
labels: {}
annotations: {}
# cloud.google.com/load-balancer-type: "Internal"
--- 77,85 ----
type: "Recreate"
service:
! type: ClusterIP
port: 5601
! nodePort: ""
labels: {}
annotations: {}
# cloud.google.com/load-balancer-type: "Internal"
パラメータを編集したファイル名をインプットにして、デプロイする。
helm install kibana --namespace elasticsearch -f kibana-values.yaml elastic/kibana
変更した通りNodePortでアクセス可能となっていることを確認する。
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kibana-kibana NodePort 10.32.0.84 <none> 5601:31920/TCP 4m5s
これで Kibanaのポッドが起動したら http://192.168.1.91:31920/app/kibana でアクセスすることができる。
この時点ではログシッパーの設定がされていないため、ログの参照はできない。
Elasticsearch Beatsとは
Elasticsearch Beatsは、データシッピング専用のツールで、何百、何千ものマシンからLogstashやElasticsearchにデータを転送できる。用途に合わせた下記のツールがある。
- Filebeat ログファイル転送
- Metricbeat メトリック
- Packetbeat ネットワークパケット
- Winlogbeat Windowsイベントログ
- Auditbeat 監査データ
- Heartbeat 稼働状態の監視
- Functionbeat サーバーレスシッパー
過去は、Elastiecsearchはログ分析基盤と言い換えていたが、Beatsの機能からメトリックスの監視にも利用できるということがわかる。
本記事では、Filebeat, Metricbeat, Auditbeatをセットアップする。
Beatのインストール
Beatのインストールには、GitHubから7.5.2をクローンして利用する。それ以前のバージョンのBeatでは コンテナエンジン containerd に対応していないため、古いBeatsでは動作しない。 OpenShift4 を利用する場合コンテナエンジンは cri-o となるために注意が必要である。
git clone -b 7.5 https://github.com/elastic/beats
cd beats/deploy/kubernetes
ls -al
合計 56
drwxrwxr-x 6 tkr tkr 4096 1月 26 17:28 .
drwxrwxr-x 4 tkr tkr 4096 1月 26 16:14 ..
drwxrwxr-x 2 tkr tkr 4096 1月 26 16:14 .travis
-rw-rw-r-- 1 tkr tkr 575 1月 26 16:14 Makefile
-rw-rw-r-- 1 tkr tkr 323 1月 26 16:14 README.md
drwxrwxr-x 2 tkr tkr 4096 1月 26 16:14 auditbeat
-rw-rw-r-- 1 tkr tkr 4286 1月 26 17:27 auditbeat-kubernetes.yaml
drwxrwxr-x 2 tkr tkr 4096 1月 26 16:14 filebeat
-rw-rw-r-- 1 tkr tkr 4003 1月 26 17:27 filebeat-kubernetes.yaml
drwxrwxr-x 2 tkr tkr 4096 1月 26 16:14 metricbeat
-rw-rw-r-- 1 tkr tkr 8744 1月 26 17:28 metricbeat-kubernetes.yaml
このディレクトリにある3つのYAMLファイルを利用することで、インストールは完了するのだが、一つ課題がある。 これは、インストールしても、Elasticseachと繋がらないため動作しないとう課題である。その原因と対策について次に対応する。
Beatの課題対応
filebeat-kubernetes.yamlを例に問題点について確認する。この中で spec.hostNetwork=trueが設定されている。これは
apiVersion: apps/v1
kind: DaemonSet
<中略>
spec:
serviceAccountName: filebeat
terminationGracePeriodSeconds: 30
hostNetwork: true <--- 注目
dnsPolicy: ClusterFirstWithHostNet
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:7.5.2
args: [
"-c", "/etc/filebeat.yml",
"-e",
]
env:
- name: ELASTICSEARCH_HOST
value: elasticsearch-master.elasticsearch.svc.cluster.local
- name: ELASTICSEARCH_PORT
value: "9200"
ログ取得対象にはノードも含まれるため hostNetwork: true
を設定する必要がある。そして、DNS名からアドレス解決として、K8sクラスタ内DNSとホストネットDNSをサーチする設定 「ClusterFirstWithHostNet」にしなければならない。しかし、この環境では、ノードのアドレスを外部DNSで解決できない。それが直接的な原因かわからないが、サービスが登録したDNS名 elasticsearch-master.elasticsearch.svc.cluster.local
のIPアドレスを変換できない。以下にAPIドキュメントの翻訳を添付しておく。
-
hostNetwork:ブール値
このポッドに要求されたホストネットワーキング。ホストのネットワーク名前空間を使用します。このオプションを設定する場合、使用するポートを指定する必要があります。デフォルトはfalseです。 -
dnsPolicy: ストリング
ポッドのDNSポリシーを設定します。デフォルトは「ClusterFirst」です。有効な値は「ClusterFirstWithHostNet」、「ClusterFirst」、「Default」または「None」です。DNSConfigで指定されたDNSパラメーターは、DNSPolicyで選択されたポリシーとマージされます。DNSオプションをhostNetworkとともに設定するには、DNSポリシーを明示的に「ClusterFirstWithHostNet」に指定する必要があります。
参考URL https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#podspec-v1-core
この問題として、ワーカノードの外部DNSを設定して、ノードのDNS名を解決できるようにするべきだが、少々大変なので、簡易的な解決策として、ElasticsearchのサービスのIPアドレスをマニフェストに記述することで解決する。
デプロイの度に、毎回 IPアドレスを設定するのはやってられないが、まず最終的な目的とする結果を得た後に考えたい。
Beat接続先IPアドレスの取得とマニフェストの編集
Beatがログを転送するべきサーバーのIPアドレスは、次のように求めることができる。
kubectl get svc elasticsearch-master
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch-master ClusterIP 10.32.0.3 <none> 9200/TCP,9300/TCP 61m
この10.32.0.3
を前述の3つのファイルに設定する。編集箇所は、73行目 ELASTICSEARCH_HOST の値になる。
72 env:
73 - name: ELASTICSEARCH_HOST
74 value: 10.32.0.3 ##elasticsearch-master.elasticsearch.svc.cluster.local
75 - name: ELASTICSEARCH_PORT
76 value: "9200"
77 - name: ELASTICSEARCH_USERNAME
78 value: <>
編集後にデプロイする。
kubectl apply -f filebeat-kubernetes.yaml
kubectl get pod -n kube-system -l k8s-app=filebeat
NAME READY STATUS RESTARTS AGE
filebeat-8j998 1/1 Running 0 60s
filebeat-jszwk 1/1 Running 0 60s
filebeat-t422c 1/1 Running 0 60s
同様にmetricbeat-kubernetes.yamlとauditbeat-kubernetes.yamlも編集してアプライする。
Beatの問題の詳細
ELASTICSEARCH_HOSTにDNS名でシッピング先をセットした場合、以下のように lookup で no such host のエラーとなる。
2020-01-26T04:08:33.186Z WARN transport/tcp.go:53 DNS lookup failure "elasticsearch-master.elasticsearch.svc.cluster.local": lookup elasticsearch-master.elasticsearch.svc.cluster.local: no such host
2020-01-26T04:08:34.335Z ERROR pipeline/output.go:100 Failed to connect to backoff(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
2020-01-26T04:08:34.335Z INFO pipeline/output.go:93 Attempting to reconnect to backoff(elasticsearch(http://elasticsearch-master.elasticsearch.svc.cluster.local:9200)) with 1 reconnect attempt(s)
しかしながら、DNSユーティリティのコンテナを使ってアドレスを確認すると、確かに登録されており、アドレスの解決ができることがわかる。つまり、Beatのポッドの設定に問題があることが確認できる。
tkr@luigi:~/sandbox-rook/beats/deploy/kubernetes$ kubectl exec -ti -n default dnsutils -- nslookup 10.32.0.34
34.0.32.10.in-addr.arpa name = elasticsearch-master.elasticsearch.svc.cluster.local.
Kibanaの設定と動作確認
左端に並ぶアイコンの一番したギヤーのアイコンをクリックすると、Beatからデータが転送されていることがわかる。このような状態になっていれば、各Beatからデータが転送されている。もし、表示がなければ、シッピング先のIPアドレスを再確認する。
次にDiscoverの設定を行っておく。左のアイコン列の上部方位磁針のアイコンをクリックしてFilebeatの頭文字にアスタリスクを設定する。そして、次へ進み、フィールドに @timestamp
を設定する。
この設定により、ログの受信状態を取得できる。
ログだけでなく、メトリックス情報も表示できる。
まとめ
ROOK Ceph でダイナミックプロビジョニングできる永続ストレージを利用して、ログ分析基盤 Elasticsearch と Kibana をデプロイすることができた。Beatは便利なツールで、Filebeatはワーカーノードにデプロイされたコンテナのファイルシステムを直接読み取るため、コンテナのログ収集のために、個別に設定することも不要となる。KibanaやElasticsearchは、とても便利なツールであり、このセットアップにフォーカスして記事を書いてみたい。
ここまでやってみて、一番辛いことは、適切に動作するOSSの組み合わせを探ることだ。また、OSSのプロジェクトは、それぞれ、非同期にプロジェクトを推進して、新しいバージョンやパッチを提供するため、常に注意を払っておかなければならない。また、脆弱性対応という点からも、OSのレベルアップを続けないければならない。ROOKは、このOSSのスタックをベースにしているストレージシステムである事から、安価に構築できる利点もあるが、維持するための運用が重要あることも忘れてはいけない。
番外 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.91:31178
<html ng-app="redis">
<head>
<title>Guestbook</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<以下省略>