K8S+DevOpsアーキテクト実践コース|業務ログ収集を実現するEFKを使った実践

ビデオ ソース: Station B「Docker&k8s チュートリアルの天井、Station B が教える絶対に最高のもの、Docker のすべてのコア知識を取得するための k8s 学習セットはここにあります」

学習中に先生の授業内容やテストノートを整理してみんなで共有してください。違反しているものは削除されます。よろしくお願いします。

概要投稿を添付してください: K8S+DevOps アーキテクト実践コース | 概要


EFK アーキテクチャのワークフロー

  • Elasticsearch は、オープンソースの分散型 Restful スタイルの検索およびデータ分析エンジンであり、その最下層はオープンソース ライブラリ Apache Lucene です。これは正確に次のように説明できます: 各フィールドのインデックス付けと検索が可能な分散型リアルタイム ドキュメント ストレージ、分散型リアルタイム分析検索エンジン、数百のサービス ノードを拡張可能、構造化または非構造化 PB レベルの構造をサポートデータ。
  • Kibana Kibana は、Elasticsearch と連携するように設計されたオープンソースの分析および視覚化プラットフォームです。Kibana を使用すると、Elasticsearch インデックスに保存されているデータを検索、表示、操作できます。高度なデータ分析も簡単に実行でき、データをさまざまなチャート、表、地図で視覚化できます。
  • Fluentd は 、ログの収集、処理、転送システムです。豊富なプラグイン システムを通じて、さまざまなシステムやアプリケーションからログを収集し、ユーザー指定の形式に変換し、ユーザーが指定したログ ストレージ システムに転送できます。Fluentd は、指定されたデータ ソースのセットからログ データを取得し、処理し (構造化データ形式に変換し)、Elasticsearch、オブジェクト ストレージ、kafka などの他のサービスに転送します。Fluentd は 300 を超えるログ ストレージと分析サービスをサポートしているため、この点で非常に柔軟です。主な動作手順は、まず Fluentd が複数のログソースからデータを取得し、構造化されたタグを付けて、一致するタグに従って複数の対象サービスにデータを送信します。

流暢な集中スピーキング

Fluentd アーキテクチャ

k8s システムのログ収集ツールとして fluentd を使用することが推奨されるのはなぜですか?

  • プラグイン可能なアーキテクチャ設計

  • リソース占有量が非常に少ない C および Ruby 言語に基づいており、30 ~ 40MB、13,000 イベント/秒/コア

  • 極めて高い信頼性 インメモリおよびローカル ファイルベースのキャッシュ 強力なフェイルオーバー

Fluentdイベントフローのライフサイクルと命令構成

Input -> filter 1 -> ... -> filter N -> Buffer -> Output

開始コマンド

$ fluentd -c fluent.conf

命令の紹介:

  • source  、データ ソース、入力に対応します。source コマンドを使用して、必要な入力プラグインを選択して構成し、Fluentd 入力ソースを有効にし、source がイベントを fluentd のルーティング エンジンに送信します。さまざまな種類のデータ ソースを区別するには、type を使用します。次の構成では、指定されたファイルの追加入力を監視できます。
<source>
  @type tail
  path /var/log/httpd-access.log
  pos_file /var/log/td-agent/httpd-access.log.pos
  tag myapp.access
  format apache2
