Raccoon Tech Blog [株式会社ラクーン 技術戦略部ブログ]

株式会社ラクーン 技術戦略部より、tipsやノウハウなど技術的な話題を発信いたします。

サーバ

Fabric + Serverspec 社内勉強会

こんにちは。主にCORECの開発に携わっている、技術戦略部のおおはらです。

同部の松尾が主催した「Fabric + Serverspec 社内勉強会」に参加しました。

勉強会のゴールはFabricを使ってサーバに設定をし、正しく設定されたことをServerspecで確認する、ということです。

今回のハンズオン環境として、FabricとServerspecがインストールされたUbuntuのVMイメージが事前に配布されました。それをVMWare PlayerまたはVirtual Boxを使って各自のノートPCにハンズオン環境を構築しています。

最初に、松尾からハンズオンをスムーズに進めるためにUbuntuの便利な使い方(ワークスペース、tmux)の説明がありました。そして、勉強用のサーバをAWS上に各自作成しました。

IMG_20150313_145328


次にFabricの基本的な説明がありました。
FabricはPython製のデプロイツールで、サーバでsshが動いていればOK(サーバにpython不要)、既存のシェルスクリプトとFabricのメソッドでタスクを簡単に書ける、といった特徴を持ちます。
具体的なタスクの書き方、fabコマンドによるタスクの実行の仕方の解説の後、実習としてnginxのインストールやスタート、crontabの更新といったタスクを作成、実行しました。

最後にServerspecの解説です。
ServerspecはRuby製のサーバ自動テストツールで、サーバでsshが動いていればOK、RSpec形式でテストコードが書ける、といった特徴があります。
勉強会資料を参考に、Fabricでインストールしたnginxが動作していることを、Serverspecでテストを書き、実行して確認しました。

デプロイツールには大規模なシステムでの実績があるChefやAnsibleといった有名なものもありますが、別の選択肢としてシンプルにタスクが書けるFabricが弊社では上手く使えそうな気がします。

私が携わっているCORECではサーバ設定の一部をwikiで管理したり手動設定している部分があります。まずは、設定をファイルとしてgitで管理し、Fabricで設定することから始めていこうと思いました。

fluentd(td-agent) の導入

はじめまして。開発チームの yuzuki です。

7/1に弊社の 決済サービスPaid(ペイド) のサーバー群へ
ログ集約の改善を目的として導入した fluentd(td-agent) の導入手順などをまとめてみました。

ログ集約を改善する動機

弊社ではこれまで(今も大部分は) cron + rsync を使い、週次バッチでWebサーバー上のログファイルをファイルサーバーへ転送することで一応の集約をさせてきました。
(集約というよりはバックアップといった意味合いの方が強いかもしれません)
サーバー台数が少なかった頃はこの仕組みでも特に大きな問題はなかったと思いますが、
サービスの成長にあわせて、サーバー台数が増え、リリース時に運用系と待機系を相互に切り替える運用へ変わったことで、
ログファイルから問合せや障害などの調査を行う際に、まずログファイルを取得することに手間が掛かる状況になっていました。

下記は弊社のもう1つのサービス ファッション・雑貨向けB2Bサイトスーパーデリバリー
(以下 SUPER DELIVERY)のサーバー構成です。

sd-network


当日分のログファイルについては、まず1系と2系のどちらが運用系なのかを調べてから、
片系で4台あるサーバー全てからログファイルをscp/sftpでせっせと取得し調査していました。

過去分のログファイルについては、各サーバーでローテーションされ週次バッチでの集約を待つ状態と、
週次バッチで各サーバーからファイルサーバーへ集約された状態の2つの状態があります。
※この集約は1台のサーバーに集まるというだけで、1ファイルにまとまるわけではありません。

過去分は、運用系/待機系の切り替えも考慮すると、両方のログを調査対象とするのが確実であるため
  • 集約待ちであれば全8台のサーバーからログファイルを取得
  • 集約済みであれば1台のサーバーの8つのディレクトリからログファイルを取得
といった手間が調査の度に発生していました。

「ここ、何とかならないかな?」と、ずっと思っていたところに現れたのが fluentd です。
fluentd を各サーバーへインストールして、ログの転送を任せてしまえば
1日のログを1台のファイルサーバーの1つのファイルにまとめることが出来てしまいます。


余談:
SUPER DELIVERYが動機になっているのに、なぜPaidへの導入記事なのかというと、
先に導入のコンセンサスが取れたのがPaidだったから、というだけの理由です。
もうPaidで実績ができましたし、SUPER DELIVERYへの導入ハードルも下がったように思います。

fluentd(td-agent) とは?

"Fluentd" is an open-source tool to collect events and logs.
http://fluentd.org/

fluentd は、ほぼリアルタイムでログの読み込み、加工、転送、さらには書き込みまでも行ってくれる非常に素晴らしい Ruby ベースのミドルウェアです。
ログ以外にも、メッセージと表現されることもあります。
※cron + rsync と異なり、扱えるのはログファイルだけではありません!


fluentd はプラグインを書くことで拡張も可能で、既に多くのプラグインが開発・公開されています。
http://fluentd.org/plugin/

fluentd は標準プラグインがバンドルされた Ruby の gem です。
http://rubygems.org/gems/fluentd

td-agent は fluentd 専用の Ruby や jemalloc などがバンドルされ、
安定感のある fluentd の配布パッケージ(rpm, deb など)です。
http://docs.treasuredata.com/articles/td-agent

導入対象のシステムには Ruby 1.9.3 が入っていたこともあり、
既存機能への干渉を避けるため、td-agent を選びました。

td-agent のインストール

執筆時点の弊社では CentOS 5.x on x86_64 が主流なので、
下記のページを参考にインストールしました。
http://help.treasuredata.com/customer/portal/articles/1246904-installing-td-agent-on-rhel-and-centos
※以下、x86_64環境を前提として書いています。

まずはroot権限を持っているユーザーで下記のコマンドを実行し、ファイルを作成します。
# touch /etc/yum.repos.d/td.repo

次に、お好みのエディタで下記の通りに編集して保存します。
[treasuredata]
name=TreasureData
baseurl=http://packages.treasure-data.com/redhat/$basearch
gpgcheck=0

最後に下記のコマンドを実行し、td-agent をインストールします。
# yum install td-agent

インストール手順は上記のページに書かれている内容に従っています。

td-agent のファイル配置場所など

■td-agent の起動スクリプト
/etc/rc.d/init.d/td-agent

■td-agent の設定ファイル テンプレート
/etc/td-agent/td-agent.conf.tmpl

■ td-agent にバンドルされた Ruby のインストール先
/usr/lib64/fluent/ruby/

■ td-agent のログ出力先
/var/log/td-agent/

■ td-agent の.pid出力先
/var/run/td-agent/

