Filebeat→Logstash→Elasticsearch→KibanaでNginxのログを可視化する

面白そうだったので

  • Filebeat – 軽量ログ収集ツール
  • Logstash – データを変換し一元化してくれるツール
  • ElasticSearch – 全文検索や統計を取ってくれるツール
  • Kibana – ブラウザでアクセスして上記を可視化したり設定変更できるGUI

全て同じElastic社が作っているので連携がスムーズです。

ホストOSのNginxのログをfilebeatで収集→Logstashで加工→ElasticSearchで統計→Kibanaで表示するDocker composeを作ります。

続きを読む

Nginxの設定

Nginx設定ファイルの編集

Cloudflare(CDN)用のreal ip取得(使用している人のみ)

プロキシを挟んでいても相手の正しいIPが取得できるように下記をhttpブロックに追記しておきます。

CloudflareとNGINX公式のIP rangeを参考に、下記プロキシからのアクセスのみreal_ip_headerを取得

    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 104.16.0.0/12;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 131.0.72.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 2400:cb00::/32;
    set_real_ip_from 2606:4700::/32;
    set_real_ip_from 2803:f800::/32;
    set_real_ip_from 2405:b500::/32;
    set_real_ip_from 2405:8100::/32;
    set_real_ip_from 2c0f:f248::/32;
    set_real_ip_from 2a06:98c0::/29;

    real_ip_header CF-Connecting-IP;

Kibana&Elasticsearch&Logstash&Filebeatのインストール

Docker composeファイルの作成

さくさくっと全部入ったDocker composeを作成します。

公式Dockerイメージを使用します。バージョンは適切に設定して下さい。

docker-compose.yamlと同じフォルダにdocker.envelasticsearch.ymlkibana.ymlfilebeat.ymlファイルを作成します。

es-dataフォルダも生成し書き込み権限を持たせておきます。一応sudo docker network create mynetworkで作成したネットワークを使用しています。

docker-compose.yaml

version: '3'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.9.1
    environment:
      - "discovery.type=single-node"
      - "xpack.security.enabled=true"
      - "ELASTIC_PASSWORD=${ELASTIC_PASSWORD}"
      - "ELASTIC_USER=${ELASTIC_USER}"
    ports:
      - "9200:9200"
    volumes:
      - ./es-data:/usr/share/elasticsearch/data
      - ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
    networks:
      - mynetwork
    restart: always

  kibana:
    image: docker.elastic.co/kibana/kibana:8.9.1
    ports:
      - "5601:5601"
    environment:
      - "ELASTICSEARCH_HOSTS=http://elasticsearch:9200"
      - "XPACK_REPORTING_KIBANASERVER_HOSTNAME=localhost"
    volumes:
      - ./kibana.yml:/usr/share/kibana/config/kibana.yml:ro
    networks:
      - mynetwork
    restart: always

  logstash:
    image: docker.elastic.co/logstash/logstash:8.9.1
    environment:
      - "ELASTICSEARCH_HOST=http://elasticsearch:9200"
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
      - ./logstash/conf.d:/etc/logstash/conf.d
      - ./logstash.yml:/usr/share/logstash/config/logstash.yml:ro
    networks:
      - mynetwork
    depends_on:
      - elasticsearch
    restart: always

  filebeat:
    image: docker.elastic.co/beats/filebeat:8.9.1
    volumes:
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
      - /var/log/nginx:/var/log/nginx
    networks:
      - mynetwork
    depends_on:
      - elasticsearch
    restart: always

networks:
  mynetwork:
    driver: bridge

docker.env

Elasticsearchのユーザー名とパスワードを設定します。Kibanaのコンソールにログイン時に使用します。

ELASTIC_PASSWORD=elasticのパスワード
ELASTIC_USER=elasticのユーザー名

作成したらsudo docker compose up -dでコンテナを起動します。

ElasticSearchの設定

elasticsearch.yml