</source>
  • フィルター、イベント処理パイプライン (イベント処理フロー) フィルターを直列に接続してパイプラインを形成し、データを逐次処理し、最後に出力用のマッチングに渡すことができます。イベントの内容は次のように処理できます: <source> @type http port 9880 </source> <filter myapp.access> @type record_transformer <record> host_param “#{Socket.gethostname}” </record> </filter> フィルターデータを取得した後、組み込みの @type Record_transformer プラグインを呼び出し、新しいフィールド host_param をイベント レコードに挿入し、それを出力用の照合に渡します。
  • labelコマンドはソースに@labelを指定することができ、このソースによってトリガーされたイベントは指定されたラベルに含まれるタスクに送信され、後続の他のタスクでは取得されません。<source>@type forward</source><source>### このタスクではラベルを @SYSTEM### として指定します。ラベルは <label @SYSTEM>### に送信され、次のフィルターと一致には送信されません。 @type tail@label @SYSTEMpath /var/log/httpd-access.logpos_file /var/log/td-agent/httpd-access.log.posttag myapp.accessformat apache2</source><フィルター アクセス。>@type Record_transformer< Record># …</record></filter><match  >@type elasticsearch# …</match><label @SYSTEM>### は、<filter var.log .middleware の上の @type tail のソース イベントを受け取ります。>@type grep# …</filter><match  >@type s3# …</match></label>
  • match の場合、match 出力は「タグ」に一致するイベントを検索し、それらを処理します。match コマンドの最も一般的な使用法は、イベントを他のシステムに出力することです (したがって、match コマンドに対応するプラグインは「出力プラグイン」と呼ばれます) <source> @type http port 9880 </source> <filter myapp.access > @type record_transformer <record> host_param “#{Socket.gethostname}” </record> </filter> <match myapp.access> @type ファイルパス /var/log/fluent/access </match>

イベントの構造:

time: イベントの処理時間

タグ: イベントのソース (fluentd.conf で設定)

レコード: 実際のログ内容、json オブジェクト

たとえば、次の元のログ:

192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777

Fluentd エンジンによって処理されると、次のようになります。

2020-07-16 08:40:35 +0000 apache.access: {"user":"-","method":"GET","code":200,"size":777,"host":"192.168.0.1","path":"/"}

fluentdのバッファイベントバッファモデル

Input -> filter 1 -> ... -> filter N -> Buffer -> Output

通常、各イベントのデータ量は非常に小さいため、データ転送の効率や安定性の理由を考慮すると、基本的に各イベントが処理された直後に出力側に書き込まれることはありません。そこで、fluentd は、データの主要部分であるバッファー モデルを確立しています。それは 2 つの概念があります。

  • buffer_chunk: ローカルで処理され、宛先に送信されるイベントを保存するために使用されるイベント バッファ ブロック。各ブロックのサイズを設定できます。
  • buffer_queue: チャンクを格納するキュー、長さは設定可能

設定できるパラメータは主に以下のとおりです。

  • buffer_type、バッファタイプ、ファイルまたはメモリに設定可能
  • buffer_chunk_limit、各チャンクブロックのサイズ、デフォルトは8MBです
  • buffer_queue_limit、チャンク ブロック キューの最大長、デフォルトは 256
  • flash_interval、チャンクをフラッシュする時間間隔
  • retry_limit、チャンクブロック送信失敗時の再試行回数。デフォルトは17回で、その後チャンクデータは破棄されます。
  • retry_wait、チャンク データの送信を再試行する時間間隔、デフォルトは 1 秒、2 回目の失敗が再送信される場合、間隔は 2 秒、次回は 4 秒など

一般的なプロセスは次のとおりです。

Fluentd イベントが継続的に生成され、チャンクに書き込まれるため、キャッシュ ブロックは大きくなり続けます。キャッシュ ブロックがbuffer_chunk_limit サイズに達するか、新しいキャッシュ ブロックがフラッシュ_インターバル時間間隔を超えて生成されると、キャッシュ ブロックはキャッシュの最後にプッシュされます。キューのサイズは、buffer_queue_limit によって決まります。

新しいチャンクがキューに入れられるたびに、キューの先頭のチャンク ブロックが構成されたストレージ バックエンドにすぐに書き込まれます。たとえば、Kafka が構成されている場合、データはすぐに Kafka にプッシュされます。

理想的な状況は、新しいキャッシュ ブロックがキャッシュ キューに入るたびに、すぐにバックエンドに書き込まれることです。同時に、新しいキャッシュ ブロックは引き続きキューに入れられますが、エンキュー速度は、このように、キャッシュ キューは基本的に空であり、キュー内には最大 1 つのキャッシュ ブロックが存在します。

ただし、実際の状況では、ネットワークなどの要因を考慮すると、キャッシュ ブロックをバックエンド ストレージに書き込むときに遅延や書き込み失敗が発生することが多く、キャッシュ ブロックのバックエンドへの書き込みに失敗すると、キャッシュ ブロックはそのまま残ります。 retry_wait 時間後に送信を再試行し、リトライ回数が retry_limit に達すると、キャッシュブロックが破壊されます (データが破棄されます)。

