ククログ

株式会社クリアコード > ククログ > ConoHa上にDroongaクラスタを設置する手順

ConoHa上にDroongaクラスタを設置する手順

Droongaプロジェクトの結城です。

実際に運用中のDroongaクラスタ

Droongaプロジェクトは現在の所「レプリケーション機能があるGroonga互換の全文検索システム」を当座の目標としていますが、目標達成のためには不足している機能の実装だけでなく、「安定して動作する」という運用実績を作る必要もあります。そこで、デモンストレーションも兼ねて、GroongaのパッケージサーバがあるConoHaのクラウド上でDroongaクラスタを運用してみています。

このDroongaクラスタの全体像は、以下の図の通りです。

(運用中のDroongaクラスタの構成)

実際にhttp://157.7.124.247:80/にアクセスすると、Groonga AdminによるUIを経由して、動作中のDroongaクラスタのデータベースの内容を見られます。

このクラスタには現在の所、以下のデータが継続的に格納されています。

図ではパッケージサーバのログも収集するように描かれていますが、実は今の所はまだ、DroongaクラスタのHTTPサーバ自身のログのみ収集しています。

Droongaは複数ノード構成での運用が前提なので、当然ながら何台ものサーバが必要になります。 そんな時、物理的なサーバよりも簡単に調達でき、自前の仮想マシンよりもはるかに実用的なのが、ConoHaのようなクラウド形式のVPSサービスです。

このエントリでは、上記の運用実験用クラスタの構築手順を振り返りながら、ConoHa上にDroongaクラスタを構築する具体的な手順をご紹介します。同様の構成でDroongaを試してみる際の参考にしてください。

前提条件と完了条件

今回やりたかったこととやりたくなかったことは、以下の通りです。

  • ConoHaのクラウド上に既に運用しているサーバがあり、そのログを収集してDroongaクラスタに格納させたい。 (※今回の場合はGroongaのパッケージサーバです。が、実際にはこれはまだやっていません……)

  • 将来的にはその他にも、継続的に情報を収集してDroongaクラスタに格納させたい。

  • データの書き込みは信用できる相手だけに許可して、それ以外のユーザにはリードオンリーで利用させたい。

これらを実現するために、次のような方針を定めました。

  • 基本的な通信はローカルネットワーク上で完結させる。(速度、セキュリティ、利便性のため)

  • リバースプロキシを使い、一部の機能だけをインターネット経由で利用できるように公開する。(セキュリティを保ちつつ、デモンストレーションとして活用するため)

  • ログの収集にはFluentdを使う。(別のサーバのログを簡単に収集するため)

実際の作業は、以下の要領で進めます。

  1. ローカルネットワークを作成する。

  2. Droongaノード用のVPSを作成する。

  3. リバースプロキシを設定する。

  4. Fluentdを設定する。

順番に見ていきましょう。

ローカルネットワークの作成

ConoHaのVPSは最初からグローバルIPアドレスが割り当てられており、そのままWebサービスを公開できるようになっています。 しかし、GroongaもDroongaもHTTPのGETメソッドでデータベースの内容を変更できてしまうので、グローバルIPでの運用はお薦めできません。

幸い、ConoHaでは無料でVPSをローカルネットワークに所属させられますので、DroongaのサービスはローカルネットワークのIPアドレスで起動しておいて、サーバ同士はこのローカルネットワーク内で通信するようにすれば、Droongaクラスタを安全に運用できます。 また、ConoHaではローカルネットワークの方が高速なので、ノード間の通信が多いDroongaでは性能的なメリットも大きいです。

今回の構成では、手順に従って192.168.0.0/24のプライベートネットワークを作成しました。 同時に既存のパッケージサーバも、ネットワークインターフェースを追加してこのプライベートネットワークに参加させるようにしました。 今後新たにVPSを作成した場合も、Droongaクラスタと連携する必要があればこのネットワークに参加させることになります。

Droongaノードに使うVPSの準備

OSの入れ換え

ConoHaでVPSを作成する時は、テンプレートイメージとして「汎用のCentOS 6.5」と「CentOS 6.5にWordPressとnginxをインストールした状態」のどちらかを選べます。 しかしDroongaは現在の所、CentOSについてはCentOS 7へのインストールにのみ対応しており、CentOS 6.5にインストールするのは骨が折れます。