fluentd 内部でのログのルーティング

プラグインについて触れる前に、タグについて簡単に説明します。

現在の fluentd v10 は内部で、タグと呼ばれる文字列でログのルーティングを行っています。
タグはピリオードで区切られた文字列で、プラグインで処理を行う度に remove_tag_prefix, add_tag_prefix などでタグの書き換えを行い、
いくつかのプラグインを経由していくのが一般的かと思います。

基本的なタグの書き換えは下記のような設定になっています。
#ログ読み込み時のタグは raw.apache.access
<source>
  type tail  #標準のin_tailプラグイン
  tag raw.apache.access
  ...
</source>

#タグが filtered.apache.access と完全一致する場合、ログをファイルに出力
#※本来は一番下に書くべき設定ですが、この位置に書いても動作することの説明のため
# あえてここに書いています
<match filtered.apache.access>
  type file  #標準のout_fileプラグイン
  ...
</match>

#タグが raw.apache.access と完全一致する場合、先頭の raw を除去し apache.access とする
#そして新しいタグ apache.access で先頭からタグのルーティングをやり直す
<match raw.apache.access>
  type my_remove_tag_prefix_filter  #このようなプラグインは存在しません
  remove_tag_prefix raw
</match>

#タグが apache.access と完全一致する場合、先頭に filtered を追加し filtered.apache.access とする
#そして新しいタグ filtered.apache.access で先頭からタグのルーティングをやり直す
<match apache.access>
  type my_add_tag_prefix_filter     #このようなプラグインは存在しません
  add_tag_prefix filtered
</match>

この例では完全一致のみ説明していますが、パターンによるマッチもサポートされています。
詳しくは下記のページにある 「*」 「**」 「{X,Y,Z}」 の3ヶ所を参照してください。
http://docs.fluentd.org/articles/config-file#2-ldquomatchrdquo-tell-fluentd-what-to-do

なお、次のメジャーバージョンである fluentd v11 ではラベルなるとか・・・?

fluentd プラグインのインストール

今回は fluent-plugin-route と fluent-plugin-rewrite-tag-filter の2つのプラグインを追加でインストールして使用しました。
この2つのプラグインを簡単に説明します。

fluent-plugin-route は、上記で説明した remove_tag_prefix, add_tag_prefix を使い
柔軟なログのルーティングを実現することが出来ます。
今回は残念ながら大した使い方をしていないため、詳しくはプラグインのページを参照してください。
https://github.com/tagomoris/fluent-plugin-route

fluent-plugin-rewrite-tag-filter は、apache httpdのmod_rewriteのようなプラグインです。
ログ内の項目に対して正規表現によるパターンマッチングを試行し、
マッチした場合、またはマッチしなかった場合に、タグの書き換えを行うことで
柔軟かつ強力なログのルーティングを実現することが出来ます。
なお、フィルタリングの用途にも適しています。
https://github.com/fluent/fluent-plugin-rewrite-tag-filter

では、上記のプラグインをインストールします。
root権限を持っているユーザーで下記のコマンドを実行します。
(※gemに関する環境変数などは設定していません)
# /usr/lib64/fluent/ruby/bin/gem install fluent-plugin-route
# /usr/lib64/fluent/ruby/bin/gem install fluent-plugin-rewrite-tag-filter

エラーが何も出なければ、
/usr/lib64/fluent/ruby/lib/ruby/gems/1.9.1/gems/
にプラグインがインストールされるはずです。
(バンドルされる Ruby のバージョンが上がれば、パスの1.9.1の部分も変わるでしょう)

導入時は /usr/lib64/fluent/ruby/bin/gem を使いましたが、
他にも /usr/lib64/fluent/ruby/bin/fluent-gem を使う方法や、
gem を /etc/td-agent/plugin/ へ配置してインストールする方法もあるようです。

サーバーの構成

Paidのユーザー向けサービスが動いているWebサーバーは2台の運用系(pd01, pd02)と、
1台の待機系(pd04)で構成されています。
残りの1台(pd03)は社内向けサービスが動いているため、今回のログ集約の対象からは除外しました。

このうち運用系をログ転送元、待機系をログ転送(集約)先としてセットアップしました。
(残念ながら、この時点ではまだログ転送先がSPOFです・・・)


paid-network

■ログ集約の構成変更前
ログ集約・変更前

■ログ集約の構成変更後
ログ集約・変更後

起動スクリプトと設定ファイルの構成

Paidのサーバー群には、原則として全てのサーバーが全ての役割を果たせるようセットアップしておくというルールがあるため、ログ転送元とログ転送先に同じファイルを配置しておく必要があります。
他のサービスへの展開なども含め、色々な試行錯誤を繰り返した結果、下記の構成に落ち着きました。
(production環境以外に、staging環境と、test環境用の設定ファイルも作成しました)

■ 起動スクリプト
/etc/rc.d/init.d/
├ td-agent-paid-web-aggregator
└ td-agent-paid-web-forwarder

■ 設定ファイル
/etc/td-agent/
├ config.d/
│ └ paid/
│    ├ forward/
│    │ ├ production/
│    │ │ ├ aggregate.conf
│    │ │ └ forward.conf
│    │ ├ staging/
│    │ │ ├ aggregate.conf
│    │ │ └ forward.conf
│    │ └ test/
│    │    ├ aggregate.conf
│    │    └ forward.conf
│    ├ input/
│    │ ├ java-pd.conf
│    │ └ java-pd-web-service.conf
│    └ output/
│       ├ java-pd.conf
│       └ java-pd-web-service.conf
├ td-agent-common.conf
├ td-agent-paid-web-aggregator-production.conf
├ td-agent-paid-web-aggregator-staging.conf
├ td-agent-paid-web-aggregator-test.conf
├ td-agent-paid-web-forwarder-production.conf
├ td-agent-paid-web-forwarder-staging.conf
└ td-agent-paid-web-forwarder-test.conf

起動スクリプト


■ ログ転送元の起動スクリプト
/etc/rc.d/init.d/td-agent-paid-web-forwarder

サービスへの登録はroot権限を持っているユーザーで下記を実行します。
# chkconfig --add td-agent-paid-web-forwarder
# chkconfig --level 345 td-agent-paid-web-forwarder on

起動スクリプトは、実行環境毎に読み込む設定ファイルを変えたかったため、
/etc/rc.d/init.d/td-agent を少々改変しています。主な改変箇所はスクリプト内の赤字部分です。

※fluentd の新しいバージョンでは、configtest オプションが実装されていますが、
 導入時のバージョンは td-agent 1.1.14(fluentd 0.10.35) であったため
 ここに書いてある起動スクリプトには configtest オプションが含まれていません。