現時点では、キャッシュ キューには引き続き新しいキャッシュ ブロックが入っています。バックエンド ストレージに時間内に書き込まれていないキャッシュ ブロックがキュー内に多数ある場合、キューの長さがbuffer_queue_limit サイズに達すると、新しいイベントが発生します。拒否されると、fluentd はエラー、error_class=Fluent ::Plugin::Buffer::BufferOverflowError error="バッファ スペースにデータが多すぎます" を報告します。

もう 1 つの状況は、ネットワーク送信が遅いということです。新しいブロックが 3 秒ごとに生成されるが、バックエンドへの書き込みに 30 秒かかり、キューの長さが 100 の場合、各ブロックがデキューされるまでの時間は、さらに 10 秒になります。ブロックが到着すると、すぐにキューがいっぱいになり、例外が発生します。

実践1:業務アプリケーションログの収集と現場分析を実現する

目的: コンテナ内の nginx アプリケーションの access.log ログを収集し、ログ フィールドを JSON 形式に解析します。元のログ形式は次のとおりです。

$ tail -f access.log
...
53.49.146.149 1561620585.973 0.005 502 [27/Jun/2019:15:29:45 +0800] 178.73.215.171 33337 GET https

収集して次のように処理します。

{
    "serverIp": "53.49.146.149",
    "timestamp": "1561620585.973",
    "respondTime": "0.005",
    "httpCode": "502",
    "eventTime": "27/Jun/2019:15:29:45 +0800",
    "clientIp": "178.73.215.171",
    "clientPort": "33337",
    "method": "GET",
    "protocol": "https"
}

アイデア:

  • @tail プラグインを使用して、access.log ファイルを監視し、フィルターを使用して nginx ログ形式を分析するように fluent.conf を構成します。
  • Fluentd サービスを開始する
  • コンテンツを access.log ファイルに手動で追加する
  • ローカル出力が期待どおりかどうかを観察する

流暢な.conf

<source>
      @type tail
      @label @nginx_access
      path /fluentd/access.log
      pos_file /fluentd/nginx_access.posg
      tag nginx_access
      format none
      @log_level trace
</source>
<label @nginx_access>
   <filter  nginx_access>
      @type parser
      key_name message
      format  /(?<serverIp>[^ ]*) (?<timestamp>[^ ]*) (?<respondTime>[^ ]*) (?<httpCode>[^ ]*) \[(?<eventTime>[^\]]*)\] (?<clientIp>[^ ]*) (?<clientPort>[^ ]*) (?<method>[^ ]*) (?<protocol>[^ ]*)/
   </filter>
   <match  nginx_access>
     @type stdout
   </match>
</label>

サービスを開始し、ファイルの内容を追加します。

$ docker run -u root --rm -ti 172.21.51.67:5000/fluentd_elasticsearch/fluentd:v2.5.2 sh
/ # cd /fluentd/
/ # touch access.log
/ # fluentd -c /fluentd/etc/fluent.conf
/ # echo '53.49.146.149 1561620585.973 0.005 502 [27/Jun/2019:15:29:45 +0800] 178.73.215.171 33337 GET https' >>/fluentd/access.log

正規表現の検証には次の Web サイトを使用してください:  http://fluent.herokuapp.com

実践 2: Ruby を使用してログフィールドの変換とカスタム処理を実現する

<source>
      @type tail
      @label @nginx_access
      path /fluentd/access.log
      pos_file /fluentd/nginx_access.posg
      tag nginx_access
      format none
      @log_level trace
</source>
<label @nginx_access>
   <filter  nginx_access>
      @type parser
      key_name message
      format  /(?<serverIp>[^ ]*) (?<timestamp>[^ ]*) (?<respondTime>[^ ]*) (?<httpCode>[^ ]*) \[(?<eventTime>[^\]]*)\] (?<clientIp>[^ ]*) (?<clientPort>[^ ]*) (?<method>[^ ]*) (?<protocol>[^ ]*)/
   </filter>
   <filter  nginx_access>   
      @type record_transformer
      enable_ruby
      <record>
       host_name "#{Socket.gethostname}"
       my_key  "my_val"
       tls ${record["protocol"].index("https") ? "true" : "false"}
      </record>
   </filter>
   <match  nginx_access>
     @type stdout
   </match>