なので、今回はVPSを作成した後で、OSを自分で入れ替えて使うことにしました。

このような使い方をする場合、VPSの作成時のテンプレートイメージはどちらを選んでも構いません。 また、VPS作成時に入力するrootパスワードは最終的には使わないので、パスワード欄には適当な文字列を入力しておいて大丈夫です。

VPSが作成されたら、すぐにシャットダウンします。 その後、手順に従ってネットワークインターフェースを追加して192.168.0.0/24のローカルネットワークに参加させます。

テンプレートイメージをそのまま使う場合はこの後VPSを起動しますが、OSを入れ替える場合はここから先の手順が違います。 今回は、ディスクイメージからのインストールでOSをUbuntu 14.04LTSにしてみました。手順は以下の通りです。

  1. Ubuntu 14.04LTS 64bitのディスクイメージを挿入して、VPSの電源を入れる。

  2. 仮想コンソールでVPSに接続し、Ubuntuをインストールする。

    • インストール中に使うネットワークインターフェースはeth0(インターネットに繋がっているインターフェース)を選択する。

    • ホスト名はdroonga0とする。

    • インストール先のパーティションは、Guided - use entire diskを選択して、/dev/vdbを選ぶ。(容量が大きい方)

    • インストールオプションは以下の2つにチェックを入れる。

      • Basic Ubuntu server

      • OpenSSH server

    • 初期ユーザ名、パスワードはお好みで。

  3. インストールが完了したら、VPSの電源を落とす。

  4. ディスクイメージを排出する。

  5. 再度VPSの電源を入れる。

……という手順でUbuntuをインストールしたのですが、その後になってから、インストールイメージを使う方法があるということに気が付きました。 使いたいディストリビューションのバージョンのインストールイメージが提供されているのなら、そちらの方を使ったほうが圧倒的に簡単なのは間違いないので、これはあくまで、インストールイメージが無い場合の進め方という事にしておきます。

Droongaノード用VPSの1台目ができたら、2台目も作成します。 設定やOS入れ替えの手順はほぼ同じですが、今度はホスト名をdroonga1にします。

VPSを2台用意できたら、分かりやすいようにConoHaの管理コンソール上での表示ラベルもdroonga0droonga1に変更しておきます。

鍵認証の設定

OS入れ換え直後のVPSはSSHを使ってパスワード認証でリモートログインできる状態になっていますが、これはセキュリティ的に脆弱ですので、より安全な公開鍵認証を強制するように設定しておきます。

公開鍵の登録にはssh-copy-idコマンドを使います。 手元のPC(Ubuntu)で、以下の要領で入力します。

$ ssh-copy-id -i 公開鍵へのパス ノードのユーザ名@ノードのIPアドレス

今回のDroongaノード用VPS(droonga0)なら、以下のようになります。

piro@localpc$ ssh-copy-id -i .ssh/id_rsa.pub piro@157.7.124.247

これで鍵認証でSSH接続できるようになったので、早速手元のPCのGNOME端末からVPSに接続してみます。

piro@localpc$ ssh piro@157.7.124.247
piro@droonga0$ 

以後の操作は手元のPCから行うということで、ConoHaの仮想コンソールは閉じてしまいます。

SSHデーモンの設定変更

droonga0droonga1/etc/ssh/sshd_configを変更して、SSHを安全に運用するための定番の設定を行う事にします。

  • Port 22Port (適当な空きポート番号)に書き換えて、SSH接続に使うポート番号を変更します。 これはセキュリティ的な対策というよりも、外部から22番ポート決め打ちでアタックされた時にログが大量に記録されてしまってウザくないように、という意味合いが主です。

  • PermitRootLogin without-passwordPermitRootLogin noに書き換えて、リモートからの直接のrootログインを禁止します。 Ubuntuの場合はそもそも普通に操作しているとrootログインする場面はありませんが、念のためです。

  • PasswordAuthentication noを追加します。 これにより、パスワード認証でのリモートログインが禁止されます。

設定を編集したら、sshdを再起動します。

$ sudo service ssh restart

次に、新しいポート番号で鍵認証によって接続できる事を確認します。 GNOME端末上の現在の接続はそのままにして、GNOME端末の新しいタブを開いてからそちらで接続します。 例えば変更後のポート番号が2222なら、以下の要領です。

