1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NginxのアクセスログをFluentdでMySQLに格納して可視化

Last updated at Posted at 2023-05-04

背景

個人管理のサーバでホームページを公開していて、各ページへのアクセス情報を見てみたくなった。ログ収集の試行もかねてアクセスログを可視化してみた。

環境構築の方針

  • Docker, Docker-Composeを使って構築する。
  • 個人的な経験値から以下のミドルウェアを利用する。
    • nginx:Webサーバ
    • fluentd:nginxのアクセスログを収集
    • mysql:収集したログ情報の格納
    • metabase:DBに格納したログ情報の可視化

構成

nginxが出力したログファイルを、fluentdで収集してmysqlに格納する。
構成図
構成図2.png

前提環境

  • OS : Ubunt 20.04.4 LTS
  • Docker : 20.10.17, build 100c701
  • Docker compose : version 1.29.1, build c34c88b2

構築

以下のステップで構築する。
1. ディレクトリ構成の作成
2. docker-composeファイルの作成
3. mysqlコンテナの構築
4. fluentdコンテナの構築
5. Metabaseコンテナの構築

1. ディレクトリの作成

以下のディレクトリ構成を作成した。
個別コンテナの設定ファイルなどについては後述する。

/home/com/homepage 
 ├─ nginx
 │  ├─ conf
 │  │  └─ nginx.conf
 │  └─ log
 │     └─ access.log ・・・nginxのアクセスログファイル
 ├─ contents ・・・webページのコンテンツ
 │  └─ index.html
 ├─ fluented
 │  ├─ data
 │  │  └─ nginx_access.log.pos ・・・最終読み込み位置の保持ファイル
 │  ├─ Dockerfile   
 │  └─ fluent.conf ・・・Fluentdの設定ファイル
 ├─ mysql
 │  ├─ scripts
 │  │  └─ create_tabel.sql ・・・テーブル作成のSQLファイル
 │  └─ dbvolume
 ├─ metabase
 └─ docker-compose.yaml

2. docker-composeファイルの作成

以下の通り、docker-composeファイルを作成した。
[ 特記事項 ]
- fluentdのコンテナからnginxのログファイルを参照する。

docker-compose.yaml
version: '3'
services:
  nginx:
    image: nginx:1.23
    ports:
      - 80:80
    volumes:
      - ./contents:/usr/share/nginx/html
      - ./nginx/log:/var/log/nginx
      - ./nginx/conf/nginx.conf:/etc/nginx/conf.d/nginx.conf
    environment:
      TZ: Asia/Tokyo
    restart: always

  metabase:
    image: metabase/metabase:v0.46.2
    restart: always
    volumes:
      - ./metabase:/metabase-data
    ports:
      - 3000:3000
    environment:
      MB_DB_FILE: /metabase-data/metabase.db

  fluentd:
    build:
      context: .
      dockerfile: ./fluentd/Dockerfile
    ports:
      - 24224:24224
    volumes:
      - ./nginx/log:/var/log/nginx
      - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf
      - ./fluentd/data:/fluentd/log

  db:
    image: mysql:8.0
    restart: always
    volumes:
     - ./mysql/dbvolume:/var/lib/mysql
     - ./mysql/scripts:/docker-entrypoint-initdb.d
    ports:
     - 3306:3306
    environment:
      - MYSQL_DATABASE=log
      - MYSQL_USER=log
      - MYSQL_PASSWORD=password
      - MYSQL_ROOT_PASSWORD=passwordpassword
      - TZ=Asia/Tokyo

3. mysqlコンテナの構築

以下のステップを実施した。
1. テーブル定義ファイルの作成
2. コンテナ起動時のテーブル作成自動化

3-1. テーブル定義ファイルの作成

 Fluendの公式ページを参照して、nginxのアクセスログを解析した際の出力要素を確認した。
 それらの項目をカラムとして持つテーブルを作成するためのSQL文をファイルに出力した。