</label>

ConfigMap 構成ファイルのマウント使用シナリオ

始める前に、configmap の一般的なマウント シナリオを確認しましょう。

シナリオ 1: 単一のファイルを空のディレクトリにマウントする

ビジネス アプリケーションに application-1.conf という名前の構成ファイルがある場合、この構成をポッドの /etc/application/ ディレクトリにマウントする場合。

application-1.conf の内容は次のとおりです。

$ cat application-1.conf
name: "application"
platform: "linux"
purpose: "demo"
company: "luffy"
version: "v2.1.0"

設定ファイルは、k8s の configmap を通じて管理できますが、通常、設定ファイルを管理するには次の 2 つの方法があります。

  • kubectl コマンドラインを使用して configmap を生成する
# 通过文件直接创建
$ kubectl -n default create configmap application-config --from-file=application-1.conf

# 会生成配置文件,查看内容,configmap的key为文件名字
$ kubectl -n default get cm application-config -oyaml
  • yaml ファイルから直接作成する
$ cat application-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: application-config
  namespace: default
data:
  application-1.conf: |
    name: "application"
    platform: "linux"
    purpose: "demo"
    company: "luffy"
    version: "v2.1.0"

# 创建configmap
$ kubectl apply -f application-config.yaml

demo-deployment.yaml ファイルを準備し、上記の configmap を /etc/application/ にマウントします。

$ cat demo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  namespace: default
spec:
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      volumes:
      - configMap:
          name: application-config
        name: config
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - mountPath: "/etc/application"
          name: config

作成して表示するには:

$ kubectl apply -f demo-deployment.yaml

configmap ファイルの内容を変更し、ポッドが変更を自動的に感知するかどうかを観察します。

$ kubectl edit cm application-config
configmap ファイル全体が Pod に直接マウントされ、configmap が変更されると、Pod は自動的にそれを感知して Pod に取り込みます。
ただし、ポッド内のプロセスは自動的に再起動されないため、多くのサービスは内部リロード インターフェイスを実装して、最新の構成ファイルをプロセスにロードします。

シナリオ 2: 複数のファイルをマウントする

複数の構成ファイルがある場合は、それらをすべてポッド内にマウントし、すべて 1 つのディレクトリに置く必要があります。

$ cat application-1.conf
name: "application-1"
platform: "linux"
purpose: "demo"
company: "luffy"
version: "v2.1.0"
$ cat application-2.conf
name: "application-2"
platform: "linux"
purpose: "demo"
company: "luffy"
version: "v2.1.0"

次の 2 つの方法でも作成できます。

$ kubectl delete cm application-config

$ kubectl create cm application-config --from-file=application-1.conf --from-file=application-2.conf

$ kubectl get cm application-config -oyaml

ポッドが最新の変更を自動的に取得していることを確認します。

$ kubectl exec demo-55c649865b-gpkgk ls /etc/application/
application-1.conf
application-2.conf

この時点で、ポッド /etc/application の空のディレクトリにマウントされます。ポッドの既存のディレクトリにマウントする場合は、たとえば次のようにします。

$  kubectl exec   demo-55c649865b-gpkgk ls /etc/profile.d
color_prompt
locale

デプロイメントのマウント ディレクトリを変更します。

$ cat demo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  namespace: default
spec:
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      volumes:
      - configMap:
          name: application-config
        name: config
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - mountPath: "/etc/profile.d"
          name: config

ポッドを再構築する

$ kubectl apply -f demo-deployment.yaml

# 查看pod内的/etc/profile.d目录,发现已有文件被覆盖
$ kubectl exec demo-77d685b9f7-68qz7 ls /etc/profile.d
application-1.conf
application-2.conf

シナリオ 3 マウント サブパス

複数の構成ファイルを実装し、ポッド内の異なるディレクトリにマウントできます。例えば:

  • application-1.conf は /etc/application/ にマウントされます
  • application-2.conf は /etc/profile.d にマウントされます