piro@localpc$ ssh piro@157.7.124.247 -p 2222
piro@droonga0$ 

設定を間違えてしまっていてうまくいかない場合は、元のタブの方の接続で設定を修正します。 このように、リモートからのログインに関係する重要な設定を変更する時は、元のセッションを保持したまま作業するとトラブル対応を楽にできます。 元のセッションが切断されてしまった場合は、面倒ですがConoHaの仮想コンソールから操作するほかありません。

固定IPの設定

この時点では、ローカルネットワーク用のインターフェースであるeth1にはIPアドレスが割り当てられていません。 ConoHaのローカルネットワークには初期状態ではDHCPサーバがいないからなのですが、そもそもDroongaクラスタのような物を運用する場合はIPアドレスがコロコロ変わる方が面倒なので、ここはDHCPサーバを立てずに固定IPを自分で設定することにしました。

droonga0droonga1/etc/network/interfacesに、以下の要領でeth1の設定を追加します。

auto eth1
iface eth1 inet static
address 192.168.0.50
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
  • addressの値はノードごとに変えます。 droonga0192.168.0.50droonga1192.168.0.51としました。 ちなみに、ConoHaの仕様により、IPアドレスは11254の範囲で設定する必要があります。

  • デフォルトゲートウェイは設定しません。

ネットワークインターフェースの設定ができたら、インターフェースeth1を有効化します。

$ sudo ifup eth1

Ubuntuならsudo service networking restartなんじゃないの……?と思われるかも知れませんが、Ubuntu 14.04LTSでは既知の不具合のため、これはエラーになってしまいます。 なので、ifupコマンドを直接使っています。

ともかくこれで、Droongaノード用のVPS同士は互いに192.168.0.50192.168.0.51というIPアドレスで通信できるようになりました。 便利なように、それぞれの/etc/hostsに以下の行を追加(および、127.0.0.1への自身のホスト名の割り当てを削除)して、互いに名前で参照できるようにしておきます。

192.168.0.50 droonga0
192.168.0.51 droonga1

Droonga Engineのインストール

ここまで来たら、後はDroongaのチュートリアルにある通りの手順でDroongaノードとしてVPSを設定するだけです。

droonga0$ curl https://raw.githubusercontent.com/droonga/droonga-engine/master/install.sh | \
            sudo HOST=droonga0 bash

HOSTの指定はノードごとに変えます。

Droonga Engineがインストールされたら、片方をもう片方にjoinさせて、クラスタを構築します。 droonga1droonga0のクラスタに参加させるなら、以下の通りです。

droonga0$ droonga-engine-join --host droonga1 --replica-source-host droonga0
Start to join a new node droonga1
       to the cluster of droonga0
                     via droonga0 (this host)
    port    = 10031
    tag     = droonga
    dataset = Default

Source Cluster ID: 88260971556bc9203087d476c0566c9da0114695

Changing role of the joining node...
Configuring the joining node as a new replica for the cluster...
Registering new node to existing nodes...
Changing role of the source node...
Getting the timestamp of the last processed message in the source node...
The timestamp of the last processed message at the source node: 2015-05-13T05:04:20.317923Z
Setting new node to ignore messages older than the timestamp...
Copying data from the source node...
0% done (maybe 00:00:00 remaining)
Restoring role of the source node...
Restoring role of the joining node...
Done.

これで、2ノードからなるDroongaクラスタができました。

安全なクラスタである事の確認

このDroongaクラスタが本当に外部から接続できない安全なクラスタかどうかを、念のため確認しておきます。

チュートリアルの通りにスキーマを定義した状態から、以下のコマンドを実行して、ローカルネットワークのIPアドレス宛にレコードの追加と検索のリクエストを送ってみます。

droonga0$ echo '{"type":"add","body":{"table":"Store","key":"dummy-store0","values":{"name":"Dummy Store 0"}}}' | \
            droonga-send --server droonga:192.168.0.50:10031/droonga

droonga0$ droonga-groonga select --table Store --limit -1 --output_columns name --pretty
[
  [
    0,
    1431500987.197475,
    1.1444091796875e-05
  ],
  [
    [
      [
        1
      ],
      [
        [
          "name",
          "ShortText"
        ]
      ],
      [
        "Dummy Store 0"
      ]
    ]
  ]
]