create_tabel.sql
CREATE TABLE `nginx_access_log` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `time_jst` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
  `remote_ip` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `host_ip` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `user_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `method` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `access_path` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `size` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `referer` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `agent` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `http_code` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
  `xforwarded` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3;

参考
Fluentd nginx parser plugin

3-2. コンテナ起動時のテーブル作成自動化

Fluentdのコンテナ起動時にテーブルが無いと、Fluentdでエラーになる。そのため、テーブルが存在しない場合には、自動的にテーブルを作成するようにした。
docker-entrypoint-initdb.dにスクリプトファイルを格納しておくと、コンテナ起動時に自動的に実行されるので、3-1で作成したスクリプトをコンテナにマウントする。

docker-compose.yaml
  db:
    image: mysql:8.0
    restart: always
    volumes:
     - ./mysql/dbvolume:/var/lib/mysql
     - ./mysql/scripts:/docker-entrypoint-initdb.d←これを追加

参考
【Docker】【MySQL】コンテナ初回起動時にスクリプトを実行させる

4. fluentdコンテナの構築

以下のステップを実施した。
1. MySQLプラグインのインストール
2. ログ収集の設定

4-1. MySQLプラグインのインストール

fluentdで読み込んだnginxのログをmysqlにbulk_insert1するために、td-agentでmysqlのプラグインを追加しておく必要がある。
fluentdのデフォルトのコンテナイメージには、mysqlのプラグインが含まれていない。コンテナ立ち上げ時にインストールしておくようにDockerfileを用意してbuildする。

[ 特記事項 ]
- インストールするプラグインは、fluent-plugin-mysql
- ファイルサイズが大きくならないように--no-documentを指定
- ユーザflunetには、インストール権限が無いため、rootに切り替える
- コンテナのタイムゾーンをJSTに変更

Dockerfile
FROM fluent/fluentd:v1.16-1

USER root

RUN apk add --no-cache --virtual .build-deps \
    build-base \
    ruby-dev \
    tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo "Asia/Tokyo" > /etc/timezone && \
    apk add --no-cache \
    mariadb-dev && \
    gem install fluent-plugin-mysql --no-document && \
    apk del .build-deps

USER fluent

参考
fluent/fluentd - Docker Image
【Docker環境】FluentdとMySQLのbulk insertを使用したログ収集【前編】

4-2. ログ収集の設定

nginxのログを読み込んで、mysqlサーバに登録するために設定ファイルを作成する。

fluent.conf
<source>
  @type tail
  format nginx
  path /var/log/nginx/access.log
  pos_file /fluentd/data/nginx_access.log.pos
  tag nginx.access
</source>

<match nginx.access>
  @type mysql_bulk
  host 192.168.2.10
  port 3307
  database log
  username log
  password password
  
  column_names id,time_jst,remote_ip,host_ip,user_id,method,access_path,http_code,size,referer,agent,xforwarded
  key_names id,host,user,${time},method,path,version,code,size,referer,agent,xforwarded
  table nginx_access_log
  
  flush_interval 10s
</match>

参考
fluentdのnginxアクセスログ取得をdockerで試す

5. metabaseによる可視化

ダッシュボードの作成
「分析」機能-「要約」で、集約方法:カウント、集約キー:time_jst(週)を選択
image.png

ひとまず、以上で可視化までのパスを通すことができました。
ダッシュボードの拡張は今後のタスクにして、今回はここまでにします。

躓いたところ

1. ログファイルのパーミッション

fluentdのコンテナを立ち上げたとき、以下のエラーが発生して、コンテナが起動しなかった。

unexpected error error_class=Errno::EACCES error="Permission denied @ rb_file_s_stat - `/var/log/nginx/access.log"

fluentdがnginxのアクセスログ(access.log)を読み込む権限が無くてエラーになっていた。
fluentdが参照できるようにaccess.logファイルのパーミッションを変更した。

chmod 775 /home/com/homepage/web/log/access.log

fluentdのコンテナを再起動したら、上記のエラーは解消したが、次のエラーが発生した。

unexpected error error_class=Errno::EACCES error="Permission denied @ rb_sysopen - /fluentd/log/nginx_access.log.pos"

fluentdがnginxのアクセスログ(access.log)を読み込む際に、
どこまで読み込んだかという情報を保持するために、access.log.posというファイルを作成するが、そのファイルを作れなくてエラーになっていた。
ファイルを作成できるようにディレクトリのパーミッションを変更した。

chmod 777 ./fluentd/data

これで、エラー無くコンテナが起動するようになった。

参照
Permission denied @ rb_file_s_stat #2425

2. fluentdのログ確認

fluentdのログを確認するために、fluentdのコンテナに接続しようと以下のコマンドを実行したが、fluentdのコンテナにはbashがなかったので接続できなかった。

docker exec -it homepage_nginx_1 /bin/bash

bashではなく、shはインストールされていたので、下記のコマンドで接続することで、起動できた。

docker exec -it homepage_nginx_1 /bin/sh

接続後、コンソールにて、コマンドを実行してログを確認できた。

fluentd -vv -c /fluentd/etc/fluent.conf

参照
Fluentd の Docker イメージを動かした際のメモ
Fluentd Logging

3. fluentdコンテナのタイムゾーン

初期の状態ではUTCになっていた。docker-composeにて、環境変数でタイムゾーンを指定しても反映されなかった。
下記のサイトを参照して、Dockerfileを修正し、コンテナイメージを変更した。
Dockerコンテナ(Fluentd)のTimeZoneをUTCからJSTに変更する

その他のTips

1. 既存ログの読み込み

既に運用を開始しているwebサーバのアクセスログを可視化するため、ログファイルの先頭から読み込みたい。
fluentdの初期設定では、末尾の情報しか読み込まないので、設定の変更が必要になる。
read_from_headをTrueにする。

fluent.conf

<source>
  @type tail
  format nginx
  path /var/log/nginx/access.log
  pos_file /fluentd/data/nginx_access.log.pos
  tag nginx.access
  read_from_head true ← 追加!!
</source>

参考
fluentdのin_tailプラグインの動作について理解する

2. 監視間隔の短縮

デフォルトの設定では、ログファイルの更新を確認する監視間隔は60秒になっている。動作確認をする際には、時間間隔が短いほうが都合がいいので、設定を変更した。
fluent.conf

<source>
  @type tail
  format nginx
  path /var/log/nginx/access.log
  pos_file /fluentd/data/nginx_access.log.pos
  tag nginx.access
  read_from_head true
  refresh_interval 10 ← 追加!!
</source>

参考
fluentdのin_tailプラグインの動作について理解する

3. テーブルのオートインクリメントの初期化

DBへの格納を試行錯誤していると、オートインクリメントによってIDの値がどんどん大きくなっていってしまう。
運用開始時点では、1から始まるようにしたいので、オートインクリメントの値を初期化した。
以下のSQLを実行することで初期化できる。

ALTER TABLE <テーブル名> AUTO_INCREMENT = 1;

今回のケースでは、以下のSQLになる。

ALTER TABLE nginx_access_log AUTO_INCREMENT = 1;

下記のようにtruncate table文で、すべてのレコードを削除した場合もインクリメントは初期化される。

TRUNCATE TABLE

参考
MySQL で AUTO_INCREMENT の値をリセットする方法
全てのデータを削除する(TRUNCATE TABLE文)

  1. bulk_insert:リレーショナルデータベース(RDB)のテーブルに行を追加する際、複数の行を一回のSQL文の実行で追加すること e-words

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?