基本デフォルトのままなので特に弄らなくて良いかもです。

cluster.name: "docker-cluster"
network.host: 0.0.0.0
http.port: 9200

トークンの生成

Docker経由でコマンドを打ってElasticsearchでelastic/kibanaのアクセストークンを生成します。

sudo docker exec -it kibana-elasticsearch-1 bash -c "bin/elasticsearch-service-tokens create elastic/kibana my-token"

このトークンをkibana.ymlに入力します。

Kibanaの設定

公式ドキュメント – Kibana

上記で生成したトークンを記述します。32文字以上のフレーズは適当なジェネレーターで生成しました。

kibana.yml

server.host: "0.0.0.0"
server.shutdownTimeout: "5s"

# 作成したアクセストークンを入力
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
elasticsearch.serviceAccountToken: "生成したトークン"

xpack.security.encryptionKey: "32文字以上のフレーズ"
xpack.reporting.encryptionKey: "32文字以上のフレーズ"
xpack.encryptedSavedObjects.encryptionKey: "32文字以上のフレーズ"

xpack.security.session.idleTimeout: "1h"
xpack.reporting.kibanaServer.hostname: "kibana"

Nginxの設定

例として「https://ドメイン:23232/」にアクセスしたらKibanaのコンソールにアクセスするように設定します。今回は許可したIPアドレスからのみ接続できるようにしています。

/etc/nginx/conf.d/kibana-proxy.confを作成して下記を入力します。

kibana-proxy.conf

server {
    listen 23232 ssl;
    server_name ドメイン名;

    ssl_certificate 証明書.pem;
    ssl_certificate_key 証明書鍵.pem;

    location / {
        allow 許可するIP;
        allow 127.0.0.0/24;
        deny all;

        proxy_pass http://localhost:5601;  # Kibanaのアドレス
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

できたらsudo systemctl restart nginxでNginxを再起動し、Dockerも再起動してコンソール「https://ドメイン:23232/」にアクセスしてみます。ログイン画面が出てくれば成功です。

データ収集&加工

Filebeatの設定

公式ドキュメント – Filebeat

/var/log/nginx/*.jsonに保存されたデータを収集します。

filebeat.yml

Firebeatでログを収集し、Logstashへデータを送ります。

type: logは非推奨になりtype: filestreamを使用するようにと公式ドキュメントにあるのでそれを使用します。

filebeat.inputs:
- type: filestream
  paths:
    - /var/log/nginx/*.json
  tags: ["nginx", "json"]
    parsers:
      - ndjson:
        target: ""
        add_error_key: true

output.logstash:
  hosts: ["logstash:5044"]

Logstashの設定

公式ドキュメント – Logstash

公式サイト を参考にKibanaでLogstashを動かすためのロールとユーザーを作成します。

このユーザー名とパスワードをlogstash.confファイルに記述します。

logstashフォルダを作成し、更にその下にpipelineフォルダを作成し、その下にlogstash.confファイルを作成します。ここに基本設定を記入します。

logstash/pipeline/logstash.conf

ベースの設定をします。

input {
  beats {
    port => 5044
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
    user => logstash_internal
    password => 設定したパスワード
  }
}

Logstashでのデータ加工

こちらのサイトfilter-nginx.conflog-json.confをそのまま使用させて頂きました。

filter-nginx.confファイルをpipelineフォルダの中に入れます。

log-json.confの内容をホストOSの/etc/nginx/nginx.confのhttpブロックに追記し、更に下記を追記します。

    access_log /var/log/nginx/global-access.json json;
    error_log /var/log/nginx/global-error.log;

これでjson形式の細かいログが取れます。

あとはNginxとDockerを再起動します。

実行

Discoverを開いて上手くデータが流れ込んできていれば成功です。やったね。

ufwやfail2banの設定ファイルも公開されている方がいるので使ってみたいところ。アクセスログだけでなくMetricbeatでシステム情報もロギングしたいです。