configmap は変更されないままなので、デプロイメント ファイルを変更します。

$ cat demo-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  namespace: default
spec:
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      volumes:
      - name: config
        configMap:
          name: application-config
          items:
          - key: application-1.conf
            path: application1
          - key: application-2.conf
            path: application2
      containers:
      - name: nginx
        image: nginx:alpine
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - mountPath: "/etc/application/application-1.conf"
          name: config
          subPath: application1
        - mountPath: "/etc/profile.d/application-2.conf"
          name: config
          subPath: application2

テストマウント:

$ kubectl apply -f demo-deployment.yaml

$ kubectl exec demo-78489c754-shjhz ls /etc/application
application-1.conf

$ kubectl exec demo-78489c754-shjhz ls /etc/profile.d/
application-2.conf
color_prompt
locale

コードをコピーする

subPath を使用してポッド内にマウントされたファイルは、元の ConfigMap の変更を自動的に認識しません。

ESサービスを導入する

導入分析

  1. es 実稼働環境では、es クラスターをデプロイします。通常、デプロイメントにはステートフルセットを使用します。
  2. デフォルトでは、es は elasticsearch ユーザーを使用してプロセスを開始します。es のデータ ディレクトリはホスト マシンのパスを通じてマウントされるため、ディレクトリのアクセス許可はホスト マシンのディレクトリのアクセス許可によって上書きされます。したがって、initContainer コンテナはes プロセスの開始前にディレクトリのアクセス許可を変更するために使用されます。init に注意してください。コンテナーは特権モードで開始する必要があります。
  3. Helm デプロイメントを使用する場合は、  https://github.com/helm/charts/tree/master/stable/elasticsearchを参照してください。

StatefulSet を使用してステートフル サービスを管理する

デプロイメントを使用して複数のレプリカ ポッドを作成する場合:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
  labels:
    app: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-deployment
  template:
    metadata:
      labels:
        app: nginx-deployment
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80

StatefulSet を使用してマルチレプリカ ポッドを作成する場合:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-statefulset
  namespace: default
  labels:
    app: nginx-sts
spec:
  replicas: 3
  serviceName: "nginx"
  selector:
    matchLabels:
      app: nginx-sts
  template:
    metadata:
      labels:
        app: nginx-sts
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80

ヘッドレスサービス ヘッドレスサービス

kind: Service
apiVersion: v1
metadata:
  name: nginx
  namespace: default
spec:
  selector:
    app: nginx-sts
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  clusterIP: None
$ kubectl -n default exec  -ti nginx-statefulset-0 sh
/ # curl nginx-statefulset-2.nginx

デプロイと検証

es-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: es-config
  namespace: logging
data:
  elasticsearch.yml: |
    cluster.name: "luffy-elasticsearch"
    node.name: "${POD_NAME}"
    network.host: 0.0.0.0
    discovery.seed_hosts: "es-svc-headless"
    cluster.initial_master_nodes: "elasticsearch-0,elasticsearch-1,elasticsearch-2"

es-svc-headless.yaml

apiVersion: v1
kind: Service
metadata:
  name: es-svc-headless
  namespace: logging
  labels:
    k8s-app: elasticsearch
spec:
  selector:
    k8s-app: elasticsearch
  clusterIP: None
  ports:
  - name: in
    port: 9300
    protocol: TCP

es-statefulset.yaml

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch
  namespace: logging
  labels:
    k8s-app: elasticsearch