selectの結果を見ると、ちゃんとレコードが追加されている事が分かります。

今度は、ローカルネットワーク以外のIPアドレス宛にレコードの追加と検索のリクエストを送ってみます。

droonga0$ echo '{"type":"add","body":{"table":"Store","key":"dummy-store2","values":{"name":"Dummy Store 1"}}}' | \
            droonga-send --server droonga:localhost:10031/droonga
E, [2015-05-13T14:24:01.896664 #14333] ERROR -- : Failed to connect fluentd: Connection refused - connect(2)
E, [2015-05-13T14:24:01.896899 #14333] ERROR -- : Connection will be retried.
E, [2015-05-13T14:24:01.908777 #14333] ERROR -- : FluentLogger: Can't send logs to localhost:10031: Connection refused - connect(2)

droonga0$ echo '{"type":"add","body":{"table":"Store","key":"dummy-store2","values":{"name":"Dummy Store 1"}}}' | \
            droonga-send --server droonga:127.0.0.1:10031/droonga
E, [2015-05-13T14:24:01.896664 #14333] ERROR -- : Failed to connect fluentd: Connection refused - connect(2)
E, [2015-05-13T14:24:01.896899 #14333] ERROR -- : Connection will be retried.
E, [2015-05-13T14:24:01.908777 #14333] ERROR -- : FluentLogger: Can't send logs to 127.0.0.1:10031: Connection refused - connect(2)

droonga0$ echo '{"type":"add","body":{"table":"Store","key":"dummy-store2","values":{"name":"Dummy Store 1"}}}' | \
            droonga-send --server droonga:157.7.124.247:10031/droonga
E, [2015-05-13T14:24:01.896664 #14333] ERROR -- : Failed to connect fluentd: Connection refused - connect(2)
E, [2015-05-13T14:24:01.896899 #14333] ERROR -- : Connection will be retried.
E, [2015-05-13T14:24:01.908777 #14333] ERROR -- : FluentLogger: Can't send logs to 157.7.124.247:10031: Connection refused - connect(2)

$ droonga-groonga select --table Store --limit -1 --output_columns name --pretty

127.0.0.1(ループバックアドレス)も157.7.124.247(グローバルIPアドレス)も、指定のポートに接続できないというエラーになっています。 selectによる検索はエラーが出ていませんが、これは接続エラーが内部でハンドルされているためで、結果はやはり得られていません。 もう1度192.168.0.50を指定して検索してみると、当然ながら結果に変化は無く、レコード追加のリクエストは処理されていないことが分かります。 (このような結果になるのは、Droonga Engineのサービスが初期化時に指定されたホスト名およびそれに紐付けられたIPアドレスにのみバインドされているからです。)

ということで、Droongaクラスタがローカルネットワーク向けにのみサービスを提供していることを確認できました。 ちなみに、Droonga Engine同士が互いの死活状態を把握するために使っているSerfのサービスも、同様にローカルネットワーク内でのみ利用できるようになっています。

droonga0$ sudo -u droonga-engine -H ~droonga-engine/droonga/serf -rpc-addr 192.168.0.50:7373
droonga0:10031/droonga     192.168.0.50:7946  alive  role=service-        provider,type=engine,cluster_id=5531f182f96b4699b55f0aa7cb100a118c73945a,internal-name=droonga0:46944/droonga

droonga0$ sudo -u droonga-engine -H ~droonga-engine/droonga/serf members  -rpc-addr localhost:7373
Error connecting to Serf agent: dial tcp 127.0.0.1:7373: connection refused

droonga0$ sudo -u droonga-engine -H ~droonga-engine/droonga/serf members  -rpc-addr 127.0.0.1:7373
Error connecting to Serf agent: dial tcp 127.0.0.1:7373: connection refused

droonga0$ sudo -u droonga-engine -H ~droonga-engine/droonga/serf members  -rpc-addr 157.7.124.248:7373
Error connecting to Serf agent: dial tcp 157.7.124.248:7373: connection refused

Droonga HTTP serverのインストール

Droonga EngineだけではHTTP接続できないので、Droonga HTTP serverもインストールしておきます。

droonga0$ curl https://raw.githubusercontent.com/droonga/droonga-http-server/master/install.sh | \
            sudo HOST=droonga0 ENGINE_HOST=droonga0 bash

HOSTENGINE_HOSTの指定はノードごとに変える必要があります。

Droonga HTTP serverをインストールできたら、設定を変えて、サービスを0.0.0.0ではなくローカルネットワークのIPアドレスにバインドするようにします。

droonga0$ sudo droonga-http-server-configure 
Do you want the configuration file "droonga-http-server.yaml" to be regenerated? (y/N): y
IP address to accept requests from clients (0.0.0.0 means "any IP address") [0.0.0.0]: 192.168.0.50
...
enable "trust proxy" configuration (y/N): y
...

上記以外の箇所はすべて既定値のままにします。 これで、Droonga HTTP serverもDroonga Engine同様に外部からのアクセスを受け付けなくなります。

droonga0$ curl http://localhost:10041/engines
curl: (7) Failed to connect to localhost port 10041: Connection refused

droonga0$ curl http://157.7.124.247:10041/droonga/system/status
curl: (7) Failed to connect to 157.7.124.247 port 10041: 接続を拒否されました

ここまでの結果を図にすると、以下のような構成になっているという事になります。

(ローカルネットワーク向けにDroongaクラスタが構成されている様子の図)

サーバを安全に運用する、という話になるとファイアウォールの設置やiptablesといった話題が出てきがちですが、Droongaノードはこの種の技術との相性が悪いです。 というのも、Droongaはランダムに決まったポート番号でメッセージを受け付ける部分があるため、どのポートを開放するかということを事前に完全には決めきれないのです。 なので、今回の例のように、外界から隔離されたネットワーク内で互いに自由に通信できるDroongaノード同士でクラスタを構成しておき、セキュリティ対策は別のレイヤで講じるのが、Droongaクラスタの推奨運用スタイルということになります。 (言い換えると、複数拠点間をインターネット越しに繋いだDroongaクラスタの構築は非常に面倒という事になります。速度的なデメリットもありますので、そのような構成は非推奨というのが正直な所です。)

リバースプロキシの設定

さて、安全なDroongaクラスタを構築できたわけですが、このままだとConoHa上のローカルネットワークに属しているVPSからでないとDroongaクラスタに接続できません。 インターネット越しにDroongaクラスタに接続するには、SSHでポートフォワードするなどの工夫が必要になります。 このクラスタはDroongaの運用デモンストレーションに使いたいので、これでは困ります。

そこで、リバースプロキシとしてnginxを設定しました。

(nginxをリバースプロキシとして利用して、80番ポートへのアクセスをDroonga HTTP serverに繋いでいる様子の図)

リバースプロキシとして設定されたnginxは、グローバルIPアドレスの80番ポートで接続を待ち受けて、受け付けたリクエストのうち安全な物だけをDroonga HTTP serverに引き渡すという動作をします。 これで、Droongaクラスタを意図しない変更から守りつつ、内容をインターネットで公開することができます。

nginxの導入は、Ubuntuであればaptでインストールして設定を作成するだけで済みます。 Droonga HTTP server用の設定は、Ningx本体の一般的な設定とは別のファイルに分けておくと管理が容易です。

droonga0$ sudo apt-get install nginx
droonga0$ sudo vi /etc/nginx/conf.d/droonga-http-server.conf

/etc/nginx/conf.d/droonga-http-server.confの内容は以下の通りです。

upstream droonga-http-server {
    server 192.168.0.50:10041;
}

server {
    listen 80;
    server_name 157.7.124.247;
    location ~ ^/($|favicon\.|(js|css|images|scripts|styles|views|[^\.]+\.(html|txt))/|engines|connections|cache|d/(select|table_list|column_list|status|suggest)|droonga/(search|system/status|system/statistics)) {
        proxy_pass http://droonga-http-server;
    }
}

locationに定義しているのは、この正規表現にマッチするパスのリクエストだけを192.168.0.50に転送するという指定です。 機能のうち極限られた部分だけが安全で、それ以外は全て危険、という場合にはこのようにホワイトリスト形式でリバースプロキシを設定するのが定石です。

ファイルを編集し終えたら、nginxを再起動します。

droonga0$ sudo service nginx restart

これで、安全なリードオンリーのリクエストのみ、インターネット上からnginxを経由してDroonga HTTP serverに送れるようになりました。 同様の手順でdroonga1にもnginxを設定しておけば、droonga0droonga1のどちらもDroongaクラスタへの公開エンドポイントとして利用できるようになります。 ちなみに、この記事の冒頭に記載したリンクも、このリバースプロキシ経由でDroonga HTTP serverに接続するための物です。

nginxのログを収集してDroongaクラスタに格納する

これだけだと本当にただ単にDroongaクラスタがあるだけなので、デモンストレーションとしては役に立ちません。 また、継続的にリクエストがある状態にしておかないと、「ちゃんと安定して動作しているかどうか」という検証にもなりません。 そこで、手始めにFluentdを使ってdroonga0自体のnginxのアクセスログを収集するようにしてみました。

Fluentdでは、いくつかのプラグインを組み合わせて「情報ソースからデータを取得してくる」→「データを加工する」→「データを出力する」という事を行います。 この時、データの出力先として他のノードを指定したり、データの情報ソースとして他のノードからの流入を受け付けたりすることで、複数ノードからの情報を一箇所に簡単に集められます。

今回の事例では、droonga0droonga1のそれぞれについてnginxのログを収集して、droonga0のDroonga HTTP serverを使ってログをデータベースに格納するように設定しました。 図にすると以下の要領です。

(Droongaクラスタ、リバースプロキシのnginx、Fluentdの3者が連携している様子の図)

Fluentdのインストール

何はともあれ、Fluentdを各ノードにインストールする必要があります。 droonga0droonga1の両方に、以下の手順でFluentdをインストールします。

$ sudo apt-get install ntp
$ sudo service ntp restart
$ curl -L http://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sudo sh

ログを監視するノードでの設定

続けて、nginxのログを監視したいすべてのノード(ここではdroonga0droonga1)で、必要な設定を行います。 まず、nginxのログをFluentdから読めるようにグループとパーミッションを設定します。

$ sudo chmod -R g+r /var/log/nginx
$ sudo chgrp -R adm /var/log/nginx
$ sudo usermod -a -G adm td-agent

td-agentユーザやグループに対して読み取りの権限を与えるのではなく、admグループに読み取りの権限を与えた上でtd-agentadmグループに所属させる、という操作をしているのがポイントです。

admというのは端的に言うと「ログを見る権限のあるユーザ」を示すグループ名です。 ログファイルのグループをtd-agentに変更する方法だと、ログローテーションが発生すると新しいログファイルのグループは自動的にadmに設定されるため、ログローテーションの度にファイルのアクセス権を設定し直さないといけないということになってしまいます。

次に、必要なFluentdプラグインを導入します。 多くのFluentdプラグインはGemパッケージとして提供されていますが、gemではなくtd-agent-gemコマンドを使うことで、Fluentd専用にそれらのパッケージをインストールできます。

$ sudo td-agent-gem install fluent-plugin-config-expander
$ sudo td-agent-gem install fluent-plugin-parser
$ sudo td-agent-gem install fluent-plugin-anonymizer

各プラグインの役割は以下の通りです。

  • fluent-plugin-config-expander:設定の中で変数を使えるようにします。

  • fluent-plugin-parser:nginxのログファイルの各行を、扱いやすいように各フィールドの名前をキーとしたハッシュに変換します。

  • fluent-plugin-anonymizer:特定のフィールドの値をハッシュ化し、プライバシーを保ちつつ、元は別々の値であったことを分かるようにします。nginxのログにはプライバシーに関わる情報が含まれるため、これを使って匿名化しておきます。

必要なプラグインが揃ったら、Fluentdの設定ファイル(/etc/td-agent/td-agent.conf)に以下の設定を書き加えます。

$ sudo vi /etc/td-agent/td-agent.conf
# nginxのアクセスログを監視する
<source>
  type config_expander
  <config>
    type tail
    path /var/log/nginx/access.log
    pos_file /var/log/td-agent/nginx.pos
    # 後で分かりやすいように、タグにホスト名を含める。
    tag nginx.log.${hostname}
    format nginx
  </config>
</source>

# プライバシーに関わる情報を匿名化する
<match nginx.log.*.**>
  type anonymizer
  # 公開するログサーバなので、refererも匿名化する
  sha1_keys remote, user, referer
  # 値をハッシュ化する際のsaltなので、ここは任意の文字列に変えておく
  # (各ノードで共通の値にする)
  hash_salt droonga-log-cluster
  add_tag_prefix anonymized.
</match>

droonga0以外のノードでは、以下の設定も付け足して、ログをdroonga0に送るようにします。

# ログをdroonga0宛に転送する
<match anonymized.*.log.*.**>
  type forward
  <server>
    host droonga0
  </server>
</match>

ログをDroongaクラスタに格納するための設定

他のノードから送られてきたログを受け取ってDroongaクラスタに格納するためのエンドポイントとなるdroonga0では、さらに追加の設定が必要です。

まず、必要なFluentdプラグインを導入します。

droonga0$ sudo td-agent-gem install fluent-plugin-record-reformer
droonga0$ sudo td-agent-gem install fluent-plugin-groonga

各プラグインの役割は以下の通りです。

  • fluent-plugin-record-reformer:タグ名から取り出した値などを使って、フィールドの値を再設定します。

  • fluent-plugin-groonga:ログをGroongaのレコードとしてloadします。GroongaサーバにはHTTPでリクエストを送る事ができるため、Droongaにもそのまま利用できます。

fluent-plugin-groongaのバッファ保存先に使うために、Fluentdが読み書きできるディレクトリを作成します。

droonga0$ sudo mkdir -p /var/spool/td-agent/buffer/
droonga0$ sudo chown -R td-agent:td-agent /var/spool/td-agent/

Fluentdの設定ファイルに、ログをDroongaクラスタに格納するための設定を書き加えます。

droonga0$ sudo vi /etc/td-agent/td-agent.conf
# 他ノードからforwardされてきたログを取り込む
<source>
  type forward
</source>

# 各ホストから流入してきたログに、ホストを識別するための情報を付与する
<match anonymized.*.log.*.**>
  type record_reformer
  enable_ruby false

  tag ${tag_parts[2]}

  <record>
    host ${tag_suffix[3]}
    type ${tag_parts[1]}
    timestamp ${time}
  </record>
</match>

# ここまでの加工が全て終わったログのみを記録する
<match log>
  type groonga
  store_table Logs

  protocol http
  host droonga0

  buffer_type file
  buffer_path /var/spool/td-agent/buffer/groonga
  flush_interval 1s

  <table>
    name Terms
    flags TABLE_PAT_KEY
    key_type ShortText
    default_tokenizer TokenBigram
    normalizer NormalizerAuto
  </table>

  <table>
    name Hosts
    flags TABLE_PAT_KEY
    key_type ShortText
  </table>

  <table>
    name Timestamps
    flags TABLE_PAT_KEY
    key_type Time
  </table>

  <mapping>
    name host
    type Hosts
    <index>
      table Hosts
      name logs_index
    </index>
  </mapping>

  <mapping>
    name timestamp
    type Time
    <index>
      table Timestamps
      name logs_index
    </index>
  </mapping>

  <mapping>
    name path
    type Text
    <index>
      table Terms
      name logs_message_index
      flags WITH_POSITION
    </index>
  </mapping>

  <mapping>
    name referer
    type Text
    <index>
      table Terms
      name logs_message_index
      flags WITH_POSITION
    </index>
  </mapping>
</match>

ログの収集を開始する

設定が終わったら、各ノードのFluentdを再起動します。

$ sudo service td-agent restart

これで、Fluentdがnginxのログを読み始めて、結果がfluent-plugin-groongaを経由してDroongaクラスタに格納されるようになります。

まとめ

以上、ConoHa上にDroongaクラスタを構築する手順と、そのDroongaクラスタに継続的に情報を格納する例としてnginxのログをFluentdで収集する手順を紹介しました。

Droongaはまだまだ開発途上のプロジェクトのため、Groongaに対して実装が追いついていない部分や、Droonga独自の部分で不具合が残っている部分があります。 お恥ずかしい話ですが、今回の公開用クラスタの構築中にもいくつかの不具合を見つけて修正しました。 継続的な運用を通じてこういった不安要素を排除していき、安心して誰でも使えるようなクオリティの物にDroongaを育てていきたいと思っています。 また、実際にDroongaを試してみて不具合に遭遇したりドキュメントの不備を見つけられた方は、GitHubのイシュートラッカーに問題を報告したり、修正内容をプルリクエストで送ったりして頂ければ幸いです。