■■ ログ転送元の起動スクリプトの内容
#!/bin/bash
#
# /etc/rc.d/init.d/td-agent-paid-web-forwarder
#
# chkconfig: - 80 20
# description: td-agent
# processname: td-agent-paid-web-forwarder
# pidfile: /var/run/td-agent/td-agent-paid-web-forwarder.pid
#
### BEGIN INIT INFO
# Provides:          td-agent
# Default-Stop:      0 1 6
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Short-Description: td-agent's init script
# Description:       td-agent is a data collector
### END INIT INFO

# Source function library.
. /etc/init.d/functions

name="td-agent-paid-web-forwarder"
prog=$name
hostname=`hostname -s`
if [[ $hostname =~ ^pd[0-9]{2}$ ]]; then
    mode=production
elif [[ $hostname =~ ^stg\-pd[0-9]{2}$ ]]; then
    mode=staging
else
    mode=test
fi

fluentd=/usr/lib/fluent/ruby/bin/fluentd
if [ -f "/usr/lib64/fluent/ruby/bin/fluentd" ]; then
    fluentd=/usr/lib64/fluent/ruby/bin/fluentd
fi

if [ -f /etc/sysconfig/$prog ]; then
    . /etc/sysconfig/$prog
fi

RUN_USER=td-agent
RUN_GROUP=td-agent
PIDFILE=/var/run/td-agent/$prog.pid
CONF_FILE=/etc/td-agent/$prog-$mode.conf
LOG_FILE=/var/log/td-agent/$prog.log
FLUENTD_ARGS="--group $RUN_GROUP -d $PIDFILE -c $CONF_FILE -o $LOG_FILE -q"

if [ -n "${PIDFILE}" ]; then
    mkdir -p $(dirname ${PIDFILE})
    chown -R $RUN_USER:$RUN_GROUP $(dirname ${PIDFILE})
fi

# use jemalloc to avoid fragmentation
if [ -f "/usr/lib/fluent/jemalloc/lib/libjemalloc.so" ]; then
    export LD_PRELOAD=/usr/lib/fluent/jemalloc/lib/libjemalloc.so
fi
if [ -f "/usr/lib64/fluent/jemalloc/lib/libjemalloc.so" ]; then
    export LD_PRELOAD=/usr/lib64/fluent/jemalloc/lib/libjemalloc.so
fi

RETVAL=0

start() {
    echo -n "Starting $name[$mode]: "
    daemon --pidfile=$PIDFILE --user=$RUN_USER $fluentd "$FLUENTD_ARGS"
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
    return $RETVAL
}

stop() {
    echo -n "Shutting down $name[$mode]: "
    if [ -e "${PIDFILE}" ]; then
        killproc -p ${PIDFILE} || killproc $prog
    else
        killproc $prog
    fi
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && rm -f $PIDFILE && rm -f /var/lock/subsys/$prog
    return $RETVAL
}

restart() {
    stop
    start
}

reload() {
    echo -n "Reloading $name[$mode]: "
    killproc -p $PIDFILE $prog -HUP
    echo
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    reload)
        reload
        ;;
    condrestart)
        [ -f /var/lock/subsys/$prog ] && restart || :
        ;;
    status)
        status -p $PIDFILE $prog
        ;;
    *)
        echo "Usage: $prog {start|stop|reload|restart|condrestart|status}"
        exit 1
        ;;
esac
exit $?


■ログ転送先の起動スクリプト
/etc/rc.d/init.d/td-agent-paid-web-aggregator

サービスへの登録はroot権限を持っているユーザーで下記を実行します。
# chkconfig --add td-agent-paid-web-aggregator
# chkconfig --level 345 td-agent-paid-web-aggregator on

■■ログ転送先の起動スクリプトの内容
   forwarder を aggregator へ置換しただけです。
#!/bin/bash
#
# /etc/rc.d/init.d/td-agent-paid-web-aggregator
#
# chkconfig: - 80 20
# description: td-agent
# processname: td-agent-paid-web-aggregator
# pidfile: /var/run/td-agent/td-agent-paid-web-aggregator.pid
#
### BEGIN INIT INFO
# Provides:          td-agent
# Default-Stop:      0 1 6
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Short-Description: td-agent's init script
# Description:       td-agent is a data collector
### END INIT INFO

# Source function library.
. /etc/init.d/functions

name="td-agent-paid-web-aggregator"
prog=$name
hostname=`hostname -s`
if [[ $hostname =~ ^pd[0-9]{2}$ ]]; then
    mode=production
elif [[ $hostname =~ ^stg\-pd[0-9]{2}$ ]]; then
    mode=staging
else
    mode=test
fi

fluentd=/usr/lib/fluent/ruby/bin/fluentd
if [ -f "/usr/lib64/fluent/ruby/bin/fluentd" ]; then
    fluentd=/usr/lib64/fluent/ruby/bin/fluentd
fi

if [ -f /etc/sysconfig/$prog ]; then
    . /etc/sysconfig/$prog
fi

RUN_USER=td-agent
RUN_GROUP=td-agent
PIDFILE=/var/run/td-agent/$prog.pid
CONF_FILE=/etc/td-agent/$prog-$mode.conf
LOG_FILE=/var/log/td-agent/$prog.log
FLUENTD_ARGS="--group $RUN_GROUP -d $PIDFILE -c $CONF_FILE -o $LOG_FILE -q"

if [ -n "${PIDFILE}" ]; then
    mkdir -p $(dirname ${PIDFILE})
    chown -R $RUN_USER:$RUN_GROUP $(dirname ${PIDFILE})
fi

# use jemalloc to avoid fragmentation
if [ -f "/usr/lib/fluent/jemalloc/lib/libjemalloc.so" ]; then
    export LD_PRELOAD=/usr/lib/fluent/jemalloc/lib/libjemalloc.so
fi
if [ -f "/usr/lib64/fluent/jemalloc/lib/libjemalloc.so" ]; then
    export LD_PRELOAD=/usr/lib64/fluent/jemalloc/lib/libjemalloc.so
fi

RETVAL=0

start() {
    echo -n "Starting $name[$mode]: "
    daemon --pidfile=$PIDFILE --user=$RUN_USER $fluentd "$FLUENTD_ARGS"
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
    return $RETVAL
}

stop() {
    echo -n "Shutting down $name[$mode]: "
    if [ -e "${PIDFILE}" ]; then
        killproc -p ${PIDFILE} || killproc $prog
    else
        killproc $prog
    fi
    RETVAL=$?
    echo
    [ $RETVAL -eq 0 ] && rm -f $PIDFILE && rm -f /var/lock/subsys/$prog
    return $RETVAL
}

restart() {
    stop
    start
}