spec:
  replicas: 3
  serviceName: es-svc-headless
  selector:
    matchLabels:
      k8s-app: elasticsearch
  template:
    metadata:
      labels:
        k8s-app: elasticsearch
    spec:
      initContainers:
      - command:
        - /sbin/sysctl
        - -w
        - vm.max_map_count=262144
        image: alpine:3.6
        imagePullPolicy: IfNotPresent
        name: elasticsearch-logging-init
        resources: {}
        securityContext:
          privileged: true
      - name: fix-permissions
        image: alpine:3.6
        command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
        securityContext:
          privileged: true
        volumeMounts:
        - name: es-data-volume
          mountPath: /usr/share/elasticsearch/data
      containers:
      - name: elasticsearch
        image: 172.21.51.67:5000/elasticsearch/elasticsearch:7.4.2
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
        resources:
          limits:
            cpu: '1'
            memory: 2Gi
          requests:
            cpu: '1'
            memory: 2Gi
        ports:
        - containerPort: 9200
          name: db
          protocol: TCP
        - containerPort: 9300
          name: transport
          protocol: TCP
        volumeMounts:
          - name: es-config-volume
            mountPath: /usr/share/elasticsearch/config/elasticsearch.yml
            subPath: elasticsearch.yml
          - name: es-data-volume
            mountPath: /usr/share/elasticsearch/data
      volumes:
        - name: es-config-volume
          configMap:
            name: es-config
            items:
            - key: elasticsearch.yml
              path: elasticsearch.yml
  volumeClaimTemplates:
  - metadata:
      name: es-data-volume
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: "nfs"
      resources:
        requests:
          storage: 5Gi

es-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: es-svc
  namespace: logging
  labels:
    k8s-app: elasticsearch
spec:
  selector:
    k8s-app: elasticsearch
  ports:
  - name: out
    port: 9200
    protocol: TCP
$ kubectl create namespace logging

## 部署服务
$ kubectl apply -f es-config.yaml
$ kubectl apply -f es-svc-headless.yaml
$ kubectl apply -f es-sts.yaml
$ kubectl apply -f es-svc.yaml

