Surgo

lazy programmer. (simple is better than complex !)

Nov 19, 2009

高可用性ロードバランサーを nginx + heartbeat で作る

ロードバランサーの可用性を高めるために、アクティブスタンバイ構成で、アクティブ系が落ちたらスタンバイ系に引き継げるようにする。

構築環境

  • サーバー機
    • NIC × 2 枚 (推奨 4 枚)
    • RAID: 1, (推奨 0 + 1)
    • 電源ボード × 2 (予算があれば)
    • 仮想化ソフトウェア: VMWare ESXi 4.0
  • 仮想化ソフトウェア (VMWare ESXi 4.0) の設定
    • NIC は 2 枚 1 組でフェイルオーバーするように設定
    • ネットワーク × 2 (NIC 2 枚構成の場合は VLANを作成)
      • VM Network: 既存 (デフォルト)
      • HA Network: 新規追加
  • ロードバランサー用ゲストOS (Ubuntu Server 9.10: 各サーバに1 台ずつ追加)
    • ディスク: 4G程度 (Ubuntu Server の最小ハードウェア要件は 1G)
    • コア数: 2
    • メモリ: 4G
    • ネットワーク × 2
      • VM Network に接続された NIC
      • HA Network に接続された NIC
ネットワーク アクティブ (lb01) スタンバイ (lb02)
eth0 (heartbeat 監視用) 192.168.0.2 192.168.0.3
eth1 (管理用) 172.16.0.2 172.16.0.3
サービス用 172.16.0.1 (実際にサービスを提供する IP)

インストールと設定

  1. パッケージ類のインストール (nginx と heartbeat)
    ロードバランサーとして利用する nginx と、クラスタリングするための heartbeat をインストールする
    sudo aptitude install nginx heartbeat
    
  2. nginx の自動起動をやめる
    sysv-rc-conf などを利用し、各ランレベルでの自動起動を停止しておく
    ※ sysv-rc-conf をインストールしていない場合は以下でインストールできる
    sudo sptitude install sysv-rc-conf
    
  3. hosts ファイルに各サーバを登録する
    sudo vi /etc/hosts
    
    192.168.0.2 lb01
    192.168.0.3 lb02
    
    ※ お互い ping 試験
  4. /etc/ha.d/ha.cf の作成
    テンプレートがあるので、作業用ディレクトリーに複製、及び編集
    監視対象を指定
    sudo cp /usr/share/doc/heartbeat/ha.cf.gz .
    sudo gzip -d ha.cf.gz
    sudo vi ha.cf
    
    コメントを外したり、記入したりなどする
    keepalive 2
    deadtime 30
    warntime 10
    initdead 120
    udpport 694
    ucast eth0 192.168.0.[2-3] # 相手のIPアドレス
    auto_failback on
    node lb01
    node lb02
    use_logd yes
    
    /etc/ha.d/ へ配置する
    sudo cp ha.cf /etc/ha.d/
    
  5. /etc/ha.d/haresources の作成
    これもテンプレートから
    アクティブ系、IP、サービス名を指定
    sudo cp /usr/share/doc/heartbeat/haresources.gz .
    sudo gzip -d haresources.gz
    sudo vi haresources
    
    lb01 IPaddr::172.16.0.1/24 nginx
    
    /etc/ha.d/ へ配置する
    sudo cp haresources /etc/ha.d/
    
  6. /etc/ha.d/authkeys の作成
    これもテンプレートから
    sudo cp /usr/share/doc/heartbeat/authkeys .
    sudo vi authkeys
    
    auth 3
    3 md5 Hello!
    
    /etc/ha.d/ へ配置し、root ユーザからのアクセスのみ許可するようにする (これしてなくて heartbeat 起動時に怒られた)
    sudo cp authkeys /etc/ha.d/
    chmod 600 /etc/ha.d/authkeys
    
  7. lb01 -> lb02 の順で heartbeat を起動
    sudo /etc/init.d/heartbeat start
    
  8. フェイルオーバーの試験とか
    ifconfig とかでeth1:0 に サービス IP 172.16.0.1 が引き継がれていれば成功。

Nov 10, 2009

mozilla labs より raindrop を試してみた

mozilla LABS に raindrop という新プロジェクトが先月 (Oct 2009) 登場しました。raindrop は mozilla messaging の開発チーム (thunderbird など) が Web 上のメッセージングサービスに関する革新的な実験をするのが目的だそうです。バックエンドは、CouchDB、及び (Twisted) Python です。せっかく仕事で CouchDB を触ったので、インストールしてみることに。