reload() {
    echo -n "Reloading $name[$mode]: "
    killproc -p $PIDFILE $prog -HUP
    echo
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        restart
        ;;
    reload)
        reload
        ;;
    condrestart)
        [ -f /var/lock/subsys/$prog ] && restart || :
        ;;
    status)
        status -p $PIDFILE $prog
        ;;
    *)
        echo "Usage: $prog {start|stop|reload|restart|condrestart|status}"
        exit 1
        ;;
esac
exit $?

設定ファイル

■ログ転送(送信)用の設定ファイル
/etc/td-agent/td-agent-paid-web-forwarder-production.conf
/etc/td-agent/td-agent-paid-web-forwarder-staging.conf
/etc/td-agent/td-agent-paid-web-forwarder-test.conf
ログ転送元の起動スクリプト /etc/rc.d/init.d/td-agent-paid-web-forwarder から
実行環境毎に、上記の3ファイルのうち1つが読み込まれます。

■■ ログ転送(送信)用の設定ファイルの内容
include config.d/paid/input/*.conf
include config.d/paid/forward/production/forward.conf
include td-agent-common.conf
上記は /etc/td-agent/td-agent-paid-web-forwarder-production.conf の内容ですが
staging, test環境用はproductionの部分を置換しただけです。

これは include ディレクティブで外部の設定ファイルを読み込むだけの設定です。

■ ログ転送(受信)用の設定ファイル
/etc/td-agent/td-agent-paid-web-aggregator-production.conf
/etc/td-agent/td-agent-paid-web-aggregator-staging.conf
/etc/td-agent/td-agent-paid-web-aggregator-test.conf
ログ転送先の起動スクリプト /etc/rc.d/init.d/td-agent-paid-web-aggregator から
実行環境毎に、 上記の3ファイルのうち1つが読み込まれます。

■■ ログ転送(受信)用の設定ファイルの内容
include config.d/paid/forward/production/aggregate.conf
include config.d/paid/output/*.conf
include td-agent-common.conf
上記は /etc/td-agent/td-agent-paid-web-aggregator-production.conf の内容ですが
これもstaging, test環境用はproductionの部分を置換しただけです。

同じく include ディレクティブで外部の設定ファイルを読み込むだけの設定です。

■共通の設定ファイル
/etc/td-agent/td-agent-common.conf
全体で共通して読み込む設定ファイルです。commonというネーミングにマサカリが飛んできそうですね。

■■共通の設定ファイルの内容
<match null>
  type null
</match>

<match fluent.**>
  type file
  path /var/log/td-agent/fluent
</match>

<match **>
  type file
  path /var/log/td-agent/unmatched
  compress gz
</match>

上から順に解説します。

<match null>
  type null
</match>
上記は、out_nullプラグインを使い、"null"というタグを持つログを破棄するための設定です。
意図的に破棄したいログに対して使おうとしていましたが、導入時は使いませんでした。
/dev/null のようなものですね。

<match fluent.**>
  type file
  path /var/log/td-agent/fluent
</match>
上記は、out_fileプラグインを使い、fluentd 内部のログを
/var/log/td-agent/fluent.20131118_0.log
のような名前のファイルに出力するための設定です。

<match **>
  type file
  path /var/log/td-agent/unmatched
  compress gz
</match>
上記は、同じくout_fileプラグインを使い、いずれにもマッチしなかったタグを持つログを
/var/log/td-agent/unmatched.20131118_0.log
のような名前のファイルに出力するための設定です。
どれだけ出力されるのかが不明だったため、ローテート時にgzip圧縮し、拡張子に.gzが追加される設定を有効にしています。

※失敗談: 実は7/1の導入時は(実は現在も・・・)全体的に
 path /var/log/td-agent/fluent.log
 path /var/log/td-agent/unmatched.log
 のように、path の末尾に.logを書いてしまっていたために、作成されるログファイル名が
 fluent.log.20130701_0.log
 のように.logが重なってしまっていました・・・

 下記のページに path の仕様がちゃんと書かれています。真面目に読まなきゃダメですね・・・
 http://docs.fluentd.org/articles/out_file
 > The Path of the file. The actual path is path + time + ”.log”.


Paidのログファイル
弊社が運営するサービスの多くはJavaで開発されています。
フレームワークはSeasar2, S2Dao, Hibernate, S2Struts, Tilesといったところで、
Apache Tomcat上で動作しています。
(最近はPlay Framework、Ruby on Railsを使った開発もあります)

このため、今回はアプリケーション内で出力しているアクセスログファイルを対象とします。
以下、「Paidのログファイル」とは、このアクセスログファイルのことを指します。

アクセスログファイルは下記のようなフォーマットになっています。
(実際にはユーザーIDや、その他の情報も含まれていますが、ここでは省略しています)
2013-07-01 16:35:02,665 HEAD http://paid.jp/v/contents/index.jsp 7
2013-07-01 16:36:01,675 HEAD http://paid.jp/v/contents/index.jsp 6

Paidのログファイルを読み込みための設定ファイル
/etc/td-agent/config.d/paid/input/java-pd.conf

■■Paidのログファイルを読み込みための設定ファイルの内容
   ※path, formatは改変しています。
# input ( -> raw.paid.tomcat-pd.tomcat.access)
<source>
  type tail
  path /var/log/tomcat6-pd/access.log
  pos_file /var/log/td-agent/paid_tomcat-pd_tomcat_access.pos
  tag raw.paid.tomcat-pd.tomcat.access
  format /^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) (?<method>[A-Z]+) (?<url>.+) (?<response_millis>\d+)$/
  time_format %Y-%m-%d %H:%M:%S,%L
</source>

# filter (raw.paid.tomcat-pd.tomcat.access -> forward.paid.tomcat-pd.tomcat.access.${hostname})
<match raw.paid.tomcat-pd.tomcat.access>
  type rewrite_tag_filter
  remove_tag_prefix raw
  hostname_command hostname -s

  rewriterule1 method .* forward.${tag}.${hostname}
</match>

上から順に解説します。

# input ( -> raw.paid.tomcat-pd.tomcat.access)
<source>
  type tail
  path /var/log/tomcat6-pd/access.log
  pos_file /var/log/td-agent/paid_tomcat-pd_tomcat_access.pos
  tag raw.paid.tomcat-pd.tomcat.access
  format /^(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3}) (?<method>[A-Z]+) (?<url>.+) (?<response_millis>\d+)$/
  time_format %Y-%m-%d %H:%M:%S,%L
</source>
上記は、in_tailプラグインを使い、tail -F コマンドのように
ログファイルに追記される度に書き込まれたログ(1行単位)を読み込むための設定です。
ログファイルがローテートされても、もちろん追従してくれます。

# filter (raw.paid.tomcat-pd.tomcat.access -> forward.paid.tomcat-pd.tomcat.access.${hostname})
<match raw.paid.tomcat-pd.tomcat.access>
  type rewrite_tag_filter
  remove_tag_prefix raw
  hostname_command hostname -s

  rewriterule1 method .* forward.${tag}.${hostname}
</match>
上記は、fluent-plugin-rewrite-tag-filterプラグインを使い、最初にタグの先頭の raw を除去し、
次にタグの先頭に forward を、タグの末尾に ${hostname} を付加しています。
${hostname} は hostname_command で指定した hostname -s コマンドの実行結果に置き換わります。
この設定はログの転送後に、そのログがどのサーバーから転送されてきたのかを残すための準備です。

これは /etc/td-agent/config.d/paid/input/java-pd.conf と大して変わらないので省略します。
/etc/td-agent/config.d/paid/input/java-pd-web-service.conf

Paidのログファイルを転送(送信)するための設定ファイル
/etc/td-agent/config.d/paid/forward/{production,staging,test}/forward.conf

■■Paidのログファイルを転送(送信)するための設定ファイルの内容
   ※hostは改変しています。
# filter (forward.paid.*.*.access.${hostname} -> production.forward.paid.*.*.access.${hostname})
<match forward.paid.*.*.access.*>
  type route

  <route forward.paid.*.*.access.{pd01,pd02,pd03,pd04}>
    add_tag_prefix production
  </route>
</match>

# forward-output (production.forward.paid.*.*.access.${hostname} -> )
<match production.forward.paid.*.*.access.*>
  type forward
  heartbeat_type tcp

  buffer_type file
  buffer_path /var/log/td-agent/forward-paid.buf

  <server>
    name pd04
    host 192.168.2.4
  </server>
  #<server>
  #  name pd03
  #  host 192.168.2.3
  #  standby
  #</server>

  <secondary>
    type file
    path /var/log/td-agent/forward-paid.err
    compress gz
  </secondary>
</match>
上記は /etc/td-agent/config.d/paid/forward/production/forward.conf の内容ですが
staging, test環境用はproductionの部分、route内のホスト名、hostの部分を置換しただけです。

上から順に解説します。

# filter (forward.paid.*.*.access.${hostname} -> production.forward.paid.*.*.access.${hostname})
<match forward.paid.*.*.access.*>
  type route

  <route forward.paid.*.*.access.{pd01,pd02,pd03,pd04}>
    add_tag_prefix production
  </route>
</match>
上記は、fluent-plugin-routeプラグインを使い、転送前にホスト名の簡易チェックを行った後に、
チェックがOKであればタグの先頭に production を付加しています。
チェックがNGであればunmatchedのログファイルに出力されます。

※転送時の送信側と受信側で、タグに付加された実行環境毎に異なる文字列をチェックすることで
 誤ってテスト環境から本番環境の fluentd にログを転送するリスクを減らそうとする目論見です。
 本来は iptables などで接続制限を加えるべきなのでしょうが、現在はそこまでしていません。

# forward-output (production.forward.paid.*.*.access.${hostname} -> )
<match production.forward.paid.*.*.access.*>
  type forward
  heartbeat_type tcp

  buffer_type file
  buffer_path /var/log/td-agent/forward-paid.buf

  <server>
    name pd04
    host 192.168.2.4
  </server>
  #<server>
  #  name pd03
  #  host 192.168.2.3
  #  standby
  #</server>

  <secondary>
    type file
    path /var/log/td-agent/forward-paid.err
    compress gz
  </secondary>
</match>
上記は、out_forwardプラグインを使い、ログを転送(送信)するための設定です。
パフォーマンスはかなり落ちますが、転送(送信)時にファイルバッファを使いログ消失を防止したり、
転送(送信)エラーとなったログをファイルへ書き込んで残したりしています。
コメントアウトされているログ転送先のスタンバイは、まだ稼働していません・・・

Paidのログファイルを転送(受信)するための設定ファイル
/etc/td-agent/config.d/paid/forward/{production,staging,test}/aggregate.conf

■■Paidのログファイルを転送(受信)するための設定ファイルの内容
# forward-input ( -> production.forward.paid.*.*.access.${hostname})
<source>
  type forward
</source>

# filter (production.forward.paid.*.*.access.${hostname} -> paid.*.*.access.${hostname})
<match production.forward.paid.*.*.access.*>
  type route

  <route production.forward.paid.*.*.access.*>
    remove_tag_prefix production.forward
  </route>
</match>
上記は /etc/td-agent/config.d/paid/forward/production/aggregate.conf の内容ですが
staging, test環境用はproductionの部分を置換しただけです。

上から順に解説します。

# forward-input ( -> production.forward.paid.*.*.access.${hostname})
<source>
  type forward
</source>
上記は、in_forwardプラグインを使い、ログを転送(受信)するための設定です。

# filter (production.forward.paid.*.*.access.${hostname} -> paid.*.*.access.${hostname})
<match production.forward.paid.*.*.access.*>
  type route

  <route production.forward.paid.*.*.access.*>
    remove_tag_prefix production.forward
  </route>
</match>
上記は、転送されてきたログのタグに、実行環境が同一であることを示す文字列が含まれているかチェックしています。
チェックがOKであれば転送(送信)前にタグの先頭に付加された production.forward を除去します。
チェックがNGであればunmatchedのログファイルに出力されます。

■転送されてきたPaidのログファイルを集約して書き込むための設定ファイル
/etc/td-agent/config.d/paid/output/java-pd.conf

■■転送されてきたPaidのログファイルを集約して書き込むための設定ファイルの内容
# output (paid.tomcat-pd.tomcat.access.${hostname} -> )
<match paid.tomcat-pd.tomcat.access.*>
  type file
  path /var/log/td-agent/aggregate_paid_tomcat-pd_tomcat_access
  compress gz
</match>
上記は、out_fileプラグインを使い、ログをファイルへ書き込む設定です。
だいたい上の方で説明済みですね。

ファイルへは、タイムスタンプ、タグ、JSONの順で、タブ文字区切りで書き込まれます。
2013-07-01T16:35:02+09:00    paid.tomcat-pd.tomcat.access.pd01    {"method":"HEAD","url":"http://paid.jp/v/contents/index.jsp","response_millis":"7"}
2013-07-01T16:36:01+09:00    paid.tomcat-pd.tomcat.access.pd02    {"method":"HEAD","url":"http://paid.jp/v/contents/index.jsp","response_millis":"6"}

これも /etc/td-agent/config.d/paid/output/java-pd.conf と大して変わらないので省略します。
/etc/td-agent/config.d/paid/output/java-pd-web-service.conf

まとめ

7/1の導入から4ヶ月以上経ちましたが、fluentd(td-agent) はノートラブルで動き続けています。
現在はPaidだけですが、次はSUPER DELIVERYへの導入を考えています。

格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(3)

インフラエンジニアのETOです。  

弊社は間もなく本社を移転するため、準備に追われていて忙しい日々です。
なにかと人手不足なので、一緒に働いてくれる方を募集中です!


前回の「格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(2)」に引き続き、今回はいよいよ「仮想マシンホストサーバ」を構築し、仮想マシンを作ってベンチマークをとりたいと思います。
3回目になりますこのお題も、今回で最後です。張り切っていきましょう!

・今回使うもの
 ・仮想マシンホストサーバ
  ハード: HP ML110G7 
      メモリ 16GB
      USBメモリ起動 8GB
      HDD ナシ ZEROスピンドル!
 
 OS: ESXi5.0 Update 1 
      "VMware-VMvisor-Installer-5.0.0.update01-623860.x86_64.iso"を焼いた起動メディア一枚。
       ※ESXi5.0用のライセンスキーもisoダウンロードの際に控えておいてください。


・構成図
今回は左側の「vmhost01」をセットアップします。
kousei




・前準備
ML110G7の内部USBポートに起動用のUSBメモリをさします。

前面スロットからHDDを抜きます。
抜いたHDDの転用先がないという方はそのままでも結構です。

ネットワークを結線します。
前回作ったNFSサーバも結線して起動しておいてください。 

BIOSの設定を調整します。
ML110G7とESXi5.0は標準設定のままだと、紫色(?)のエラー画面が出て起動しません。
これを回避するにはBIOSの以下の項目を調整する必要があります。
HP Power Regulator: OS Control Mode
HP Power Profile: Custom
Advanced Power Management Options Minimum Processor Idle Power State: C6 States
参考:vSphere 5.0 on HP ML110 G7 

↓このあたりです
ML110G7_BIOS_2

 
 

・セットアップ手順 
ESXi5.0 Update 1 をインストールします。
BIOSの設定が正しく行われていれば詰まるような箇所はないと思います。

注意が必要なところのみ抜粋します。
Select a Disk to Installation or Upgrade
※インストール先にUSBメモリを選択。
※HDDを搭載したままの人はインストール先に注意。

Please select a keyboard layout
※Japaneseを選択。
あとは画面の指示に従ってインストールしてください。


インストールが終了して、再起動後にやるべきことは、
  1. ESXiサーバの管理用ip設定
  2. VMware vShpere Clientのインストール
  3. ESXiサーバの構成設定(ライセンス、NTP、ネットワーク、ストレージ)
になります。


1. ESXiサーバの管理用ip設定
再起動して黄色いESXiの画面になったらF2を押してログインし、
[Configure Management Network]→[IP Configuration]
を選択。
構成図の通りにipを設定していきます。必要な方はご自分の環境に合わせて変更してください。
IP Address [192.168.0.1]
Subnet Mask [255.255.255.0] 
Default Gateway [192.168.0.254]
 0U1_01

SSHでESXiに直接ログインしたい方は
[Troubleshooting Options]→[Enable SSH]
もやっておきましょう。色々と便利です。


2. VMware vShpere Clientのインストール
設定したipにブラウザでアクセスするとクライアントをダウンロードできるページが表示されます。便利ですね!
ダウンロードしてインストールしてください。

ちなみに既に旧バージョンのクライアントがインストールしてある場合は、クライアントでアクセスするとバージョンアップファイルが自動的にダウンロードされます。
 

3. ESXiサーバの構成設定(ライセンス、NTP、ネットワーク、ストレージ)
クライアントでESXiサーバにアクセスして構成設定をしていきます。
 0U1_02

・ライセンス設定
isoダウンロードの際に控えておいたライセンスキーを入力してください。

・ NTP設定
適当なNTPサーバを設定してください。nictmfeedあたりでよいでしょう。
設定後に、起動ポリシーを[ホストに連動して開始および停止]にしてサービスコマンドから[開始]しておいてください。
仮想マシンは時計がずれやすいので、ホストサーバ側の時計を正確に保っておくのは意外と重要なことです。

・ネットワーク設定
管理用に登録したip側のネットワークは既に構成されていると思いますので、NFS用のネットワークを追加します。
ネットワークの追加画面から[接続タイプ]で[VMkernel]を選択してNFSネットワーク用のip(10.255.255.1)を設定します。必要な方はご自分の環境に合わせて変更してください。

↓成功すればこのような感じになります。
0U1_03
・ストレージ設定
ストレージの追加画面から[ネットワークファイルシステム]を選び、NFSサーバの情報を入れていきます。ご自分の環境に合わせた方は適宜読み替えてください。 
サーバ: 10.255.255.100
フォルダ: /datapool/nfs01
データストア名: nfs01 
ネットワークの設定と、前回作ったNFSサーバの設定がうまくいっていればここで詰まることはないはずです。



これで「仮想マシンホストサーバ」の作成は完了です!



仮想マシンでベンチマーク
早速Linux(CentOS5)の仮想マシンを1台作ってベンチマークを取ってみましょう。
[ファイル]→[新規]→[仮想マシン]から仮想マシン作成を行います。

各パラメータは以下のとおりです。
名前 linuxtest
データストア nfs01
ゲスト OS CentOS 4/5/6(64ビット)
CPU 2
メモリ 4096MB
NIC 1
NIC1ネットワーク: VM Network
NIC 1タイプ E1000
ディスクプロビジョニング: シン プロビジョニング
仮想ディスクサイズ: 30GB
 
 仮想マシンが追加されたら、
[インベントリ]→[仮想マシン]→[コンソールを開く]
で仮想マシンのコンソール画面を開き、今回はCentOS5.8をインストールします。

↓コンソール画面からインストール用のisoイメージを直接マウントすることができます。
0U1_04

 
CentOSのインストール部分は割愛させていただきます。 


さて、無事にインストールができたでしょうか。
次はbonnie++でベンチマークタイムです。ドキドキです。 
[root@centos5~]# bonnie++ -d / -n 128  -u 0
~中略~
Version  1.03       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
centos5                4G 42153  71 96249  17 39526   8 53224  85 101409   7 14859  18
                    ------Sequential Create------ --------Random Create--------
                    -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                128 65598  70 +++++ +++ 126228 100 94847  99 +++++ +++ 120353  99
NFS越しですが、シーケンシャルでread/write共に100MB/s近く出ています。
今回は1000BASE-Tでネットワークを組んでいますので、理論値の限界は125MB/s。
そう考えるとなかなかいい数字が出ているのがお分かりいただけると思います。



おわりに
今回はひとまず基本をおさえていただきたいということで、あえて安い機材構成を使いましたが、
UPSや冗長化電源、RAIDカード、LANカードを追加していただくことで、さらに可用性の高いシステムを
手軽に構築することが可能だと、実感いただけたかと思います。

全3回になりましたが、このお題も今回で終了です。長々とお付き合いいただきありがとうございました!

格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(2)

インフラエンジニアのETOです。  

暑い日が続きますが皆様いかがお過ごしでしょうか。
最近、週に2回ほど熱いお風呂につかるようにしたのですが、寝付きがとても良くなりました。
肩こりも取れますので、オフィスの冷房で肩こりが酷い方にもお勧めです!


さて、早速ですが前回の「格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(1)」の続きです。今回は実際の構築に入っていきましょう。
まずは「NFS外部ストレージサーバ」からセットアップしていきます。

・今回使うもの
  ・NFS外部ストレージサーバ
 ハード: HP ML110G7
     メモリ 8GB
     USBメモリ 8GB
     HDD 2TB*4
 
 OS: OpenIndiana 151a (for servers)
      "oi-dev-151a-text-x86.iso"を焼いた起動メディア一枚。
※今回はZFSを使うのでOpenSolaris系OSの正統後継である「OpenIndiana」をインストールしたいと思います。最近ではFreeBSDやLinuxでもZFSを使えますが、やはり安定性を考えると実装元であるSolaris系OSで使うべきだと思います。

・構成図
今回は右側の「fsrv01」をセットアップします。
kousei



・前準備
ML110G7の内部USBポートに起動用のUSBメモリをさします。
この機種では内部SDカードスロットも付いたので、そちらでチャレンジしてみても面白いかもしれません。

前面の4つのスロットにHDDを搭載します。
今回使うノンホットプラグモデルのML110G7に4つ並んだSATAスロットのうち、左側の2つは6.0Gbpsですが右側の2つは3.0Gbpsです。SSDを搭載する場合はボトルネックにならないよう左側に搭載しましょう。
※余談ですが、2.5インチのSSDをこのスロットにきれいに収めるには2.5→3.5変換ケースのSilverStone「SST-SDP09」が大変おすすめです。余計なチップは搭載されておらず、延長コネクタのような構造のため相性問題など出ません。

BIOSの設定を調整します。
起動時に、F9でBIOS設定画面へ。
 [Advanced Options]→[SATA Controller Options]→[Embedded SATA Configuration]
  "Enable SATA AHCI Support"へ変更
 [Advanced Options]→[SATA Controller Options]→[Drive Write Cache]
  "Enable"へ変更 (信頼性優先ならDisableで)
↓このあたりです
ML110G7_BIOS





・セットアップ手順
OpenIndiana 151a (for servers) をインストールしていきます。
サーバ用として配布されている「oi-dev-151a-text-x86.iso」でCDかDVDを作成して起動しましょう。

以降注意が必要なところのみ抜粋します。 
TO select the Keyboard layout, enter a number [default 47]: 23
※23番日本語キーボードを選択。

TO select the language you wish to use, enter a number [default is 7]: 7
※ここはそのまま7で。テキスト版なので日本語は出ません。

Disks
※内部に挿したUSBを選択。

Fdisk Partitions: ~
※「Use the whole disk」を選択。

Network
※[Computer Name:]に「fsrv01」を入力。
※カーソルを下段の「None」にあわせる。
あとは画面の指示に従ってインストールしてください。


インストール終了後、再起動後にやるべきことは、
  1. rpool(システム領域)のatimeをoffにする
  2. ipとネットワークの設定
  3. ストレージプールの作成とNFS設定
  4. swap領域をrpoolからdatapoolに移す 
になります。
どんどんいきましょう。


1. rpool(システム領域)のatimeをoffにする
まずシステム領域のatime(access time)を無効化しましょう。
atimeの無効化には賛否両論ありますが、利用目的がNFSオンリーであることとUSBメモリだと細かいディスクI/Oが気になるので、思い切ってoffにします。

root@fsrv01:~# zfs set atime=off rpool


2. ipとネットワークの設定
構成図の通りに設定していきます。必要な方はご自分の環境に合わせて変更してください。
今回は必要最低限の設定しかしませんので、詳しく勉強したい方はORACLE社のドキュメント「ネットワークスタックの概要」をご覧ください。
root@fsrv01:~# echo '192.168.0.254' > /etc/defaultrouter
root@fsrv01:~# ipadm create-addr -T static -a 192.168.0.100/24 e1000g0/v4
root@fsrv01:~# ipadm create-addr -T static -a 10.255.255.100/24 e1000g1/v4  
上から、デフォルトゲートウェイの設定、表ネットワークのip設定、 NFSネットワークのip設定、になります。
ここで設定反映のため一度再起動してください。


3. ストレージプールの作成とNFS設定
zpoolコマンドを使ってzfsストレージプールを作成していきます。
まず、formatコマンドを使ってHDDの認識状況を確認しましょう。
root@fsrv01:~# format
Searching for disks...done


AVAILABLE DISK SELECTIONS:
       0. c4t0d0
          /pci@0,0/pci103c,330d@1f,2/disk@0,0
       1. c4t1d0
          /pci@0,0/pci103c,330d@1f,2/disk@1,0
       2. c4t2d0
          /pci@0,0/pci103c,330d@1f,2/disk@2,0
       3. c4t3d0
          /pci@0,0/pci103c,330d@1f,2/disk@3,0
Specify disk (enter its number): ^D

しっかり認識されていますね。CTRL+Dで抜けて、続けて以下のコマンドを実行します。

root@fsrv01:~# zpool create datapool mirror c4t0d0 c4t1d0 mirror c4t2d0 c4t3d0

これで、「datapool」という名前のストレージプールが、raid10で作成されます。なんとお手軽なのでしょう。
zpool statusコマンドで確認してみましょう。
root@fsrv01:~# zpool status datapool
  pool: datapool
 state: ONLINE
  scan: none requested
config:

        NAME        STATE     READ WRITE CKSUM
        datapool   ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            c4t0d0  ONLINE       0     0     0
            c4t1d0  ONLINE       0     0     0
          mirror-1  ONLINE       0     0     0
            c4t2d0  ONLINE       0     0     0
            c4t3d0  ONLINE       0     0     0
mirror-0とmirror-1がそれぞれRAID1、それをストライプしてdatapoolが構成されているのがわかります。
また作成時に自動的に/datapoolとしてマウントされていますので、今回はこのまま使います。 


続けてNFS用のデータセットの作成と、NFSエクスポートを一気にやってしまいます。

root@fsrv01:~# zfs create datapool/nfs01
root@fsrv01:~# zfs set sharenfs=rw,root=@10.255.255.0/24 datapool/nfs01

たった2行です。上がデータセットの作成、下がNFSのエクスポートの設定になります。
エクスポート設定について補足すると、"root="はLinuxでいうところの"no_root_squash"、"@10.255.255.0/24"はこのネットワークに対して許可を出すという意味合いです。


4. swap領域をrpoolからdatapoolに移す
USBメモリにインストールしたので、swap領域もUSBメモリ上の「rpool/swap」にできてしまっています。
立派なストレージプール「datapool」ができましたのでこちらに移してしまいましょう。
root@fsrv01:~# zfs create -V 8G -b 4k datapool/swap
root@fsrv01:~# swap -a /dev/zvol/dsk/datapool/swap

root@fsrv01:~# swap -lh
swapfile             dev    swaplo   blocks     free
/dev/zvol/dsk/rpool/swap 179,2         8  2.0G  2.0G
/dev/zvol/dsk/datapool/swap 179,3         8  8.0G  8.0G    ←追加された方
rpoolのswap領域をswapから外して消します。
root@fsrv01:~# swap -d /dev/zvol/dsk/rpool/swap
root@fsrv01:~# zfs destroy rpool/swap

root@fsrv01:~# swap -lh
swapfile             dev    swaplo   blocks     free
/dev/zvol/dsk/datapool/swap 179,3         8  8.0G  8.0G


おまけ
せっかくなのでbonnie++でベンチ取ってみました。
root@fsrv01:~# bonnie++ -d /datapool/ -n 128  -u 0
~中略~
Version 1.03c       ------Sequential Output------ --Sequential Input- --Random-
                    -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine        Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP  /sec %CP
fsrv01           8G 92723  98 197266  21 115933  20 100931  99 327860  20  1439   3
                    ------Sequential Create------ --------Random Create--------
                    -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
              files  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP  /sec %CP
                128 20072  93 182108  99 26543  96 22806  98 206876  84 24443  97
シーケンシャルでwrite 200MB/s, read 300MB/s程度出ているので、NFSで利用することを考えると十分な性能ですね。


どうでしょうか、非常に簡単にNFSサーバが構築できたかと思います。
NFS以外にもSMB共有の設定なども簡単にできますので、興味のある方はORACLE社のドキュメント「ZFSファイルシステム」を御覧ください。


さて、次回はESXiのストレージとしてNFSを登録、その上に仮想マシンをつくってみます。
「格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(3)」へ続きます。
言語を検出 » Japanese

格安サーバで作る ESXi+NFS(ZFS) の仮想マシン環境(1)

先日、早めの夏休みで青島(チンタオ)にビールを飲みに行って来ましたインフラエンジニアのETOです。
弊社は旅行好きの人が多いため、旅行休暇を取りやすいので助かっています。
旅行好きな方は是非弊社で一緒に働きましょう。ご検討ください。


さて、長期間休みを取る際にいつも気になるのは、自分がいない間のサーバ故障の発生です。
当然ながら冗長化ができている公開系に比べると、どうしても対策が後回しになりがちな開発系や、
ちょっとした社内サーバがこういう時に限って壊れたりするものです。
 
「あー壊れちゃいましたね」では済まないインフラエンジニアとしてはいつも余裕を持ったリソースを確保しておきたいものですが、なかなか(主にコスト絡みで)そうはいきません。
 
そこで同じような悩みを抱える諸兄におすすめしたいのが今回のお題、
「格安サーバで作る ESXi+NFS の仮想マシン環境」です。


・目指すところ
安く手軽に"実用的"な仮想サーバ環境を手に入れるのが目的です。
実サーバのバックアップや、故障時の緊急避難先などに大活躍!当然本運用も可能です。
ZFSベースのNFS外部ストレージも自作することでデータの保全性も同時に確保してしまいましょう。

・用意するもの
各サーバ機として、HP社のML110G7を2台使います。
格安サーバとして2万円以下で手に入るコストパフォーマンス抜群のサーバ機です。
これにメモリとHDDを追加します。余っているものがあればそれを流用しても構わないと思います。

今回の具体的なハード&ソフトウェア構成は以下になります。
 ・仮想マシンホストサーバ
  OS:ESXi5.0U1
  ハード: HP ML110G7 
      メモリ 16GB
      USBメモリ起動 8GB
      HDD ナシ ZEROスピンドル!

 ・NFS外部ストレージサーバ
  OS:openindiana 151a
  ハード: HP ML110G7
      メモリ 8GB
      USBメモリ起動 8GB
      HDD 2TB*4

詳細は伏せますが、全部あわせても10万円かからない金額で調達しました。
現在はもっと安いかもしれません。


・構成図 
このような構成で構築します。
kousei





突然ですがQ&A。

Q:なぜKVMではなくESXiなの?
A:無料で使えるGUIの管理ツールが揃っていて楽だからです!
 
これだけだと色々と反論を受けそうですので補足。
やはりVMware社の企業として統一されたポリシーで作られている以下のツール群の使い勝手が良いため、KVMなどと比べるとアドバンテージがあると思っています。
  • VMware vSphere Client(管理コンソール)
  • VMware vCenter Converter Standalone(P2Vツール)


Q:なぜローカルディスクにしないの?
A:ESXiで"実用になる"RAIDカードが高いからです。

ESXiではソフトウェアRAIDや廉価なオンボード系のRAIDが使えません。 また、RAIDカードは原則的にデータ保護のためにHDDのキャッシュを無効化するため、 キャッシュメモリ未搭載の安いRAIDカードを使うととても遅くて実用に耐えません。
※この点においてはLinuxで使えるRAID構成をそのままストレージとして使えるKVMにアドバンテージがあるのですがそれはまた別の話。

いくらお手軽環境 とはいえ「HDDが壊れたらデータが飛びました」ではお話にならないのは言うまでもありません。
しかしご安心を。ESXiではNFSやiSCSIを利用することで、ネットワーク越しの外部ストレージに仮想マシンイメージを置くことが可能になっていますので、今回はZFSベースのNFS外部ストレージを作り、最低限+αくらいのデータの保全性を確保したいと思います。 


Q:ZFSってなに?
A:主にSolarisやFreeBSDで使える次世代ファイルシステムです。

旧Sun社(Oracle社に買収されました)により開発された次世代ファイルシステムです。様々な仕組みで信頼性と性能を向上させているため、高価なストレージシステムを買わなくても耐障害性の高い高速なストレージ環境を手に入れることができます。
今回はZFSのソフトウェアRAIDでNFS外部ストレージを構築します。ZFSについて詳しく知りたい方はOracle社のドキュメントをご覧ください。 


Q:なぜiSCSIじゃなくてNFSなの?
A:取り回しが楽だからです。

「今時NFSはないだろう」とか「ESXiなら普通はiSCSIでしょう」とかいう声が聞こえてきますが、今回は性能を求めるわけではないので多少のオーバーヘッドは無視してNFSを選択します。
皆さんご存知の通り、NFSは取り回しが楽ちんで素敵です。偉い人にはそれがわからんのです。


諸々ご納得いただけたでしょうか。
さて、次回から実際の構築に入って行きたいと思います。
言語を検出 » Japanese

記事検索