## 等待片刻,查看一下es的pod部署到了k8s-slave1节点,状态变为running
$ kubectl -n logging get po -o wide  
NAME              READY   STATUS    RESTARTS   AGE   IP  
elasticsearch-0   1/1     Running   0          15m   10.244.0.126 
elasticsearch-1   1/1     Running   0          15m   10.244.0.127
elasticsearch-2   1/1     Running   0          15m   10.244.0.128
# 然后通过curl命令访问一下服务,验证es是否部署成功
$ kubectl -n logging get svc  
es-svc            ClusterIP   10.104.226.175   <none>        9200/TCP   2s
es-svc-headless   ClusterIP   None             <none>        9300/TCP   32m 
$ curl 10.104.226.175:9200
{
  "name" : "elasticsearch-2",
  "cluster_name" : "luffy-elasticsearch",
  "cluster_uuid" : "7FDIACx9T-2ajYcB5qp4hQ",
  "version" : {
    "number" : "7.4.2",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
    "build_date" : "2019-10-28T20:40:44.881551Z",
    "build_snapshot" : false,
    "lucene_version" : "8.2.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"

部署kibana

導入分析

  1. Kibana は Web ページをフロントエンドに公開する必要があるため、ingress を使用してドメイン名を構成し、kibana にアクセスできるようにします。
  2. Kibana はステートレス アプリケーションであり、Deployment を使用して直接開始できます。
  3. Kibana は es にアクセスする必要があります。k8s サービス検出を使用してこのアドレスhttp://es-svc:9200にアクセスするだけです。

デプロイと検証

efk/kibana.yaml

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: kibana
  namespace: logging
  labels:
    app: kibana
spec:
  selector:
    matchLabels:
      app: "kibana"
  template:
    metadata:
      labels:
        app: kibana
    spec:
      containers:
      - name: kibana
        image: 172.21.51.67:5000/kibana/kibana:7.4.2
        resources:
          limits:
            cpu: 1000m
          requests:
            cpu: 100m
        env:
          - name: ELASTICSEARCH_HOSTS
            value: http://es-svc:9200
          - name: SERVER_NAME
            value: kibana-logging
          - name: SERVER_REWRITEBASEPATH
            value: "false"
        ports:
        - containerPort: 5601
---
apiVersion: v1
kind: Service
metadata:
  name: kibana
  namespace: logging
  labels:
    app: kibana
spec:
  ports:
  - port: 5601
    protocol: TCP
    targetPort: 5601
  type: ClusterIP
  selector:
    app: kibana
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kibana
  namespace: logging
spec:
  rules:
  - host: kibana.luffy.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kibana
          servicePort: 5601
$ kubectl apply -f kibana.yaml  
deployment.apps/kibana created
service/kibana created  
ingress/kibana created

## 配置域名解析 kibana.luffy.com,并访问服务进行验证,若可以访问,说明连接es成功

Fluentd サービスのデプロイメント

導入分析

  1. Fluentd はログ収集サービスであり、kubernetes クラスター内の各ビジネス ノードにはログがあるため、daemonset モードでデプロイする必要があります
  2. リソースをさらに制御するには、daemonset に選択ラベルを指定します。さらにフィルタリングするには、fluentd=true を指定します。このラベルを持つノードのみが fluentd をデプロイします。
  3. ログ収集の場合、ディレクトリごとに収集してesに送信する必要があるログは収集後に終了するため、設定する項目が多くなりますが、構成ファイル全体をマウントするためにconfigmapを使用することにします。

導入サービス

efk/fluentd-es-config-main.yaml

apiVersion: v1
data:
  fluent.conf: |-
    # This is the root config file, which only includes components of the actual configuration
    #
    #  Do not collect fluentd's own logs to avoid infinite loops.
    <match fluent.**>
    @type null
    </match>

    @include /fluentd/etc/config.d/*.conf
kind: ConfigMap
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
  name: fluentd-es-config-main
  namespace: logging

構成ファイル、fluentd-config.yaml、注:

  1. データソースソースの設定では、k8s はデフォルトでコンテナーの標準出力ログとエラー出力ログをホストにリダイレクトします。
  2.  デフォルトでは、ログ形式を解析し、k8s 関連のメタデータ raw.kubernetes を取得するために、kubernetes_metadata_filterプラグインが統合されています 。
  3. 出力をes側のフラッシュ構成に一致させる

efk/fluentd-configmap.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: fluentd-config
  namespace: logging
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
data:
  containers.input.conf: |-
    <source>
      @id fluentd-containers.log
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/es-containers.log.pos
      time_format %Y-%m-%dT%H:%M:%S.%NZ
      localtime
      tag raw.kubernetes.*
      format json
      read_from_head false
    </source>
    # Detect exceptions in the log output and forward them as one log entry.
    # https://github.com/GoogleCloudPlatform/fluent-plugin-detect-exceptions 
    <match raw.kubernetes.**>
      @id raw.kubernetes
      @type detect_exceptions
      remove_tag_prefix raw
      message log
      stream stream
      multiline_flush_interval 5
      max_bytes 500000
      max_lines 1000
    </match>
  output.conf: |-
    # Enriches records with Kubernetes metadata
    <filter kubernetes.**>
      @type kubernetes_metadata
    </filter>
    <match **>
      @id elasticsearch
      @type elasticsearch
      @log_level info
      include_tag_key true
      hosts elasticsearch-0.es-svc-headless:9200,elasticsearch-1.es-svc-headless:9200,elasticsearch-2.es-svc-headless:9200
      #port 9200
      logstash_format true
      #index_name kubernetes-%Y.%m.%d
      request_timeout    30s
      <buffer>
        @type file
        path /var/log/fluentd-buffers/kubernetes.system.buffer
        flush_mode interval
        retry_type exponential_backoff
        flush_thread_count 2
        flush_interval 5s
        retry_forever
        retry_max_interval 30
        chunk_limit_size 2M
        queue_limit_length 8
        overflow_action block
      </buffer>
    </match>

デーモンセット定義ファイル、fluentd.yaml、注:

  1. ログに基づいてメタデータをクエリするには、k8s API にアクセスする必要があるため、rbac ルールを構成する必要があります。
  2. /var/log/containers/ ディレクトリをコンテナにマウントする必要があります
  3. fluentd の configmap 内の構成ファイルをコンテナーにマウントする必要があります
  4. fluentd ノードをデプロイする場合は、ラベル fluentd=true を追加する必要があります。

efk/fluentd.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: fluentd-es
  namespace: logging
  labels:
    k8s-app: fluentd-es
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd-es
  labels:
    k8s-app: fluentd-es
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
rules:
- apiGroups:
  - ""
  resources:
  - "namespaces"
  - "pods"
  verbs:
  - "get"
  - "watch"
  - "list"
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: fluentd-es
  labels:
    k8s-app: fluentd-es
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
subjects:
- kind: ServiceAccount
  name: fluentd-es
  namespace: logging
  apiGroup: ""
roleRef:
  kind: ClusterRole
  name: fluentd-es
  apiGroup: ""
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    k8s-app: fluentd-es
  name: fluentd-es
  namespace: logging
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-es
  template:
    metadata:
      labels:
        k8s-app: fluentd-es
    spec:
      containers:
      - env:
        - name: FLUENTD_ARGS
          value: --no-supervisor -q
        image: 172.21.51.67:5000/fluentd_elasticsearch/fluentd:v2.5.2
        imagePullPolicy: IfNotPresent
        name: fluentd-es
        resources:
          limits:
            memory: 500Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - mountPath: /var/log
          name: varlog
        - mountPath: /var/lib/docker/containers
          name: varlibdockercontainers
          readOnly: true
        - mountPath: /fluentd/etc/config.d
          name: config-volume
        - mountPath: /fluentd/etc/fluent.conf
          name: config-volume-main
          subPath: fluent.conf
      nodeSelector:
        fluentd: "true"
      securityContext: {}
      serviceAccount: fluentd-es
      serviceAccountName: fluentd-es
      volumes:
      - hostPath:
          path: /var/log
          type: ""
        name: varlog
      - hostPath:
          path: /var/lib/docker/containers
          type: ""
        name: varlibdockercontainers
      - configMap:
          defaultMode: 420
          name: fluentd-config
        name: config-volume
      - configMap:
          defaultMode: 420
          items:
          - key: fluent.conf
            path: fluent.conf
          name: fluentd-es-config-main
        name: config-volume-main
## 给slave1打上标签,进行部署fluentd日志采集服务
$ kubectl label node k8s-slave1 fluentd=true  
$ kubectl label node k8s-slave2 fluentd=true

# 创建服务
$ kubectl apply -f fluentd-es-config-main.yaml  
configmap/fluentd-es-config-main created  
$ kubectl apply -f fluentd-configmap.yaml  
configmap/fluentd-config created  
$ kubectl apply -f fluentd.yaml  
serviceaccount/fluentd-es created  
clusterrole.rbac.authorization.k8s.io/fluentd-es created  
clusterrolebinding.rbac.authorization.k8s.io/fluentd-es created  
daemonset.extensions/fluentd-es created 

## 然后查看一下pod是否已经在k8s-slave1
$ kubectl -n logging get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE  
elasticsearch-logging-0   1/1     Running   0          123m  
fluentd-es-246pl          1/1     Running   0          2m2s  
kibana-944c57766-ftlcw    1/1     Running   0          50m

上記は、k8s ログ デプロイメント コレクションの構成の簡略化されたバージョンであり、完全なバージョンはhttps://gitbhub.com/kubernetes/kubernetes/tree/master/cluster/addons/fluentd-elasticsearchで参照できます

EFKの機能検証

検証アイデア

スレーブノードでサービスを起動し、同時にテストログを標準出力に出力し、kibanaに収集できるか確認する

テストコンテナを作成する

efk/テストポッド.yaml

apiVersion: v1
kind: Pod
metadata:
  name: counter
spec:
  nodeSelector:
    fluentd: "true"
  containers:
  - name: count
    image: alpine:3.6
    args: [/bin/sh, -c, 'i=0; while true; do echo "$i: $(date)"; i=$((i+1)); sleep 1; done']
$ kubectl get po  
NAME                          READY   STATUS    RESTARTS   AGE  
counter                       1/1     Running   0          6s

キバナを構成する

kibana インターフェースにログインし、一連のスクリーンショットに従います。

ログ データは他のメタデータでフィルタリングすることもできます。たとえば、任意のログ エントリをクリックして、コンテナ名、Kubernetes ノード、名前空間などの他のメタデータを表示できます ( kubernetes.pod_name : counter など)。

これまでのところ、Kubernetes クラスターに EFK を正常にデプロイできました。ログ データ分析に Kibana を使用する方法については、Kibana ユーザー ガイド ドキュメントを参照してください: https://www.elastic.co/guide/en/kib

おすすめ

転載: blog.csdn.net/guolianggsta/article/details/131609826