KubernetesでElasticsearch、Fluentd、Kibana(EFK)ログスタックを設定する方法

前書き

Kubernetesクラスターで複数のサービスとアプリケーションを実行する場合、集中化されたクラスターレベルのログスタックを使用すると、Podによって生成された大量のログデータをすばやく分類して分析できます。 人気のある集中ログソリューションの1つは、Elasticsearch、Fluentd、およびKibana(EFK)スタックです。

Elasticsearchは、リアルタイムの分散型でスケーラブルな検索エンジンであり、フルテキスト検索と構造化検索、および分析を可能にします。 一般に、大量のログデータのインデックス作成と検索に使用されますが、さまざまな種類のドキュメントの検索にも使用できます。

Elasticsearchは通常、Elasticsearchの強力なデータ視覚化フロントエンドおよびダッシュボードであるKibanaと一緒にデプロイされます。 Kibanaを使用すると、Webインターフェースを介してElasticsearchログデータを探索し、ダッシュボードとクエリを作成して質問にすばやく回答し、Kubernetesアプリケーションの洞察を得ることができます。

このチュートリアルでは、Fluentdを使用して、ログデータを収集、変換し、Elasticsearchバックエンドに送信します。 Fluentdは人気のあるオープンソースのデータコレクターであり、Kubernetesノードに設定してコンテナーログファイルを追跡し、ログデータをフィルター処理して変換し、それをElasticsearchクラスターに配信します。

まず、スケーラブルなElasticsearchクラスターを構成して起動してから、Kibana Kubernetes Service and Deploymentを作成します。 最後に、FluentdをDaemonSetとして設定し、すべてのKubernetesワーカーノードで実行されるようにします。

前提条件

このガイドを始める前に、次のものが利用可能であることを確認してください。

  • 役割ベースのアクセス制御(RBAC)が有効になっているKubernetes 1.10+クラスター

    • クラスターにEFKスタックを展開するのに十分なリソースがあることを確認し、ワーカーノードを追加してクラスターをスケーリングしない場合。 3ポッドのElasticsearchクラスター(必要に応じてこれを1に縮小できます)と、単一のKibanaポッドをデプロイします。 すべてのワーカーノードもFluentdポッドを実行します。 このガイドのクラスターは、3つのワーカーノードと管理されたコントロールプレーンで構成されています。

  • ローカルマシンにインストールされ、クラスターに接続するように構成されたkubectlコマンドラインツール。 kubectlin the official documentationのインストールについて詳しく読むことができます。

これらのコンポーネントをセットアップしたら、このガイドから始める準備ができました。

[[step-1 -—-名前空間の作成]] ==ステップ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-dnskube-proxykubernetes-dashboardなど、Kubernetesシステムによって作成および使用されるオブジェクトが含まれます。 この名前空間をクリーンな状態に保ち、アプリケーションとインストルメンテーションのワークロードで汚染しないようにすることをお勧めします。

kube-public名前空間は、認証されていないユーザーであっても、クラスター全体で読み取りおよびアクセスできるようにするオブジェクトを格納するために使用できる、もう1つの自動的に作成された名前空間です。

kube-logging名前空間を作成するには、まず、nanoなどのお気に入りのエディターを使用してkube-logging.yamlというファイルを開いて編集します。

nano kube-logging.yaml

エディター内で、次の名前空間オブジェクトYAMLを貼り付けます。

kube-logging.yaml

kind: Namespace
apiVersion: v1
metadata:
  name: kube-logging

次に、ファイルを保存して閉じます。

ここでは、KubernetesオブジェクトのkindNamespaceオブジェクトとして指定します。 Namespaceオブジェクトの詳細については、Kubernetesの公式ドキュメントのNamespaces Walkthroughを参照してください。 また、オブジェクトの作成に使用されるKubernetes APIバージョン(v1)を指定し、それにnamekube-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クラスターをこの分離されたロギングネームスペースにデプロイできます。

[[step-2 -—- creating-the-elasticsearch-statefulset]] ==ステップ2— ElasticsearchStatefulSetを作成する

