KubernetesでElasticsearch、Fluentd、Kibana(EFK)のログスタックを設定する方法
序章
Kubernetesクラスタで複数のサービスとアプリケーションを実行する場合、一元化されたクラスタレベルのログスタックを使用すると、ポッドによって生成された大量のログデータをすばやく並べ替えて分析できます。 人気のある集中型ロギングソリューションの1つは、 E lasticsearch、 F luentd、および K ibana(EFK)スタックです。
Elasticsearch は、分析だけでなく、フルテキストおよび構造化された検索を可能にする、リアルタイムの分散型のスケーラブルな検索エンジンです。 大量のログデータのインデックス作成と検索に一般的に使用されますが、さまざまな種類のドキュメントの検索にも使用できます。
Elasticsearchは通常、Elasticsearchの強力なデータ視覚化フロントエンドおよびダッシュボードであるKibanaと一緒にデプロイされます。 Kibanaを使用すると、Webインターフェイスを介してElasticsearchログデータを探索し、ダッシュボードとクエリを作成して、質問にすばやく回答し、Kubernetesアプリケーションに関する洞察を得ることができます。
このチュートリアルでは、 Fluentd を使用して、ログデータを収集、変換し、Elasticsearchバックエンドに送信します。 Fluentdは人気のあるオープンソースのデータコレクターであり、Kubernetesノードにセットアップしてコンテナーログファイルを調整し、ログデータをフィルター処理して変換し、Elasticsearchクラスターに配信してインデックスを作成して保存します。
まず、スケーラブルなElasticsearchクラスターを構成して起動し、次にKibana Kubernetes ServiceandDeploymentを作成します。 結論として、FluentdをDaemonSetとして設定し、すべてのKubernetesワーカーノードで実行されるようにします。
前提条件
このガイドを開始する前に、次のものを利用できることを確認してください。
- ロールベースのアクセス制御(RBAC)が有効になっているKubernetes1.10+クラスター
- クラスターにEFKスタックをロールアウトするのに十分なリソースがあることを確認し、そうでない場合は、ワーカーノードを追加してクラスターをスケーリングします。 3ポッドのElasticsearchクラスター(必要に応じてこれを1にスケールダウンできます)と、単一のKibanaポッドをデプロイします。 すべてのワーカーノードはFluentdポッドも実行します。 このガイドのクラスターは、3つのワーカーノードとマネージドコントロールプレーンで構成されています。
- ローカルマシンにインストールされ、クラスターに接続するように構成された
kubectl
コマンドラインツール。kubectl
のインストールについて詳しくは、公式ドキュメントをご覧ください。
これらのコンポーネントを設定したら、このガイドを開始する準備が整います。
ステップ1—名前空間を作成する
Elasticsearchクラスターをロールアウトする前に、まず名前空間を作成し、そこにすべてのロギングインストルメンテーションをインストールします。 Kubernetesでは、ネームスペースと呼ばれる「仮想クラスター」抽象化を使用して、クラスターで実行されているオブジェクトを分離できます。 このガイドでは、EFKスタックコンポーネントをインストールするkube-logging
名前空間を作成します。 この名前空間を使用すると、Kubernetesクラスターの機能を失うことなく、ログスタックをすばやくクリーンアップして削除することもできます。
まず、kubectl
を使用して、クラスター内の既存の名前空間を調査します。
kubectl get namespaces
Kubernetesクラスタにプリインストールされている次の3つの初期ネームスペースが表示されます。
OutputNAME STATUS AGE default Active 5m kube-system Active 5m kube-public Active 5m
default
名前空間には、名前空間を指定せずに作成されたオブジェクトが格納されます。 kube-system
名前空間には、kube-dns
、kube-proxy
、kubernetes-dashboard
など、Kubernetesシステムによって作成および使用されるオブジェクトが含まれます。 この名前空間をクリーンに保ち、アプリケーションやインストルメンテーションのワークロードで汚染しないようにすることをお勧めします。
kube-public
名前空間は、認証されていないユーザーであっても、クラスター全体で読み取りおよびアクセスできるようにするオブジェクトを格納するために使用できる、もう1つの自動的に作成された名前空間です。
kube-logging
名前空間を作成するには、最初にkube-logging.yaml
というファイルを開き、nanoなどのお気に入りのエディターを使用して編集します。
nano kube-logging.yaml
エディター内に、次の名前空間オブジェクトYAMLを貼り付けます。
kube-logging.yaml
kind: Namespace apiVersion: v1 metadata: name: kube-logging
次に、ファイルを保存して閉じます。
ここでは、Kubernetesオブジェクトのkind
をNamespace
オブジェクトとして指定します。 Namespace
オブジェクトの詳細については、Kubernetesの公式ドキュメントの NamespacesWalkthroughを参照してください。 また、オブジェクトの作成に使用されるKubernetes APIバージョン(v1
)を指定し、name
、kube-logging
を指定します。
kube-logging.yaml
名前空間オブジェクトファイルを作成したら、kubectl create
と-f
ファイル名フラグを使用して名前空間を作成します。
kubectl create -f kube-logging.yaml
次の出力が表示されます。
Outputnamespace/kube-logging created
次に、ネームスペースが正常に作成されたことを確認できます。
kubectl get namespaces
この時点で、新しいkube-logging
名前空間が表示されます。
OutputNAME STATUS AGE default Active 23m kube-logging Active 1m kube-public Active 23m kube-system Active 23m
これで、Elasticsearchクラスターをこの分離されたロギング名前空間にデプロイできます。
ステップ2—ElasticsearchStatefulSetを作成する
ロギングスタックを格納する名前空間を作成したので、さまざまなコンポーネントの展開を開始できます。 まず、3ノードのElasticsearchクラスターをデプロイすることから始めます。
このガイドでは、3つのElasticsearchポッドを使用して、可用性の高いマルチノードクラスターで発生する「スプリットブレイン」の問題を回避します。 大まかに言うと、「スプリットブレイン」とは、1つ以上のノードが他のノードと通信できず、複数の「スプリット」マスターが選出されたときに発生するものです。 3つのノードでは、1つが一時的にクラスターから切断された場合、他の2つのノードは新しいマスターを選択でき、最後のノードが再参加を試みている間、クラスターは機能し続けることができます。 詳細については、Elasticsearchおよび投票構成でのクラスター調整の新時代を参照してください。
ヘッドレスサービスの作成
まず、3つのポッドのDNSドメインを定義するelasticsearch
というヘッドレスKubernetesサービスを作成します。 ヘッドレスサービスは、ロードバランシングを実行したり、静的IPを使用したりしません。 ヘッドレスサービスの詳細については、公式のKubernetesドキュメントを参照してください。
お気に入りのエディタを使用して、elasticsearch_svc.yaml
というファイルを開きます。
nano elasticsearch_svc.yaml
次のKubernetesサービスYAMLに貼り付けます。
Elasticsearch_svc.yaml
kind: Service apiVersion: v1 metadata: name: elasticsearch namespace: kube-logging labels: app: elasticsearch spec: selector: app: elasticsearch clusterIP: None ports: - port: 9200 name: rest - port: 9300 name: inter-node
次に、ファイルを保存して閉じます。
kube-logging
名前空間にelasticsearch
というService
を定義し、app: elasticsearch
ラベルを付けます。 次に、.spec.selector
をapp: elasticsearch
に設定して、サービスがapp: elasticsearch
ラベルの付いたポッドを選択するようにします。 Elasticsearch StatefulSetをこのサービスに関連付けると、サービスはapp: elasticsearch
ラベルが付いたElasticsearchポッドを指すDNSAレコードを返します。
次に、clusterIP: None
を設定します。これにより、サービスがヘッドレスになります。 最後に、RESTAPIとの対話とノード間通信にそれぞれ使用されるポート9200
と9300
を定義します。
kubectl
を使用してサービスを作成します。
kubectl create -f elasticsearch_svc.yaml
次の出力が表示されます。
Outputservice/elasticsearch created
最後に、kubectl get
を使用してサービスが正常に作成されたことを再確認します。
kubectl get services --namespace=kube-logging
次のように表示されます。
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 26s
ヘッドレスサービスとポッド用の安定した.elasticsearch.kube-logging.svc.cluster.local
ドメインを設定したので、StatefulSetを作成できます。
StatefulSetの作成
Kubernetes StatefulSetを使用すると、ポッドに安定したIDを割り当てて、安定した永続的なストレージを付与できます。 Elasticsearchには、ポッドの再スケジュールと再起動の間でデータを永続化するための安定したストレージが必要です。 StatefulSetワークロードの詳細については、KubernetesドキュメントのStatefulsetsページを参照してください。
お気に入りのエディタでelasticsearch_statefulset.yaml
というファイルを開きます。
nano elasticsearch_statefulset.yaml
StatefulSetオブジェクト定義をセクションごとに移動し、ブロックをこのファイルに貼り付けます。
次のブロックに貼り付けることから始めます。
Elasticsearch_statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: es-cluster namespace: kube-logging spec: serviceName: elasticsearch replicas: 3 selector: matchLabels: app: elasticsearch template: metadata: labels: app: elasticsearch
このブロックでは、kube-logging
名前空間にes-cluster
というStatefulSetを定義します。 次に、serviceName
フィールドを使用して、以前に作成したelasticsearch
サービスに関連付けます。 これにより、StatefulSet内の各ポッドに次のDNSアドレスを使用してアクセスできるようになります:es-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local
、ここで[0,1,2]
はポッドに割り当てられた整数の序数に対応します。
3つのreplicas
(ポッド)を指定し、matchLabels
セレクターをapp: elasticseach
に設定します。これを、.spec.template.metadata
セクションでミラーリングします。 .spec.selector.matchLabels
フィールドと.spec.template.metadata.labels
フィールドは一致する必要があります。
これで、オブジェクトの仕様に進むことができます。 前のブロックのすぐ下にあるYAMLの次のブロックに貼り付けます。
Elasticsearch_statefulset.yaml
. . . spec: containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0 resources: limits: cpu: 1000m requests: cpu: 100m ports: - containerPort: 9200 name: rest protocol: TCP - containerPort: 9300 name: inter-node protocol: TCP volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data env: - name: cluster.name value: k8s-logs - name: node.name valueFrom: fieldRef: fieldPath: metadata.name - name: discovery.seed_hosts value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch" - name: cluster.initial_master_nodes value: "es-cluster-0,es-cluster-1,es-cluster-2" - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m"
ここでは、StatefulSetでポッドを定義します。 コンテナーにelasticsearch
という名前を付け、docker.elastic.co/elasticsearch/elasticsearch:7.2.0
Dockerイメージを選択します。 この時点で、このイメージタグを変更して、独自の内部Elasticsearchイメージまたは別のバージョンに対応させることができます。 このガイドでは、Elasticsearch7.2.0
のみがテストされていることに注意してください。
次に、resources
フィールドを使用して、コンテナーに少なくとも0.1 vCPUが保証され、最大1 vCPUまでバーストできることを指定します(これにより、最初の大量の取り込みを実行したり、負荷を処理したりするときにポッドのリソース使用量が制限されますスパイク)。 予想される負荷と利用可能なリソースに応じて、これらの値を変更する必要があります。 リソースのリクエストと制限の詳細については、公式の KubernetesDocumentationを参照してください。
次に、RESTAPIとノード間通信用にそれぞれポート9200
と9300
を開いて名前を付けます。 data
という名前のvolumeMount
を指定して、data
という名前のPersistentVolumeをパス/usr/share/elasticsearch/data
のコンテナーにマウントします。 このStatefulSetのVolumeClaimsは、後のYAMLブロックで定義します。
最後に、コンテナにいくつかの環境変数を設定します。
cluster.name
:Elasticsearchクラスターの名前。このガイドではk8s-logs
です。node.name
:valueFrom
を使用して.metadata.name
フィールドに設定したノードの名前。 これは、ノードに割り当てられた序数に応じて、es-cluster-[0,1,2]
に解決されます。discovery.seed_hosts
:このフィールドは、ノード検出プロセスをシードするクラスター内のマスター適格ノードのリストを設定します。 このガイドでは、前に構成したヘッドレスサービスのおかげで、ポッドにはes-cluster-[0,1,2].elasticsearch.kube-logging.svc.cluster.local
の形式のドメインがあるため、それに応じてこの変数を設定します。 ローカル名前空間KubernetesDNS解決を使用して、これをes-cluster-[0,1,2].elasticsearch
に短縮できます。 Elasticsearchディスカバリーの詳細については、公式のElasticsearchドキュメントを参照してください。cluster.initial_master_nodes
:このフィールドは、マスター選出プロセスに参加するマスター適格ノードのリストも指定します。 このフィールドでは、ホスト名ではなく、node.name
でノードを識別する必要があることに注意してください。ES_JAVA_OPTS
:ここでは、これを-Xms512m -Xmx512m
に設定します。これは、JVMに512MBの最小および最大ヒープサイズを使用するように指示します。 クラスタのリソースの可用性とニーズに応じて、これらのパラメータを調整する必要があります。 詳細については、ヒープサイズの設定を参照してください。
貼り付ける次のブロックは次のようになります。
Elasticsearch_statefulset.yaml
. . . initContainers: - name: fix-permissions image: busybox command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"] securityContext: privileged: true volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data - name: increase-vm-max-map image: busybox command: ["sysctl", "-w", "vm.max_map_count=262144"] securityContext: privileged: true - name: increase-fd-ulimit image: busybox command: ["sh", "-c", "ulimit -n 65536"] securityContext: privileged: true
このブロックでは、メインのelasticsearch
アプリコンテナの前に実行されるいくつかのInitコンテナを定義します。 これらの初期化コンテナはそれぞれ、定義された順序で最後まで実行されます。 Init Containersの詳細については、公式の KubernetesDocumentationを参照してください。
1つ目はfix-permissions
という名前で、chown
コマンドを実行して、Elasticsearchデータディレクトリの所有者とグループをElasticsearchユーザーのUIDである1000:1000
に変更します。 デフォルトでは、Kubernetesはデータディレクトリをroot
としてマウントします。これにより、Elasticsearchにアクセスできなくなります。 この手順の詳細については、Elasticsearchの「本番環境での使用とデフォルトに関する注意事項」を参照してください。
2つ目はincrease-vm-max-map
という名前で、オペレーティングシステムのmmapカウントの制限を増やすコマンドを実行します。これはデフォルトでは低すぎるため、メモリ不足エラーが発生する可能性があります。 この手順の詳細については、公式のElasticsearchドキュメントを参照してください。
次に実行する初期化コンテナはincrease-fd-ulimit
で、ulimit
コマンドを実行して、開いているファイル記述子の最大数を増やします。 この手順の詳細については、Elasticsearchの公式ドキュメントの「本番環境での使用とデフォルトに関する注意事項」を参照してください。
注: Elasticsearch 本番環境での使用に関する注意には、パフォーマンス上の理由からスワッピングを無効にすることも記載されています。 Kubernetesのインストールまたはプロバイダーによっては、スワッピングがすでに無効になっている場合があります。 これを確認するには、exec
を実行中のコンテナーに入れ、cat /proc/swaps
を実行して、アクティブなスワップデバイスを一覧表示します。 そこに何も表示されない場合、スワップは無効になっています。
メインアプリコンテナと、その前に実行されるInitコンテナを定義してコンテナOSを調整したので、StatefulSetオブジェクト定義ファイルvolumeClaimTemplates
に最後のピースを追加できます。
次のvolumeClaimTemplate
ブロックに貼り付けます。
Elasticsearch_statefulset.yaml
. . . volumeClaimTemplates: - metadata: name: data labels: app: elasticsearch spec: accessModes: [ "ReadWriteOnce" ] storageClassName: do-block-storage resources: requests: storage: 100Gi
このブロックでは、StatefulSetのvolumeClaimTemplates
を定義します。 Kubernetesはこれを使用して、ポッドのPersistentVolumesを作成します。 上記のブロックでは、data
(前に定義したvolumeMount
で参照するname
)という名前を付け、同じapp: elasticsearch
を付けます。 ]StatefulSetとしてラベルを付けます。
次に、アクセスモードをReadWriteOnce
として指定します。これは、単一ノードによってのみ読み取り/書き込みとしてマウントできることを意味します。 デモの目的でDigitalOceanKubernetesクラスターを使用するため、このガイドではストレージクラスをdo-block-storage
と定義します。 この値は、Kubernetesクラスターを実行している場所に応じて変更する必要があります。 詳細については、 PersistentVolumeのドキュメントを参照してください。
最後に、各PersistentVolumeのサイズを100GiBにすることを指定します。 制作のニーズに応じて、この値を調整する必要があります。
完全なStatefulSet仕様は、次のようになります。
Elasticsearch_statefulset.yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: es-cluster namespace: kube-logging spec: serviceName: elasticsearch replicas: 3 selector: matchLabels: app: elasticsearch template: metadata: labels: app: elasticsearch spec: containers: - name: elasticsearch image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0 resources: limits: cpu: 1000m requests: cpu: 100m ports: - containerPort: 9200 name: rest protocol: TCP - containerPort: 9300 name: inter-node protocol: TCP volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data env: - name: cluster.name value: k8s-logs - name: node.name valueFrom: fieldRef: fieldPath: metadata.name - name: discovery.seed_hosts value: "es-cluster-0.elasticsearch,es-cluster-1.elasticsearch,es-cluster-2.elasticsearch" - name: cluster.initial_master_nodes value: "es-cluster-0,es-cluster-1,es-cluster-2" - name: ES_JAVA_OPTS value: "-Xms512m -Xmx512m" initContainers: - name: fix-permissions image: busybox command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"] securityContext: privileged: true volumeMounts: - name: data mountPath: /usr/share/elasticsearch/data - name: increase-vm-max-map image: busybox command: ["sysctl", "-w", "vm.max_map_count=262144"] securityContext: privileged: true - name: increase-fd-ulimit image: busybox command: ["sh", "-c", "ulimit -n 65536"] securityContext: privileged: true volumeClaimTemplates: - metadata: name: data labels: app: elasticsearch spec: accessModes: [ "ReadWriteOnce" ] storageClassName: do-block-storage resources: requests: storage: 100Gi
Elasticsearchの設定に問題がなければ、ファイルを保存して閉じます。
次に、kubectl
を使用してStatefulSetをデプロイします。
kubectl create -f elasticsearch_statefulset.yaml
次の出力が表示されます。
Outputstatefulset.apps/es-cluster created
kubectl rollout status
を使用して、StatefulSetがロールアウトされるときに監視できます。
kubectl rollout status sts/es-cluster --namespace=kube-logging
クラスタがロールアウトされると、次の出力が表示されます。
OutputWaiting for 3 pods to be ready... Waiting for 2 pods to be ready... Waiting for 1 pods to be ready... partitioned roll out complete: 3 new pods have been updated...
すべてのポッドがデプロイされたら、REST APIに対してリクエストを実行することで、Elasticsearchクラスターが正しく機能していることを確認できます。
これを行うには、最初にkubectl port-forward
を使用してローカルポート9200
をElasticsearchノードの1つ(es-cluster-0
)のポート9200
に転送します。
kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging
次に、別のターミナルウィンドウで、RESTAPIに対してcurl
リクエストを実行します。
curl http://localhost:9200/_cluster/state?pretty
次の出力が表示されます。
Output{ "cluster_name" : "k8s-logs", "compressed_size_in_bytes" : 348, "cluster_uuid" : "QD06dK7CQgids-GQZooNVw", "version" : 3, "state_uuid" : "mjNIWXAzQVuxNNOQ7xR-qg", "master_node" : "IdM5B7cUQWqFgIHXBp0JDg", "blocks" : { }, "nodes" : { "u7DoTpMmSCixOoictzHItA" : { "name" : "es-cluster-1", "ephemeral_id" : "ZlBflnXKRMC4RvEACHIVdg", "transport_address" : "10.244.8.2:9300", "attributes" : { } }, "IdM5B7cUQWqFgIHXBp0JDg" : { "name" : "es-cluster-0", "ephemeral_id" : "JTk1FDdFQuWbSFAtBxdxAQ", "transport_address" : "10.244.44.3:9300", "attributes" : { } }, "R8E7xcSUSbGbgrhAdyAKmQ" : { "name" : "es-cluster-2", "ephemeral_id" : "9wv6ke71Qqy9vk2LgJTqaA", "transport_address" : "10.244.40.4:9300", "attributes" : { } } }, ...
これは、Elasticsearchクラスターk8s-logs
が、es-cluster-0
、es-cluster-1
、およびes-cluster-2
の3つのノードで正常に作成されたことを示しています。 現在のマスターノードはes-cluster-0
です。
Elasticsearchクラスターが稼働しているので、Kibanaフロントエンドのセットアップに進むことができます。
ステップ3—Kibanaのデプロイメントとサービスの作成
KubernetesでKibanaを起動するには、kibana
というサービスと、1つのポッドレプリカで構成されるデプロイを作成します。 本番環境のニーズに応じてレプリカの数をスケーリングでき、オプションで、サービスのLoadBalancer
タイプを指定して、デプロイメントポッド間でリクエストの負荷を分散できます。
今回は、同じファイルにサービスとデプロイメントを作成します。 お気に入りのエディタでkibana.yaml
というファイルを開きます。
nano kibana.yaml
次のサービス仕様を貼り付けます。
kibana.yaml
apiVersion: v1 kind: Service metadata: name: kibana namespace: kube-logging labels: app: kibana spec: ports: - port: 5601 selector: app: kibana --- apiVersion: apps/v1 kind: Deployment metadata: name: kibana namespace: kube-logging labels: app: kibana spec: replicas: 1 selector: matchLabels: app: kibana template: metadata: labels: app: kibana spec: containers: - name: kibana image: docker.elastic.co/kibana/kibana:7.2.0 resources: limits: cpu: 1000m requests: cpu: 100m env: - name: ELASTICSEARCH_URL value: http://elasticsearch:9200 ports: - containerPort: 5601
次に、ファイルを保存して閉じます。
この仕様では、kube-logging
名前空間にkibana
というサービスを定義し、それにapp: kibana
ラベルを付けました。
また、ポート5601
でアクセス可能であり、app: kibana
ラベルを使用してサービスのターゲットポッドを選択するように指定しました。
Deployment
仕様では、kibana
というデプロイメントを定義し、ポッドレプリカを1つ指定します。
docker.elastic.co/kibana/kibana:7.2.0
の画像を使用しています。 この時点で、独自のプライベートまたはパブリックのKibanaイメージを使用するように置き換えることができます。
ポッドに対して少なくとも0.1vCPUを保証し、1vCPUの制限までバーストすることを指定します。 これらのパラメータは、予想される負荷と利用可能なリソースに応じて変更できます。
次に、ELASTICSEARCH_URL
環境変数を使用して、Elasticsearchクラスターのエンドポイントとポートを設定します。 Kubernetes DNSを使用すると、このエンドポイントはサービス名elasticsearch
に対応します。 このドメインは、3つのElasticsearchポッドのIPアドレスのリストに解決されます。 Kubernetes DNSの詳細については、サービスとポッドのDNSを参照してください。
最後に、Kibanaのコンテナポートを5601
に設定します。このポートに、kibana
サービスがリクエストを転送します。
Kibanaの構成に満足したら、kubectl
を使用してサービスとデプロイメントをロールアウトできます。
kubectl create -f kibana.yaml
次の出力が表示されます。
Outputservice/kibana created deployment.apps/kibana created
次のコマンドを実行して、ロールアウトが成功したことを確認できます。
kubectl rollout status deployment/kibana --namespace=kube-logging
次の出力が表示されます。
Outputdeployment "kibana" successfully rolled out
Kibanaインターフェースにアクセスするために、ローカルポートをKibanaを実行しているKubernetesノードにもう一度転送します。 kubectl get
を使用して、Kibanaポッドの詳細を取得します。
kubectl get pods --namespace=kube-logging
OutputNAME READY STATUS RESTARTS AGE es-cluster-0 1/1 Running 0 55m es-cluster-1 1/1 Running 0 54m es-cluster-2 1/1 Running 0 54m kibana-6c9fb4b5b7-plbg2 1/1 Running 0 4m27s
ここでは、Kibanaポッドがkibana-6c9fb4b5b7-plbg2
と呼ばれていることがわかります。
ローカルポート5601
をこのポッドのポート5601
に転送します。
kubectl port-forward kibana-6c9fb4b5b7-plbg2 5601:5601 --namespace=kube-logging
次の出力が表示されます。
OutputForwarding from 127.0.0.1:5601 -> 5601 Forwarding from [::1]:5601 -> 5601
次に、Webブラウザーで、次のURLにアクセスします。
http://localhost:5601
次のKibanaウェルカムページが表示された場合は、KibanaをKubernetesクラスターに正常にデプロイしています。
これで、EFKスタックの最後のコンポーネントであるログコレクターであるFluentdのロールアウトに進むことができます。
ステップ4—FluentdDaemonSetの作成
このガイドでは、FluentdをDaemonSetとして設定します。これは、Kubernetesクラスター内の各ノードで特定のポッドのコピーを実行するKubernetesワークロードタイプです。 このDaemonSetコントローラーを使用して、クラスター内のすべてのノードにFluentdロギングエージェントポッドをロールアウトします。 このロギングアーキテクチャの詳細については、Kubernetesの公式ドキュメントの「ノードロギングエージェントの使用」を参照してください。
Kubernetesでは、stdout
およびstderr
にログを記録するコンテナ化されたアプリケーションのログストリームがキャプチャされ、ノード上のJSONファイルにリダイレクトされます。 Fluentd Podは、これらのログファイルを調整し、ログイベントをフィルタリングし、ログデータを変換して、ステップ2でデプロイしたElasticsearchログバックエンドに送信します。
コンテナログに加えて、Fluentdエージェントは、kubelet、kube-proxy、DockerログなどのKubernetesシステムコンポーネントログを調整します。 Fluentdロギングエージェントによって調整されたソースの完全なリストを確認するには、ロギングエージェントの設定に使用されるkubernetes.confファイルを参照してください。 Kubernetesクラスタへのログインの詳細については、Kubernetesの公式ドキュメントの「ノードレベルでのロギング」を参照してください。
お気に入りのテキストエディタでfluentd.yaml
というファイルを開くことから始めます。
nano fluentd.yaml
繰り返しになりますが、Kubernetesオブジェクト定義をブロックごとに貼り付けて、コンテキストを提供します。 このガイドでは、Fluentdメンテナが提供するFluentdDaemonSet仕様を使用します。 Fluentdメンテナが提供するもう1つの役立つリソースは、 KuberentesFluentdです。
まず、次のServiceAccount定義を貼り付けます。
fluentd.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: fluentd namespace: kube-logging labels: app: fluentd
ここでは、FluentdポッドがKubernetesAPIにアクセスするために使用するfluentd
というサービスアカウントを作成します。 kube-logging
名前空間で作成し、もう一度app: fluentd
というラベルを付けます。 Kubernetesのサービスアカウントの詳細については、Kubernetesの公式ドキュメントのポッドのサービスアカウントの設定を参照してください。
次に、次のClusterRole
ブロックに貼り付けます。
fluentd.yaml
. . . --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: fluentd labels: app: fluentd rules: - apiGroups: - "" resources: - pods - namespaces verbs: - get - list - watch
ここでは、fluentd
というClusterRoleを定義し、get
、list
、およびwatch
にpods
およびnamespaces
オブジェクト。 ClusterRolesを使用すると、ノードなどのクラスタースコープのKubernetesリソースへのアクセスを許可できます。 ロールベースのアクセス制御とクラスタロールの詳細については、Kubernetesの公式ドキュメントのRBAC認証の使用を参照してください。
次に、次のClusterRoleBinding
ブロックに貼り付けます。
fluentd.yaml
. . . --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: fluentd roleRef: kind: ClusterRole name: fluentd apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: fluentd namespace: kube-logging
このブロックでは、fluentd
ClusterRoleをfluentd
サービスアカウントにバインドするfluentd
と呼ばれるClusterRoleBinding
を定義します。 これにより、fluentd
ServiceAccountにfluentd
クラスターロールにリストされているアクセス許可が付与されます。
この時点で、実際のDaemonSet仕様の貼り付けを開始できます。
fluentd.yaml
. . . --- apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd namespace: kube-logging labels: app: fluentd
ここでは、kube-logging
名前空間にfluentd
というDaemonSetを定義し、それにapp: fluentd
ラベルを付けます。
次に、次のセクションに貼り付けます。
fluentd.yaml
. . . spec: selector: matchLabels: app: fluentd template: metadata: labels: app: fluentd spec: serviceAccount: fluentd serviceAccountName: fluentd tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1 env: - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch.kube-logging.svc.cluster.local" - name: FLUENT_ELASTICSEARCH_PORT value: "9200" - name: FLUENT_ELASTICSEARCH_SCHEME value: "http" - name: FLUENTD_SYSTEMD_CONF value: disable
ここでは、.metadata.labels
で定義されているapp: fluentd
ラベルを照合し、DaemonSetにfluentd
サービスアカウントを割り当てます。 また、このDaemonSetによって管理されるポッドとしてapp: fluentd
を選択します。
次に、NoSchedule
許容値を定義して、Kubernetesマスターノードの同等の汚染に一致させます。 これにより、DaemonSetもKubernetesマスターにロールアウトされます。 マスターノードでFluentdPodを実行したくない場合は、この許容値を削除してください。 Kubernetesの汚染と許容範囲の詳細については、Kubernetesの公式ドキュメントの「汚染と許容範囲」を参照してください。
次に、fluentd
と呼ばれるポッドコンテナの定義を開始します。
Fluentdメンテナから提供された公式v1.4.2Debianイメージを使用します。 独自のプライベートまたはパブリックFluentdイメージを使用する場合、または別のイメージバージョンを使用する場合は、コンテナー仕様のimage
タグを変更します。 Dockerfileとこのイメージのコンテンツは、Fluentdのfluentd-kubernetes-daemonsetGithubリポジトリで入手できます。
次に、いくつかの環境変数を使用してFluentdを構成します。
FLUENT_ELASTICSEARCH_HOST
:これを前に定義したElasticsearchヘッドレスサービスアドレスelasticsearch.kube-logging.svc.cluster.local
に設定しました。 これは、3つのElasticsearchポッドのIPアドレスのリストに解決されます。 実際のElasticsearchホストは、このリストで返される最初のIPアドレスである可能性があります。 クラスター全体にログを分散するには、FluentdのElasticsearchOutputプラグインの構成を変更する必要があります。 このプラグインの詳細については、 Elasticsearch OutputPluginを参照してください。FLUENT_ELASTICSEARCH_PORT
:これを以前に構成したElasticsearchポート9200
に設定しました。FLUENT_ELASTICSEARCH_SCHEME
:これをhttp
に設定します。FLUENTD_SYSTEMD_CONF
:これをdisable
に設定して、コンテナに設定されていないsystemd
に関連する出力を抑制します。
最後に、次のセクションに貼り付けます。
fluentd.yaml
. . . resources: limits: memory: 512Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers
ここでは、FluentDポッドに512 MiBのメモリ制限を指定し、0.1vCPUと200MiBのメモリを保証します。 予想されるログ量と使用可能なリソースに応じて、これらのリソース制限とリクエストを調整できます。
次に、varlog
とvarlibdockercontainers
volumeMounts
を使用して、/var/log
と/var/lib/docker/containers
のホストパスをコンテナーにマウントします。 これらのvolumes
は、ブロックの最後に定義されています。
このブロックで定義する最後のパラメーターはterminationGracePeriodSeconds
です。これにより、FluentdはSIGTERM
信号を受信すると30秒で正常にシャットダウンします。 30秒後、コンテナにはSIGKILL
信号が送信されます。 terminationGracePeriodSeconds
のデフォルト値は30秒であるため、ほとんどの場合、このパラメーターは省略できます。 Kubernetesワークロードを正常に終了する方法の詳細については、Googleの「 Kubernetesのベストプラクティス:graceで終了する」をご覧ください。
Fluentdの仕様全体は次のようになります。
fluentd.yaml
apiVersion: v1 kind: ServiceAccount metadata: name: fluentd namespace: kube-logging labels: app: fluentd --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: fluentd labels: app: fluentd rules: - apiGroups: - "" resources: - pods - namespaces verbs: - get - list - watch --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: fluentd roleRef: kind: ClusterRole name: fluentd apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: fluentd namespace: kube-logging --- apiVersion: apps/v1 kind: DaemonSet metadata: name: fluentd namespace: kube-logging labels: app: fluentd spec: selector: matchLabels: app: fluentd template: metadata: labels: app: fluentd spec: serviceAccount: fluentd serviceAccountName: fluentd tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: fluentd image: fluent/fluentd-kubernetes-daemonset:v1.4.2-debian-elasticsearch-1.1 env: - name: FLUENT_ELASTICSEARCH_HOST value: "elasticsearch.kube-logging.svc.cluster.local" - name: FLUENT_ELASTICSEARCH_PORT value: "9200" - name: FLUENT_ELASTICSEARCH_SCHEME value: "http" - name: FLUENTD_SYSTEMD_CONF value: disable resources: limits: memory: 512Mi requests: cpu: 100m memory: 200Mi volumeMounts: - name: varlog mountPath: /var/log - name: varlibdockercontainers mountPath: /var/lib/docker/containers readOnly: true terminationGracePeriodSeconds: 30 volumes: - name: varlog hostPath: path: /var/log - name: varlibdockercontainers hostPath: path: /var/lib/docker/containers
Fluentd DaemonSetの設定が完了したら、ファイルを保存して閉じます。
次に、kubectl
を使用してDaemonSetをロールアウトします。
kubectl create -f fluentd.yaml
次の出力が表示されます。
Outputserviceaccount/fluentd created clusterrole.rbac.authorization.k8s.io/fluentd created clusterrolebinding.rbac.authorization.k8s.io/fluentd created daemonset.extensions/fluentd created
kubectl
を使用して、DaemonSetが正常にロールアウトされたことを確認します。
kubectl get ds --namespace=kube-logging
次のステータス出力が表示されます。
OutputNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE fluentd 3 3 3 3 3 <none> 58s
これは、3つのfluentd
ポッドが実行されていることを示しています。これは、Kubernetesクラスター内のノードの数に対応します。
これで、Kibanaをチェックして、ログデータが適切に収集されてElasticsearchに送信されていることを確認できます。
kubectl port-forward
を開いたまま、http://localhost:5601
に移動します。
左側のナビゲーションメニューでDiscoverをクリックします。
次の設定ウィンドウが表示されます。
これにより、Kibanaで探索するElasticsearchインデックスを定義できます。 詳細については、Kibanaの公式ドキュメントでインデックスパターンの定義を参照してください。 今のところ、logstash-*
ワイルドカードパターンを使用して、Elasticsearchクラスター内のすべてのログデータをキャプチャします。 テキストボックスにlogstash-*
と入力し、次のステップをクリックします。
その後、次のページに移動します。
これにより、Kibanaがログデータを時間でフィルタリングするために使用するフィールドを構成できます。 ドロップダウンで、 @timestamp フィールドを選択し、インデックスパターンの作成をクリックします。
次に、左側のナビゲーションメニューでDiscoverを押します。
ヒストグラムグラフといくつかの最近のログエントリが表示されます。
この時点で、KubernetesクラスターでEFKスタックを正常に構成してロールアウトできました。 Kibanaを使用してログデータを分析する方法については、Kibanaユーザーガイドを参照してください。
次のオプションのセクションでは、stdoutに数値を出力する単純なカウンターポッドをデプロイし、そのログをKibanaで検索します。
ステップ5(オプション)—コンテナログのテスト
特定のポッドの最新のログを探索する基本的なKibanaのユースケースを示すために、連続番号をstdoutに出力する最小限のカウンターポッドをデプロイします。
ポッドを作成することから始めましょう。 お気に入りのエディタでcounter.yaml
というファイルを開きます。
nano counter.yaml
次に、次のポッド仕様を貼り付けます。
counter.yaml
apiVersion: v1 kind: Pod metadata: name: counter spec: containers: - name: count image: busybox args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
ファイルを保存して閉じます。
これはcounter
と呼ばれる最小限のポッドで、while
ループを実行し、番号を順番に出力します。
kubectl
を使用して、counter
ポッドをデプロイします。
kubectl create -f counter.yaml
ポッドが作成されて実行されたら、Kibanaダッシュボードに戻ります。
Discover ページで、検索バーにkubernetes.pod_name:counter
と入力します。 これにより、counter
という名前のポッドのログデータがフィルタリングされます。
次に、counter
ポッドのログエントリのリストが表示されます。
いずれかのログエントリをクリックすると、コンテナ名、Kubernetesノード、名前空間などの追加のメタデータを表示できます。
結論
このガイドでは、KubernetesクラスターでElasticsearch、Fluentd、およびKibanaをセットアップおよび構成する方法を示しました。 各Kubernetesワーカーノードで実行される単一のロギングエージェントポッドで構成される最小限のロギングアーキテクチャを使用しました。
このロギングスタックを本番Kubernetesクラスターにデプロイする前に、このガイド全体に示されているように、リソースの要件と制限を調整することをお勧めします。 X-Pack を設定して、組み込みの監視およびセキュリティ機能を有効にすることもできます。
ここで使用したロギングアーキテクチャは、3つのElasticsearchポッド、1つのKibanaポッド(負荷分散されていない)、およびDaemonSetとしてロールアウトされたFluentdポッドのセットで構成されています。 本番ユースケースに応じて、この設定を拡張することをお勧めします。 ElasticsearchとKibanaスタックのスケーリングの詳細については、Elasticsearchのスケーリングを参照してください。
Kubernetesでは、ユースケースにより適した、より複雑なロギングエージェントアーキテクチャも使用できます。 詳細については、Kubernetesドキュメントのログアーキテクチャを参照してください。