機能は大きく分けて、2 つにわかれています。

  • Web 上のメッセージングサービス (gmail, imap mail, twitter, skype, etc...) の情報を収集、蓄積する機能
  • 集約した情報を表示、操作するためのユーザインタフェース機能

mozilla LABS に、そのアーキテクチャーを解り易く解説された画像が掲載されていました。

raindrop_arc.png

インストール (OS: ubuntu - その他の OS へのインストールは公式ドキュメントを参照)

  1. raindrop ソースコードのダウンロード
    # mercurial をインストールしていない方は mercurial を取得
    sudo apt-get install mercurial
    cd /usr/src/
    sudo hg clone -r 0.1 http://hg.mozilla.org/labs/raindrop
    
  2. python ライブラリー類のインストール
    必要なライブラリーは、setuptools, twisted, PyOpenSSL, Skype4Py, python-twitter, simplejson, feedparser, paisley です。setuptools を入れている場合は、以下のコマンドで一発でライブラリー類をいれてくれます。
    sudo python raindrop/server/python/check-raindrop.py --configure
    
    上記のコマンドを実行する前に PyOpenSSL を個別に apt-get 経由でインストールしておく (私の環境では setuptools ではうまくいきませんでした)。
    sudo apt-get install python-pyopenssl
    
  3. raindrop 設定ファイルを作成
    ホームディレクトリー配下に .raindrop というファイルを作成し、Web メッセージングサービスの認証情報をセットします。これは、Web インターフェース上から実行できるように開発中とのことです。。
    vi ~/.raindrop
    
    ファイルには以下のように記載しました。実際に作成する際は、本家ドキュメントで最新版を確認した方がいいと思います。
    [couch-local]
    host=localhost
    port=5984
    
    [account-gmail-username]
    proto=imap
    kind=gmail
    username=[gmail アドレス]
    password=[gmail パスワード]
    ssl=True
    
    [account-twitter-username]
    proto=twitter
    kind=twitter
    username=[twitter ID]
    password=[twitter パスワード]
    
    [account-skype-username]
    proto=skype
    kind=skype
    username=[skype ID]
    password=[skype パスワード]
    
    [account-rss-feed]
    proto=rss
    uri=[購読したい feed URL]
    
  4. raindrop の起動
    sudo python raindrop/server/python/run-raindrop.py sync-messages --max-age=2days
    
    Web メッセージングサービスを巡回し、ガンガンメッセージを収集します。
    http://127.0.0.1:5984/raindrop/inflow/index.html で raindrop UI にアクセスできます。

以下のような UI が起動します。

画像は解説付きで picasa にアップロードしました。

Nov 7, 2009

ubuntu に mongodb をインストール - with pymongo / vs couchdb

一段落ついたので、couchdb に引き続き mongodb もインストールしてみた。環境は同じく VMWare 上の ubuntu。シングルサーバ、シングルクライアント (python) な環境で比較することに。

というのも、設定に誤りがあるためか、 couchdb が期待できるようなパフォーマンスが出なかったため。100 万件のデータを insert 処理するストレステスト (本番バッチ処理環境を考慮) をしているのですが、途中で conflict -> socket error -> down になってしまう。途中 sleep を入れると socket error は出なくなるけど、それだと遅いのと、なんだか気持ち悪い。前ポストで書いたように、0.8.0, 0.11.0b, 0.10.0 で試したけど、結果は同じでした。何が悪いのだろう・・・。