ロギングスタックを格納する名前空間を作成したので、さまざまなコンポーネントの展開を開始できます。 まず、3ノードのElasticsearchクラスターを展開します。

このガイドでは、3つのElasticsearchポッドを使用して、可用性の高いマルチノードクラスターで発生する「スプリットブレイン」問題を回避します。 高レベルでは、「スプリットブレイン」は、1つ以上のノードが他のノードと通信できず、複数の「スプリット」マスターが選出されるときに発生します。 3つのノードでは、1つが一時的にクラスターから切断された場合、他の2つのノードが新しいマスターを選出し、最後のノードが再参加を試みている間クラスターは機能を継続できます。 詳細については、A new era for cluster coordination in ElasticsearchおよびVoting configurationsを参照してください。

ヘッドレスサービスの作成

まず、3つのポッドのDNSドメインを定義するelasticsearchというヘッドレスKubernetesサービスを作成します。 ヘッドレスサービスは、ロードバランシングを実行しないか、静的IPを持ちません。ヘッドレスサービスの詳細については、公式のKubernetes documentationを参照してください。

お気に入りのエディターを使用して、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.selectorapp: elasticsearchに設定して、サービスがapp: elasticsearchラベルの付いたポッドを選択するようにします。 Elasticsearch StatefulSetをこのサービスに関連付けると、サービスは、app: elasticsearchラベルが付いたElasticsearchポッドを指すDNSAレコードを返します。

次に、clusterIP: Noneを設定します。これにより、サービスがヘッドレスになります。 最後に、REST APIとの対話とノード間通信にそれぞれ使用されるポート92009300を定義します。

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                 9200/TCP,9300/TCP   26s

ポッド用にヘッドレスサービスと安定した.elasticsearch.kube-logging.svc.cluster.localドメインを設定したので、先に進んでStatefulSetを作成できます。

StatefulSetの作成

Kubernetes StatefulSetを使用すると、ポッドに安定したIDを割り当てて、安定した永続的なストレージを付与できます。 Elasticsearchでは、Podの再スケジュールと再起動の間でデータを保持するために安定したストレージが必要です。 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.0Dockerイメージを選択します。 この時点で、このイメージタグを変更して、独自の内部Elasticsearchイメージまたは別のバージョンに対応させることができます。 このガイドでは、Elasticsearch7.2.0のみがテストされていることに注意してください。

次に、resourcesフィールドを使用して、コンテナーに少なくとも0.1 vCPUが保証されている必要があり、最大1つのvCPUをバーストできることを指定します(これにより、最初の大量の取り込みを実行するとき、または負荷の急増に対処するときのポッドのリソース使用量が制限されます)。 これらの値は、予想される負荷と利用可能なリソースに応じて変更する必要があります。 リソースのリクエストと制限の詳細については、公式のKubernetes Documentationを参照してください。

次に、REST APIとノード間通信用にそれぞれポート92009300を開いて名前を付けます。 dataという名前のPersistentVolumeをパス/usr/share/elasticsearch/dataのコンテナーにマウントするdataという名前のvolumeMountを指定します。 この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 documentationを参照してください。

  • cluster.initial_master_nodes:このフィールドは、マスター選出プロセスに参加するマスター適格ノードのリストも指定します。 このフィールドでは、ホスト名ではなく、node.nameでノードを識別する必要があることに注意してください。

  • ES_JAVA_OPTS:ここでは、これを-Xms512m -Xmx512mに設定します。これは、JVMに512MBの最小および最大ヒープサイズを使用するように指示します。 これらのパラメーターは、クラスターのリソースの可用性とニーズに応じて調整する必要があります。 詳細については、Setting the heap sizeを参照してください。

貼り付ける次のブロックは次のようになります。

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の詳細については、公式のKubernetes Documentationを参照してください。

1つ目はfix-permissionsという名前で、chownコマンドを実行して、Elasticsearchデータディレクトリの所有者とグループをElasticsearchユーザーのUIDである1000:1000に変更します。 デフォルトでは、Kubernetesはデータディレクトリをrootとしてマウントします。これにより、Elasticsearchからアクセスできなくなります。 この手順の詳細については、Elasticsearchの「https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults [本番環境での使用とデフォルトに関する注意事項]」をご覧ください。

