2013年1月14日月曜日

[Redis 2.6]インストールメモ + パスワード設定時の起動スクリプト

明けまくりましておめでとうございます、おもくそです。
最終更新は汗もしたたる真夏、そして内容は今は亡き(失礼!)koboに関して、そして久方ぶりの更新はヤマト運輸がギブするほどの大雪日という現実に、四季が存在する国の素晴らしさを噛みしめております。

そんな新年一発目のエントリに、今年の抱負といった一般的なものではなく技術ネタを持ってくるという自分のことが、好きでもあり嫌いでもあります。まあ今年もこんな感じでマイペースに行こうと思います。

試した環境

Redisは昨年にバージョン2.4を少し使うことがあったのだけど、その時のドキュメントには「バージョン2.6でクラスタ構成できるようになるよ(Redis Cluster)」ってあったけど、正式リリースはまだみたいですね

ダウンロード、インストール

以下ページの通りに。「make install」しないんだね。あと言わずもがなだけどgcc必要です。
Download – Redis
$ wget http://redis.googlecode.com/files/redis-2.6.8.tar.gz
$ tar xvzf redis-2.6.8.tar.gz
$ cd redis-2.6.8
$ make

起動スクリプト生成

confファイル、ログファイル、起動スクリプトを生成してくれるシェルが同梱されているので、それを実行。Redis本体のバイナリ(redis-server)にパス通して無い場合は、途中でバイナリの実行パスを指定してあげる必要があります。
ところがこのシェル、どうもバグってるっぽいです。詳しくは後述します。まあ僕の環境の問題かもしれないけど・・・もしエラー発生しなかった場合は、エラーが関連している節は読み飛ばしてください。
$ cd utils
# ./install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server


Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] 
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] 
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] 
Selected default - /var/lib/redis/6379
which: no redis-server in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/omokuso/bin)
Please select the redis executable path [] /usr/local/redis/src/redis-server
which: no redis-cli in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/omokuso/bin)
s#^port [0-9]{4}$#port 6379#;s#^logfile .+$#logfile /var/log/redis_6379.log#;s#^dir .+$#dir /var/lib/redis/6379#;s#^pidfile .+$#pidfile /var/run/redis_6379.pid#;s#^daemonize no$#daemonize yes#;
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
./install_server.sh: line 178: update-rc.d: コマンドが見つかりません
 exists, process is already running or crashed
Installation successful!
「update-rc.d: コマンドが見つかりません」だと?
不具合その1。
「update-rc.d」というのは、UbuntuなどのDebian系のコマンドで、自動起動設定を行うものです。CentOSなどRedhat系での「chkconfig」に相当。CentOSで実行したら、見つからないのは当たり前です。

はて、バグか?起動スクリプト生成シェルを確認してみたところ・・・
・・・
#Install the service
echo "Installing service..."
if [ !`which chkconfig` ] ; then
        #if we're not a chkconfig box assume we're able to use update-rc.d
        update-rc.d redis_$REDIS_PORT defaults && echo "Success!"
else
        # we're chkconfig, so lets add to chkconfig and put in runlevel 345
        chkconfig --add redis_$REDIS_PORT && echo "Successfully added to chkconfig!"
        chkconfig --level 345 redis_$REDIS_PORT on && echo "Successfully added to runlevels 345!"
fi
・・・

うーん・・・ちゃんと「『chkconfig』が見つからなかったら」という判定を行ってRedhat系の場合の分岐もあるのけどな・・・chkconfigのパスも通ってるし。何でだろう・・・

とりあえず、判定条件とupdate-rc.d実行部分をコメントアウトし、chkconfigが無理矢理実行されるようにしてから再度実行してみたところ・・・
今度は「サービス redis_6379 は、chkconfig をサポートしていません。」ですって!?
不具合その2。
「redis_6379」ってのは自動生成されたRedisの起動スクリプトです。
chkconfigに登録するには、特定のフォーマットの記述が必要。以下はApacheの起動スクリプトの例です。
$ head /etc/init.d/httpd
#!/bin/bash
#
# httpd        Startup script for the Apache HTTP Server
#
# 以下2項目が必要
# ↓順番に「ランレベル(この例だと未指定だけど)」「起動優先順位」「停止優先順位」
#     優先順位はそれぞれ100未満じゃないとダメっぽい
# chkconfig: - 85 15
# ↓これはただの説明
# description: The Apache HTTP Server is an efficient and extensible  \
#        server implementing the current HTTP standards.
・・・