気は取り直して、mongodb は期待する結果が得られたので、インストールと pymongo 経由での処理方法です。

  1. 依存パッケージ類のインストール
    sudo aptitude install tcsh git-core scons g++
    sudo aptitude install libpcre++-dev libboost1.37-dev libreadline-dev libmozjs-dev
    
  2. git から mongodb のダウンロードとインストール (/opt/mongo へ)
    cd /usr/src/
    git clone git://github.com/mongodb/mongo.git
    cd mongo
    sudo scons all
    sudo scons --prefix=/opt/mongo install
    
  3. mongo ユーザの追加
    sudo adduser --system --home /opt/mongo/ --no-create-home --shell /bin/bash --group --gecos "mongoDB Administrator" mongo
    
  4. db データディレクトリーの追加とパーミッション設定
    sudo mkdir -p /data/db
    sudo chown -R mongo:mongo /data/
    sudo chmod a+x /data/db/
    
    データディレクトリは任意だけど、デフォルトのパスは上記のディレクトリになってる
  5. デーモン monbod の起動
    sudo /opt/mongo/bin/mongod
    
    もしデータディレクトリを別の場所にしている場合は、--dbpath オプションで渡してやる
    sudo /opt/mongo/bin/mongod --dbpath /path/to/db
    
    バックグラウンドプロセスで起動するために、末尾に "&" をつけてやる。
    もし、そのまま起動してしまった場合は <Ctrl>+z でプロセスを停止し、 bg でバックグラウンドプロセスに放り込む
    正常に起動した場合は、以下のようなメッセージが標準出力に表示される。
    Fri Nov  6 11:43:02 Mongo DB : starting : pid = 3558 port = 27017 dbpath = /data/db master = 0 slave = 0  32-bit
    
    ** NOTE: when using MongoDB 32 bit, you are limited to about 2 gigabytes of data
    **       see http://blog.mongodb.org/post/137788967/32-bit-limitations for more
    
    Fri Nov  6 11:43:02 *** warning: spider monkey build without utf8 support.  consider rebuilding with utf8 support
    Fri Nov  6 11:43:02 db version v1.1.3-, pdfile version 4.5
    Fri Nov  6 11:43:02 git version: 9ecceafbca1c0f88ec69aa659f12a7098f563095
    Fri Nov  6 11:43:02 sys info: Linux wb01 2.6.28-16-generic #55-Ubuntu SMP Tue Oct 20 19:48:24 UTC 2009 i686
    Fri Nov  6 11:43:02 waiting for connections on port 27017
    
  6. mongodb の停止
    mongo プロンプトからやるか ps からプロセスIDを取得して kill するらしい。プロンプトでやろう (笑
    sudo /opt/mongo/bin/mongo
    
    > use admin
    switched to db admin
    > db.shutdownServer()
    Fri Nov  6 11:55:57 terminating, shutdown command received
    Fri Nov  6 11:55:57  dbexit:
    Fri Nov  6 11:55:57      shutdown: going to flush oplog...
    Fri Nov  6 11:55:57      shutdown: going to close sockets...
    Fri Nov  6 11:55:57      shutdown: waiting for fs...
    Fri Nov  6 11:55:57      shutdown: closing all files...
    Fri Nov  6 11:55:57      closeAllFiles() finished
    Fri Nov  6 11:55:57      shutdown: removing fs lock...
    Fri Nov  6 11:55:57  dbexit: really exiting now
    ERROR: Client::shutdown not called!
    server should be down...
    Fri Nov  6 11:55:57 trying reconnect to 127.0.0.1
    Fri Nov  6 11:55:57 reconnect 127.0.0.1 ok
    Fri Nov  6 11:55:57 JS Error: Error: error doing query: failed (anon):99
    > exit
    bye
    [3]-  Done                    sudo /opt/mongo/bin/mongod
    
  7. pymongo のインストール (setuptools を使う)
    sudo easy_install pymongo
    
  8. pymongo を使ってみる (pymongo のドキュメント通りにやってみる)
    >>> from pymongo.connection import Connection
    >>> connection = Connection("localhost", 27017)
    Fri Nov  6 12:02:30 connection accepted from 127.0.0.1:29390 #2
    Fri Nov  6 12:02:30 end connection 127.0.0.1:29390
    >>> db = connection.test
    >>> db.name()
    u'test'
    >>> db.my_collection
    Collection(Database(Connection('localhost', 27017), u'test'), u'my_collection')
    >>> db.my_collection.save({"x": 10})
    Fri Nov  6 12:03:12 connection accepted from 127.0.0.1:29646 #3
    Fri Nov  6 12:03:12 allocating new datafile /data/db/test.ns, filling with zeroes...
    ObjectId('4af391f07ad5bd0fc4000000')
    >>> Fri Nov  6 12:03:12 done allocating datafile /data/db/test.ns, size: 16MB, took 0.102 secs
    Fri Nov  6 12:03:12 allocating new datafile /data/db/test.0, filling with zeroes...
    Fri Nov  6 12:03:13 done allocating datafile /data/db/test.0, size: 64MB, took 0.55 secs
    Fri Nov  6 12:03:13 building new index on { _id: ObjId(000000000000000000000000) } for test.my_collection...
    Fri Nov  6 12:03:13 Buildindex test.my_collection idxNo:0 { name: "_id_", ns: "test.my_collection", key: { _id: ObjId(000000000000000000000000) } }
    Fri Nov  6 12:03:13 done for 0 records 0.257secs
    Fri Nov  6 12:03:12 insert test.my_collection 913ms
    
    >>> db.my_collection.save({"x": 8})
    ObjectId('4af392067ad5bd0fc4000001')
    >>> db.my_collection.save({"x": 11})
    ObjectId('4af392107ad5bd0fc4000002')
    >>> db.my_collection.find_one()
    {u'x': 10, u'_id': ObjectId('4af391f07ad5bd0fc4000000')}
    >>> for item in db.my_collection.find():
    ...   print item["x"]
    ...
    10
    8
    11
    
    最初に my_connection にアクセスした際に、test バイナリーファイルが作成されるみたいですね。
    適当に connection.foo, db.bar とかやっても動きます。
  • couchdb は CPU 使用率やメモリ使用率は少ないです。それと比較すると mongodb はストレステストの間中 99.9% の CPU を消費していました
  • couchdb はストレスをかけると comflict -> socket error -> down になりましたが、mongodb は落ちずにより高速に処理できました

ちょっと今回の検証では couchdb を使いこなせなかった感じです。とりあえず、mongodb を使うことにしましたが、 couchdb についてももうちょっと勉強したいと思います。あっ tokyo tyrant も。

Nov 5, 2009

CentOS に Django をデプロイ - with python2.6, mod_python, mysql

Ubuntu でしか作ったことなかったけど、CentOS 5 系 で Django をデプロイしてみる

  1. とりあえずパッケージを最新に更新
    # yum update
    
  2. python 2.6 のインストール
    CentOS ってデフォルトでは 2.4 なんですね。2.6.4 をソースから入れる。まず zlib, sqlite を入れる。sqlite いれないと import sqlite3 できない
    # yum install zlib zlib-devel sqlite-devel
    
    python ソースのダウンロードとビルド、インストール
    # wget http://python.org/ftp/python/2.6.4/Python-2.6.4.tgz
    # tar xvfz Python-2.6.4.tgz
    # cd Python-2.6.4
    
    /opt/python2.6 にインストール。path は個人的な趣味。 --enable-shared オプションを追加する
    # ./configure --prefix=/opt/python2.6 --with-threads --enable-shared
    
    Setup ファイルで zlib のところのコメントを外す。
    # vi Modules/Setup
    
    --- #zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
    +++ zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz
    
    # make
    # make install
    
  3. python 2.6 環境設定 (2.4 と共存させる)
    パス周りを設定
    # vi /etc/ld.so.conf.d/opt-python2.6.conf
    # /sbin/ldconfig
    # sudo ln -s /opt/python2.6/bin/python /usr/bin/python2.6
    # cd
    
    個人的な趣味で、PATH は.bash_profile, alias は .bashrc にセット
    # vi .bash_profile
    
    --- PATH=$PATH:$HOME/bin
    +++ PATH=$PATH:$HOME/bin:/opt/python2.6/bin/
    
    # vi .bashrc
    
    +++ alias python='python2.6'
    
    # source ~/.bash_profile
    # source ~/.bashrc
    
    確認
    # python2.6 -V
    Python 2.6.4
    # python -V
    Python 2.6.4
    
  4. setuptools のインストール
    オプションで python の path を渡す
    # wget http://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg
    # sudo sh setuptools-0.6c11-py2.6.egg --prefix=/opt/python2.6
    
  5. PIL のインストール
    # yum install libjpeg-devel freetype*
    # wget http://effbot.org/media/downloads/Imaging-1.1.7b1.tar.gz
    # cd Imaging-1.1.7b1
    # python setup.py build
    # python setup.py install
    
    インストールをテスト
    # python selftest.py
    --------------------------------------------------------------------
    PIL 1.1.7b1 TEST SUMMARY
    --------------------------------------------------------------------
    Python modules loaded from ./PIL
    Binary modules loaded from /opt/python2.6/lib/python2.6/site-packages/PIL
    --------------------------------------------------------------------
    *** PIL CORE support not installed
    *** TKINTER support not installed
    --- JPEG support ok
    --- ZLIB (PNG/ZIP) support ok
    *** FREETYPE2 support not installed
    *** LITTLECMS support not installed
    --------------------------------------------------------------------
    Running selftest:
    --- 57 tests passed.
    
  6. Django のインストール
    easy_install さまさま
    # sudo easy_install Django
    Installed /opt/python2.6/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg
    
  7. MySQL, MySQL-python のインストール
    エンコードは utf8 に。
    # yum install mysql-devel
    # vi /etc/my.cnf
    
    +++
    [mysql]
    default-character-set = utf8
    +++
    
    # /etc/init.d/mysqld start
    
    起動時にサービスが開始されるように設定
    # /sbin/chkconfig --levels 235 mysqld on
    
    python ドライバを入れておく
    # easy_install MySQL-python
    
  8. MySQL の設定
    # mysqladmin -u root password 'パスワード';
    # mysqladmin -u root -h localhost password 'パスワード';
    # mysql -u root -p
    Enter password:
    
    mysql> CREATE DATABASE mysite;
    Query OK, 1 row affected (0.36 sec)
    
    mysql> SHOW DATABASES;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysite             |
    | mysql              |
    | test               |
    +--------------------+
    4 rows in set (0.00 sec)
    
    mysql> CREATE USER mysiteuser IDENTIFIED BY 'パスワード';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> GRANT ALL PRIVILEGES ON mysite.* TO mysiteuser IDENTIFIED BY 'パスワード';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> GRANT ALL PRIVILEGES ON mysite.* TO mysiteuser@localhost IDENTIFIED BY 'パスワード';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> quit
    Bye
    # mysql -u mysiteuser -p
    Enter password: 
    
    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysite             |
    | test               |
    +--------------------+
    3 rows in set (0.00 sec)
    
    mysql> use mysite;
    Database changed
    mysql> show tables;
    Empty set (0.00 sec)
    
    mysql> quit
    Bye
    
  9. Apache, mod_python のインストール
    # yum install httpd-devel
    # wget http://ftp.kddilabs.jp/infosystems/apache/httpd/modpython/mod_python-3.3.1.tgz
    # tar xvzf mod_python-3.3.1.tgz
    # cd mod_python-3.3.1
    # ./configure --with-python=/opt/python2.6/bin/python --with-apxs=/usr/sbin/apxs
    # make
    
  10. Apache, mod_python の設定
    • URL: http://domain.com/mysite/
    • admin URL: http://domain.com/mysite/admin/
    • media URL: http://domain.com/media/
    • django プロジェクト (settings.py) のデプロイ先: /var/www/django/mysite
    • media の展開先: /var/www/html/media
    • log の保存先: /var/log/django/
    Note: /var/www/html はデフォルトで公開されていると想定
    admin media は /path/to/django/contrib/admin/media/ を /var/www/html/ 内に ln-s でシンボリックリンクを作成し、 chown しておく
    # mkdir /var/www/django/mysite
    # mkdir /var/www/django/mysite/.python-eggs
    # chown apache:apache -R /var/www/django/
    # chmod a+x /var/www/django/
    # mkdir /var/www/html/media
    # chown apache:apache -R /var/www/html/
    # mkdir /var/log/django/mysite
    # chown apache:apache -R /var/log/django/
    # chmod a+x /var/log/django/
    # vi /etc/httpd/conf.d/python.conf
    
    +++ 
    <Location /mysite>
        SetHandler python-program
        PythonPath "sys.path + ['/var/www/django']"
        PythonHandler django.core.handlers.modpython
        PythonOption django.root /mysite
        SetEnv PYTHON_EGG_CACHE /var/www/django/mysite/.python-eggs
        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
        PythonDebug On
    </Location>
    +++ 
    
    /etc/init.d/httpd reload
    
  11. アプリケーションのデプロイと起動 SCP なり FTP なり git なり easy_install なりなんでもいいので、アプリケーションを /var/www/django/mysite/ に置く。syncdb したら動きます。
    # cd /var/www/django/mysite/
    # settings.py syncdb
    

admin User を shell で作る
shell でやる

# python manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User(username='admin', email='foo@bar.com', password='パスワード')
>>> user.is_active=True
>>> user.is_staff=True
>>> user.is_superuser=True
>>> user.save()

/mysite/admin を IP アドレスでアクセス制御する
/etc/httpd/conf.d/python.conf を以下のようにする。

<Location "/mysite/">
    SetHandler python-program
    PythonPath "sys.path + ['/var/www/django']"
    PythonHandler django.core.handlers.modpython
    PythonOption django.root /mysite
    SetEnv PYTHON_EGG_CACHE /var/www/django/mysite/.python-eggs
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonDebug On
</Location>
<LocationMatch "/mysite/admin/">
    Order deny,allow
    Deny from all
    Allow from "ipaddress"
</LocationMatch>

about

friends

archives

Kosei Kitahara.

surgo.jp at gmail.com

hosted at blogger.