2番目の名前はincrease-vm-max-mapで、コマンドを実行して、オペレーティングシステムのmmapカウントの制限を増やします。これはデフォルトでは低すぎるため、メモリ不足エラーが発生する可能性があります。 このステップの詳細については、公式のElasticsearch documentationを参照してください。

次に実行するInitコンテナはincrease-fd-ulimitです。これは、ulimitコマンドを実行して、開いているファイル記述子の最大数を増やします。 この手順の詳細については、公式のElasticsearchドキュメントの「https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_notes_for_production_use_and_defaults [プロダクションの使用とデフォルトに関する注意事項]」を参照してください。

[.note]#Note: ElasticsearchNotes for Production Useは、パフォーマンス上の理由からスワッピングを無効にすることにも言及しています。 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はこれを使用して、ポッドのPersistentVolumeを作成します。 上記のブロックでは、datavolumeMount+`s defined previously), and give it the same `+app: elasticsearchラベルでStatefulSetと呼ばれるname)という名前を付けています。

次に、アクセスモードをReadWriteOnceとして指定します。これは、単一ノードによってのみ読み取り/書き込みとしてマウントできることを意味します。 デモの目的でDigitalOceanKubernetesクラスターを使用するため、このガイドではストレージクラスをdo-block-storageと定義します。 Kubernetesクラスターを実行している場所に応じて、この値を変更する必要があります。 詳細については、Persistent Volumeのドキュメントを参照してください。

最後に、各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...

すべてのPodがデプロイされたら、REST APIに対してリクエストを実行して、Elasticsearchクラスターが正しく機能していることを確認できます。

これを行うには、最初にローカルポート9200kubectl port-forwardを使用してElasticsearchノード(es-cluster-0)の1つのポート9200に転送します。

kubectl port-forward es-cluster-0 9200:9200 --namespace=kube-logging

次に、別のターミナルウィンドウで、REST APIに対して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-0es-cluster-1、およびes-cluster-2の3つのノードで正常に作成されたことを示しています。 現在のマスターノードはes-cluster-0です。

Elasticsearchクラスターが稼働しているので、Kibanaフロントエンドのセットアップに進むことができます。

[[step-3 -—- creating-the-kibana-deployment-and-service]] ==ステップ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.1 vCPUを保証し、1 vCPUの制限までバーストすることを指定します。 これらのパラメータは、予想される負荷と利用可能なリソースに応じて変更できます。

次に、ELASTICSEARCH_URL環境変数を使用して、Elasticsearchクラスターのエンドポイントとポートを設定します。 Kubernetes DNSを使用すると、このエンドポイントはサービス名elasticsearchに対応します。 このドメインは、3つのElasticsearchポッドのIPアドレスのリストに解決されます。 Kubernetes DNSの詳細については、DNS for Services and Podsを参照してください。

最後に、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ウェルカムページが表示されたら、KubernetesクラスターにKibanaが正常にデプロイされています。

Kibana Welcome Screen

これで、EFKスタックの最終コンポーネントであるログコレクターFluentdの展開に進むことができます。

[[step-4 -—- creating-the-fluentd-daemonset]] ==ステップ4— FluentdDaemonSetの作成

このガイドでは、FluentdをDaemonSetとして設定します。これは、Kubernetesクラスター内の各ノードで特定のPodのコピーを実行するKubernetesワークロードタイプです。 このDaemonSetコントローラーを使用して、クラスター内のすべてのノードでFluentdログエージェントポッドを展開します。 このロギングアーキテクチャの詳細については、公式Kubernetesの「https://kubernetes.io/docs/concepts/cluster-administration/logging/#using-a-node-logging-agent [ノードロギングエージェントの使用]」を参照してください。 docs。

Kubernetesでは、stdoutstderrにログを記録するコンテナ化されたアプリケーションのログストリームがキャプチャされ、ノード上のJSONファイルにリダイレクトされます。 Fluentd Podは、これらのログファイルを調整し、ログイベントをフィルタリングし、ログデータを変換して、Step 2でデプロイしたElasticsearchログバックエンドに送信します。

