2018年9月7日金曜日

k8s 上で fluentd を使って外部の ElasticSearch にログを集めてみた

概要

k8s で fluentd を使ってログを収集する場合多くのケースで DaemonSet の仕組みが使われます
DaemonSet は簡単に言えば各 Pod に自動で 1 つコンテナを作成するための定義です
DaemonSet が定義されていると新規でノードが追加された際に自動でログ収集用の fluentd が起動するといった感じです

環境

  • macOS 10.13.6
  • minikube v0.28.2
  • fluent/fluentd-kubernetes-daemonset:elasticsearch (v0.12)

事前作業

ElasticSearch の構築

別の VM に構築しています
方法は何でも OK です
k8s 上に構築したコンテナからエンドポイントにアクセスできるようにしましょう

Kibana の構築 (任意)

確認に使うだけなので任意です
直接 ElasticSearch の API がコールできるのであればそれでも OK です

fluentd の DaemonSet の作成

fluentd が公式で出している定義を流用します
仕組みとしては logging driver は使わずに dockerd が動作しているホストのコンテナログが出力されるパス (/var/lib/docker/containers) をマウントしてそこに出力されるログを ElasticSearch に送ります

namespace や label は変更しても問題ないと思います

  • vim fluentd-ds.yaml
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: fluentd
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
    version: v1
    kubernetes.io/cluster-service: "true"
spec:
  template:
    metadata:
      labels:
        k8s-app: fluentd-logging
        version: v1
        kubernetes.io/cluster-service: "true"
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: fluentd
        image: fluent/fluentd-kubernetes-daemonset:elasticsearch
        env:
          - name: FLUENT_ELASTICSEARCH_HOST
            value: "192.168.99.1"
          - name: FLUENT_ELASTICSEARCH_PORT
            value: "9200"
          - name: FLUENT_ELASTICSEARCH_SCHEME
            value: "http"
          - name: FLUENT_UID
            value: "0"
        resources:
          limits:
            memory: 200Mi
          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

変更するべきは env の部分だけです
ここの IP や Port を外部に構築した ElasticSearch のものに変更すれば OK です
公式だとそれ以外にも env のありましたが不要なので削除しました

  • kubectl create -f fluentd-ds.yaml
  • kubectl get all -n kube-system -l k8s-app=fluentd-logging
NAME                READY     STATUS    RESTARTS   AGE
pod/fluentd-zhnnj   1/1       Running   0          1m

NAME                     DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/fluentd   1         1         1         1            1           <none>          1m

こんな感じで fluentd のコンテナが DaemonSet の仕組みで起動してきます

テスト用のコンテナ作成

ログを出力し続けるコンテナを適当に作成します
動作確認なので Deployment からではなく直接 Pod を作成します

  • vim counter-pod.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']
  • kubectl create -f counter-pod.yaml
  • kubectl get po
NAME      READY     STATUS    RESTARTS   AGE
counter   1/1       Running   0          29s

動作確認

Kibana があればそれを見てみましょう
インデックス (logstash-*) を作成し
k8s_fluentd1.png

タイムスタンプのフィールド (@timestamp) を作成し
k8s_fluentd2.png

Disvoery で dockercontainer_id で絞り込めばログが確認できると思います
k8s_fluentd3.png

インデックス名は logstash-2018.09.03 という感じで日付形式で来るようになっています
fluent.conf の設定はここが参考になると思います

トラブルシューティング

fluentd コンテナが立ち上がったときにログ用のパスがマウントできないエラーが発生しました

2018-09-03 00:05:58 +0000 [error]: unexpected error error_class=Errno::EACCES error=#<Errno::EACCES: Permission denied @ rb_sysopen - /var/log/fluentd-containers.log.pos> 

どうやら fluent ユーザに権限がないために上記のエラーになっているようです
fluentd-ds.yaml に FLUENT_UID の値を 0 に設定することで対応できました
同じような現象に関しての issue が Github にもありました
https://github.com/fluent/fluentd-docker-image/issues/90

お掃除

  • kubectl delete po counter
  • kubectl delete ds fluentd -n kube-system

最後に

kubernetes 上に DaemonSet の仕組みを使って fluentd コンテナを作成してみました
これを作成しておけば
今回は ElasticSearch に向かってログを投げましたが、他にもいろいろなログ集約のサービスに投げれるようです

仕組みとしてはコンテナログのファイルを監視しているだけなので標準出力/標準エラーにログを吐くコンテナであれば kubernetes 上に立てるだけでログが ElasticSearch に送られます

実は今回 minikube 上で実現しています
kubernetes 上でも同じようにできるので minikube にしました
minikube にはアドオンで「efk」というアドオンがあり実はこれを使ってもできます
が、これは e (elasticsearch) と f (fluentd) と k (kibana) のコンテナをすべて minikube 上に展開します
今回の構成は e と k は外部のホストに構築しています
なので kubernetes 上にあるのは f だけになります
f はどうしても k8s になければいけないコンテナになります
普通は e と k は別ホストにあると思うのでそれを想定して動作させてみました

参考サイト

0 件のコメント:

コメントを投稿