読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

Node.jsの実行環境を構築してみた

せっかくの機会(何)ということで、Ubuntu 10.04上にNode.jsの実行環境を構築してみたのでメモ。
とはいっても、インストール方法ならあちこちの人が書いているので、そちらを参考にすればいいんじゃな〜い(誰)。

まぁ、一応、自分がインストールするときに叩いたコマンドのメモは残しておく(謎)。
インストール:(参考は「Software Design 2011年9月号」)

$ sudo apt-get install build-essential libssl-dev curl
$ curl http://nodejs.org/dist/node-v0.4.10.tar.gz | tar xz
$ cd node-v0.4.10
$ ./configure
$ make
$ sudo make install
$ curl http://npmjs.org/install.sh | sudo sh

サンプル:

$ sudo mkdir -p /var/www/node-scripts
$ sudo chmod a+w /var/www/node-scripts
$ cd /var/www/node-scripts
$ mkdir sample01
$ cd sample01
$ cat > sample01.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "xxx.xxx.xxx.xxx");
console.log('Server running at http://xxx.xxx.xxx.xxx:1337/');
^D
$ node sample01.js
Server running at http://xxx.xxx.xxx.xxx:1337/


まぁ、これであとはApacheなりnginx(使ったことないけど)なりでバランシングしてスケールアウトしていけばいいだろ‥‥なわけはない、コンソールからサーバープログラムを起動して満足するなんてどういうことだ(謎)
ということで、ざっと調べた感じでは見当たらなかったので、init.dに置くための起動スクリプトと、起動するプログラムの配置についてマイルールを作ってみた。
仕様はこんな感じかしら。

指定したプログラムの制御
    nodectl pgstart <pg-name>
    nodectl pgstop <pg-name>
    nodectl pgrestart <pg-name>
一括で制御
    nodectl start
    nodectl stop
    nodectl restart

init.dに置くスクリプトである関係上、一括制御のコマンドはstart/stop/restartで固定。

  • プログラムの配置
+ NODE_SCRIPT_DIR    // Node.jsで動かすサーバープログラムの置き場
|  + hello_world     // プログラムごとにディレクトリを作成
|  |  - main.conf    // エントリポイントの設定(とりあえずはファイル名を書いておく)
|  |  + logs         // ログ出力用ディレクトリ
|  |  + xxx          // あとは必要なディレクトリや
|  |  - yyy          // ファイルを適当に配置
|  +  sample01
|  |  - main.conf
|  |  + logs
         :
|  +  sample02
|  |  - main.conf
|  |  + logs
         :
(中略)
+ ENABLED_NODES_DIR  // 実際に起動するプログラムを格納
|  + hello_world     // NODE_SCRIPT_DIR/hello_world へのシンボリックリンク
|  +  sample01       // NODE_SCRIPT_DIR/sample01 へのシンボリックリンク

上記の仕様に基づいた起動スクリプトはこんな感じ。

#! /bin/bash

ENABLED_NODES_DIR=/var/www/node-scripts/enabled

NODE=/usr/local/bin/node

. /lib/lsb/init-functions

function __proc() {
    local cmd=$1
    local pgname=$2
    case "${cmd}" in
    "start"|"stop"|"restart")
        __${cmd}
    ;;
    "pgstart"|"pgstop"|"pgrestart")
        __${cmd} ${pgname}
    ;;
    *)
        __usage >> /dev/stderr
        exit 1
    ;;
    esac
}

function ___chkPgName() {
    if [ -z ${pgname} ]; then
        __usage >> /dev/stderr
        exit 2
    fi
    if [ ! -d ${ENABLED_NODES_DIR}/${pgname}/ ]; then
        echo "${pgname}: Specified program is not enabled." >> /dev/stderr
        exit 3
    fi
}
function __start() {
(
    local pgname
    cd ${ENABLED_NODES_DIR}
    for pgname in * ; do
        __pgstart
    done
)
}
function __stop() {
(
    local pgname
    cd ${ENABLED_NODES_DIR}
    for pgname in * ; do
        __pgstop
    done
)
}
function __restart() {
    __stop
    __start
}
function __pgstart() {
(
    ___chkPgName
    cd ${ENABLED_NODES_DIR}/${pgname}
    main=$(cat main.conf)
    logname=$(basename ${main} .js)_log_$(date +%Y%m%d-%H%M%S)
    pidfile=${pgname}.pid
    if [ ! -f ${pidfile} ]; then
        log_daemon_msg "Starting node:${pgname}" "node"
        nohup ${NODE} ${main} > logs/${logname} 2>&1 &
        ps auxww | grep -v grep | grep "${NODE} ${main}" | awk '{print $2;}' > ${pidfile}
        if [ -n "$(cat ${pidfile})" ]; then
            log_end_msg 0
        else
            log_end_msg 1
        fi
    else
        echo "${pgname}: Already running." >> /dev/stderr
    fi
)
}
function __pgstop() {
(
    ___chkPgName
    cd ${ENABLED_NODES_DIR}/${pgname}
    pidfile=${pgname}.pid
    if [ -f ${pidfile} ]; then
        log_daemon_msg "Stopping node:${pgname}" "node"
        pid=$(cat ${pidfile})
        kill ${pid}
        if [ $? -eq 0 ]; then
            rm -f ${pidfile}
            log_end_msg 0
        else
            log_end_msg 1
        fi
    else
        echo "${pgname}: Not running." >> /dev/stderr
    fi
)
}
function __pgrestart() {
    ___chkPgName
    __pgstop
    __pgstart
}

function __usage() {
    echo "USAGE $0 {start|stop|restart}"
    echo "        or"
    echo "      $0 {pgstart|pgstop|pgrestart} <pg-name>"
}

__proc $1 $2

思いがけず大きなスクリプトになった‥
このスクリプトを配置して、起動/停止設定。起動順はてきとー(ぇ

$ sudo cp -i nodectl /etc/init.d/
$ sudo chmod a+x /etc/init.d/nodectl
$ sudo update-rc.d nodectl defaults 99 1
$ ls -l /etc/*.d/* | grep nodectl
-rwxr-xr-x 1 root root  1925 2011-10-31 23:09 /etc/init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc0.d/K01nodectl -> ../init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc1.d/K01nodectl -> ../init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc2.d/S99nodectl -> ../init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc3.d/S99nodectl -> ../init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc4.d/S99nodectl -> ../init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc5.d/S99nodectl -> ../init.d/nodectl
lrwxrwxrwx 1 root root    17 2011-10-31 23:14 /etc/rc6.d/K01nodectl -> ../init.d/nodectl

‥って、ファイルモードは700もしくは744でいいんじゃないかと思ったが、ほかのファイルも755になってるのでとりあえず気にしない(待て)。