Fluentdエージェントは、コンテナログに加えて、kubelet、kube-proxy、DockerログなどのKubernetesシステムコンポーネントログを追跡します。 Fluentdロギングエージェントによって調整されたソースの完全なリストを表示するには、ロギングエージェントの構成に使用されるkubernetes.confファイルを参照してください。 Kubernetesクラスターでのロギングの詳細については、公式の「https://kubernetes.io/docs/concepts/cluster-administration/logging/#logging-at-the-node-level [ノードレベルでのロギング]」を参照してください。 Kubernetesのドキュメント。

お気に入りのテキストエディタでfluentd.yamlというファイルを開くことから始めます。

nano fluentd.yaml

繰り返しになりますが、Kubernetesオブジェクト定義をブロックごとに貼り付けて、コンテキストを提供します。 このガイドでは、Fluentdメンテナが提供するFluentd DaemonSet specを使用します。 Fluentdメンテナが提供するもう1つの役立つリソースは、Kuberentes Fluentdです。

まず、次のServiceAccount定義を貼り付けます。

fluentd.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd
  namespace: kube-logging
  labels:
    app: fluentd

ここでは、FluentdポッドがKubernetes APIにアクセスするために使用するfluentdというサービスアカウントを作成します。 kube-logging名前空間で作成し、もう一度ラベルapp: fluentdを付けます。 Kubernetesのサービスアカウントの詳細については、Kubernetesの公式ドキュメントのConfigure Service Accounts for Podsを参照してください。

次に、次の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

ここでは、podsおよびnamespacesオブジェクトに対するgetlist、およびwatchアクセス許可を付与するfluentdというClusterRoleを定義します。 ClusterRolesを使用すると、ノードなどのクラスタースコープのKubernetesリソースへのアクセスを許可できます。 ロールベースのアクセス制御とクラスターロールの詳細については、Kubernetesの公式ドキュメントのUsing RBAC Authorizationを参照してください。

ここで、次の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を選択します。

次に、Kubernetesマスターノードの同等の汚染に一致するNoSchedule許容値を定義します。 これにより、DaemonSetもKubernetesマスターに確実にロールアウトされます。 マスターノードでFluentd Podを実行したくない場合は、この許容を削除します。 Kubernetesの汚染と許容の詳細​​については、Kubernetesの公式ドキュメントの「https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/[Taints and Tolerations]」を参照してください。

次に、fluentdと呼ばれるポッドコンテナの定義を開始します。

Fluentdメンテナから提供されたofficial v1.4.2 Debian imageを使用します。 独自のプライベートまたはパブリックFluentdイメージを使用する場合、または別のイメージバージョンを使用する場合は、コンテナー仕様のimageタグを変更します。 Dockerfileとこのイメージのコンテンツは、Fluentdのfluentd-kubernetes-daemonset Github repoで利用できます。

次に、いくつかの環境変数を使用してFluentdを構成します。

  • FLUENT_ELASTICSEARCH_HOST:これを前に定義したElasticsearchヘッドレスサービスアドレスelasticsearch.kube-logging.svc.cluster.localに設定します。 これは、3つのElasticsearchポッドのIPアドレスのリストに解決されます。 実際のElasticsearchホストは、おそらくこのリストで最初に返されるIPアドレスです。 クラスター全体にログを配布するには、FluentdのElasticsearch Outputプラグインの構成を変更する必要があります。 このプラグインの詳細については、Elasticsearch Output Pluginを参照してください。

  • 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のメモリを保証します。 予想されるログボリュームと利用可能なリソースに応じて、これらのリソース制限とリクエストを調整できます。

次に、varlogvarlibdockercontainersvolumeMountsを使用して、/var/log/var/lib/docker/containersのホストパスをコンテナーにマウントします。 これらのvolumesは、ブロックの最後で定義されます。