前述の「サポートしていません」エラーは、上記の記述が無い場合に発生する。
登録対象の起動スクリプトを確認してみると・・・何じゃこりゃぁっ!!
# vim /etc/init.d/redis_6379
#/bin/sh\n #Configurations injected by install_server below....\n\n EXEC=/usr/local/redis/src/redis-server\n CLIEXEC=/usr/local/redis/src/redis-cli\n PIDFILE=/var/run/redis_6379.pid\n CONF="/etc/redis/6379.conf"\n\n REDISPORT="6379"\n\n ###############\n\n

case "$1" in
    start)
・・・

chkconfig登録に必要な記述が無いばかりか、実行コードの一部分が改行されずに冒頭のシバンに連なってしまっている。どうも「\n」をメタ文字じゃなくテキストとして処理してしまっているっぽい。

とりあえず問題の「\n」を改行に変換(正規表現は「%s/\\n/\r/g」)し、chkconfig登録に必要な記述を追加したのが以下。
#/bin/sh
# chkconfig: - 90 90
# description: Redis and Gentlemen!

 EXEC=/usr/local/redis/src/redis-server
 CLIEXEC=/usr/local/redis/src/redis-cli
 PIDFILE=/var/run/redis_6379.pid
 CONF="/etc/redis/6379.conf"

 REDISPORT="6379"
・・・

これでようやく全ての準備が整いました。
起動・停止してみる。
# /etc/init.d/redis_6379 start
Starting Redis server...
# /etc/init.d/redis_6379 stop
Stopping ...
Waiting for Redis to shutdown ...
Redis stopped

そして自動起動設定。
# chkconfig --add redis_6379
# chkconfig redis_6379 on
# chkconfig --list redis_6379
redis_6379      0:off 1:off 2:on 3:on 4:on 5:on 6:off

Redisにパスワードを設定してみたら、停止できなくなった!

Redisは以下のようにパスワードを設定できます。
# vim /etc/redis/6379.conf
・・・
requirepass RedisAndGentlemen
・・・

これにより、各種操作を行う前にauthコマンドによる認証が必要になる。

さて、この状態で先ほど生成した起動スクリプトを実行すると、起動は問題なく行われるのだけど、停止は・・・
# /etc/init.d/redis_6379 start
Starting Redis server...
# /etc/init.d/redis_6379 stop
Stopping ...
(error) ERR operation not permitted
Waiting for Redis to shutdown ...

失敗してしまいます。shutdownコマンドの実行前にauthコマンドで認証通っておく必要あるようだ。

というわけで、起動スクリプトを修正。ちなみに当サンプルではncコマンドを使用するのでインストールしておいてください。

# yum install nc
# vim /etc/init.d/redis_6379
・・・

# パスワード
REQUIREPASS="RedisAndGentlemen"

・・・
    stop)
        if [ ! -f $PIDFILE ]
               ・・・
        else
               ・・・
                # 旧ロジック。こういうのはコミット前に削除しようね!
                #$CLIEXEC -p $REDISPORT shutdown

                # authとshutdownは同一セッションで実行しないといけません
                echo -en "auth $REQUIREPASS\r\nshutdown\r\n" | nc localhost $REDISPORT

                # ちなみに以下はダメ。auth時とshutdown時はセッション異なるので。
                #$CLIEXEC -p $REDISPORT auth $REQUIREPASS
                #$CLIEXEC -p $REDISPORT shutdown
                ・・・

以上。

2 件のコメント:

Kenji Saito さんのコメント...

インストールスクリプトは!`which chkconfig`が2箇所、chkconfigの存在チェックの判定条件が間違っています。
!と`の間にスペースが必要なのが抜けている。

これを解決すると、きちんと動作します。

おもくそ さんのコメント...

Re: Kenji Saito さん
あー本当だ。情報ありがとうございます。
他にはログファイルやデータディレクトリの判定部分も同様にスペース抜けてますね。

てか最初に気付けよ、俺・・・