このブロックで定義する最後のパラメーターはterminationGracePeriodSecondsです。これにより、FluentdはSIGTERMシグナルを受信すると30秒で正常にシャットダウンします。 30秒後、コンテナにはSIGKILLシグナルが送信されます。 terminationGracePeriodSecondsのデフォルト値は30秒​​であるため、ほとんどの場合、このパラメーターは省略できます。 Kubernetesのワークロードを正常に終了する方法の詳細については、Googleの「https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-terminating-with-grace[Kubernetesベストプラクティス:猶予で終了]」を参照してください。

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                     58s

これは、3fluentdのポッドが実行されていることを示しています。これは、Kubernetesクラスター内のノードの数に対応します。

Kibanaをチェックして、ログデータが適切に収集され、Elasticsearchに送信されていることを確認できます。

kubectl port-forwardを開いたまま、http://localhost:5601に移動します。

左側のナビゲーションメニューでDiscoverをクリックします。

Kibana Discover

次の構成ウィンドウが表示されます。

Kibana Index Pattern Configuration

これにより、Kibanaで探索したいElasticsearchインデックスを定義できます。 詳細については、Kibanaの公式ドキュメントのDefining your index patternsを参照してください。 今のところ、logstash-*ワイルドカードパターンを使用して、Elasticsearchクラスター内のすべてのログデータをキャプチャします。 テキストボックスにlogstash-*と入力し、Next stepをクリックします。

その後、次のページに移動します。

Kibana Index Pattern Settings

これにより、Kibanaがログデータを時間でフィルタリングするために使用するフィールドを構成できます。 ドロップダウンで、@timestampフィールドを選択し、Create index patternを押します。

次に、左側のナビゲーションメニューでDiscoverを押します。

ヒストグラムグラフといくつかの最近のログエントリが表示されます。

Kibana Incoming Logs

この時点で、KubernetesクラスターでEFKスタックの構成とロールアウトが正常に完了しました。 Kibanaを使用してログデータを分析する方法については、Kibana User Guideを参照してください。

次のオプションセクションでは、数値を標準出力に出力する単純なカウンターポッドをデプロイし、Kibanaでログを検索します。

[[step-5-optional--testing-container-logging]] ==ステップ5(オプション)—コンテナロギングのテスト

特定のポッドの最新ログを調査する基本的なKibanaの使用例を示すために、連続番号を標準出力に出力する最小限のカウンターポッドを展開します。

ポッドを作成することから始めましょう。 お気に入りのエディターで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']

ファイルを保存して閉じます。

これは、whileループを実行し、番号を順番に出力する、counterと呼ばれる最小のポッドです。

kubectlを使用してcounterポッドをデプロイします。

kubectl create -f counter.yaml

ポッドを作成して実行したら、Kibanaダッシュボードに戻ります。

Discoverページで、検索バーにkubernetes.pod_name:counterと入力します。 これにより、counterという名前のポッドのログデータがフィルタリングされます。

次に、counterポッドのログエントリのリストが表示されます。

Counter Logs in Kibana

任意のログエントリをクリックして、コンテナ名、Kubernetesノード、ネームスペースなどの追加のメタデータを表示できます。

結論

このガイドでは、KubernetesクラスターでElasticsearch、Fluentd、Kibanaを設定および構成する方法を示しました。 各Kubernetesワーカーノードで実行される単一のログエージェントポッドで構成される最小限のログアーキテクチャを使用しました。

このロギングスタックを運用Kubernetesクラスターにデプロイする前に、このガイド全体で示されているリソース要件と制限を調整することをお勧めします。 組み込みの監視およびセキュリティ機能を有効にするために、X-Packを設定することもできます。

ここで使用したロギングアーキテクチャは、3つのElasticsearchポッド、単一のKibanaポッド(負荷分散されていない)、およびDaemonSetとして展開されたFluentdポッドのセットで構成されています。 実稼働ユースケースに応じて、このセットアップをスケーリングすることもできます。 ElasticsearchとKibanaスタックのスケーリングの詳細については、Scaling Elasticsearchを参照してください。

Kubernetesでは、ユースケースにより適した、より複雑なログエージェントアーキテクチャも使用できます。 詳細については、KubernetesドキュメントのLogging Architectureを参照してください。

Related