2014年7月24日木曜日

さくらレンタルサーバーにnode.jsをインストールしてみた

スタンダードさくらインターネットレンタルサーバーにnode.jsをインストールしました。

こだわりゆえに死ぬほど大変でしたが、まとめておきます。

結果から言うと、node.js上でチャットアプリケーションがインターネット上のサービスとしてきちんと動作するところまで確認できました。


こういった事は計画が大事なので、どういう方針でインストールするか書いておきます。
(当然、事前に計画したものではなく、試行錯誤の結果である事は言うまでもない)


  • nvmからのインストールにこだわる
  • 問題が発生しても、安易にソース修正して機能削減を行わず、きちんと足りないライブラリをインストールするようにする
  • 倫理的に問題になりそうな手段はとらない
  • 出来るだけ理解してやる(一部解らないところも出ましたが…)

です。

また結果的に、やらなければいけない事は以下です。

  • nvmのインストール
  • libexecinfoのインストール
  • node.jsのインストール
  • アプリケーションの準備
  • アプリケーションの実行・確認

苦労話は省略して、上記の流れでどうすればいいのかを書いていきます。

nvmのインストール

これはgitで落としてきました。具体的には以下のコマンド

git clone git://github.com/creationix/nvm.git ~/.nvm

これでnvm実行に必要なすべてのファイルが~/.nvmにダウンロードされます。
~/.nvm/nvm.shを実行すればnvmコマンドが使えるようになりますが、ここではまだ実行しません。

libexecinfoのインストール

恐らくここが一番の難関だと思います。

結論から言うと、portsをインストールしてlibexecinfoをダウンロード・展開し、手動でhome/local/に作ったディレクトリにコピーするという手段をとりました。ソースからでも良いのですが、実施時点でFreeBSDの公開URLが解らなくなっておりまして…。正直、できるならソースからの方が楽だと思います。

まずportsのインストールはこちらを参考にさせて頂きました。


まずはディレクトリを準備します。参考サイトのコマンドそのままです。
% mkdir ~/local
% cd ~/local
% mkdir work
% mkdir work/ports
% mkdir work/ports/distfiles
% mkdir var
% mkdir var/db
% mkdir var/db/portsnap
% emacs ~/work/ports/portsnap.conf
最後のコマンドでportsnap.confのエディタが開きます。僕はemacsを使いますが、viでも問題ないです。

内容はこちらも参考サイトと同じ内容です。
パスの中のhome下のユーザー名部分の修正だけ注意してください。WORKDIRとPORTSDIRの2か所です。

# Default directory where compressed snapshots are stored.
WORKDIR=/home/(user name)/local/var/db/portsnap

# Default location of the ports tree (target for "update" and  "extract").
PORTSDIR=/home/(user name)/local/work/ports

# Server or server pool from which to fetch updates.  You can change
# this to point at a specific server if you want, but in most cases
# using a "nearby" server won't provide a measurable improvement in
# performance.
SERVERNAME=portsnap.FreeBSD.org

# Trusted keyprint.  Changing this is a Bad Idea unless you've received
# a PGP-signed email from  telling you to
# change it and explaining why.
KEYPRINT=9b5feee6d69f170e3dd0a2c8e469ddbd64f13f978f2f3aede40c98633216c330

# Example of ignoring parts of the ports tree.  If you know that you
# absolutely will not need certain parts of the tree, this will save
# some bandwidth and disk space.  See the manual page for more details.
#
# WARNING: Working with an incomplete ports tree is not supported and
# can cause problems due to missing dependencies.  If you have REFUSE
# directives and experience problems, remove them and update your tree
# before asking for help on the mailing lists.
#
REFUSE arabic chinese french german hebrew hungarian
REFUSE korean polish portuguese russian ukrainian vietnamese
REFUSE x11 x11-clocks x11-drivers x11-fm x11-fonts x11-servers x11-themes x11-toolkits x11-wm
REFUSE palm cad astro

このファイルをportsnapコマンドで読み込めば、portsの準備は完了です。
% portsnap -f ~/ports/portsnap.conf fetch extract update
portsからインストールしたものは、解りやすいように~/local/ports下にインストールするように設定します。

以下のコマンドで、ディレクトリの作成と~/.cshrcの編集を開きます。
% cd ~/local
% mkdir ports
% cd ports/
% mkdir -p bin sbin etc lib tmp/dist tmp/work var/db/pkg var/db/ports var/run
% emacs ~/.cshrc

.cshrcの追加内容は参考サイトとほぼ同じですが、NODE_PATHとNODE_MODULESを削除し、代わりにCPATHを追加しています。cプログラムソース内のincludeがうまく行くようにするためです。念のため、PATHに${HOME}/local/libも追加していますが、これは機能していないかもしれません。

また、SRCCONFの設定も重要ですので忘れずに入れてください。
setenv  PATH    ${PATH}:${HOME}/local/ports/bin:${HOME}/local/lib
setenv  CPATH   
setenv  CPATH   ${CPATH}:${HOME}/local/include
setenv  LD_LIBRARY_PATH
setenv  LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:${HOME}/local/lib

setenv  INSTALL_AS_USER yes
setenv  PREFIX  ${HOME}/local/ports
setenv  LOCALBASE   ${HOME}/local/ports
setenv  PKG_DBDIR   ${LOCALBASE}/var/db/pkg
setenv  PKG_TMPDIR  ${LOCALBASE}/tmp/
setenv  PORT_DBDIR  ${LOCALBASE}/var/db/pkg
setenv  DISTDIR ${LOCALBASE}/tmp/dist
setenv  WRKDIRPREFIX    ${LOCALBASE}/tmp/work
setenv  PORTSDIR    ${HOME}/local/work/ports
setenv  PKGTOOLS_CONF   ${LOCALBASE}/etc/pkgtools.conf
setenv  DEPENDS_TARGET  'install clean'

setenv  X11BASE ${LOCALBASE}

setenv  PKG_CONFIG_PATH "$HOME/local/ports/lib/pkgconfig:$HOME/local/ports/libdata/pkgconfig:/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/libdata/pkgconfig:/usr/libdata/pkgconfig"

# Set user and group variables to ourself
setenv  BINOWN  `whoami`
setenv  BINGRP  `id -G -n ${BINOWN}`
setenv  SHAREOWN    ${BINOWN}
setenv  SHAREGRP    ${BINGRP}
setenv  MANOWN  ${BINOWN}
setenv  MANGRP  ${BINGRP}

# Make sure files are installed with correct default permissions
setenv  BINMODE 744
setenv  SHAREMODE   644
setenv  MANMODE 644

# Make sure we don't really try to become root, but just execute everything as ourselves
setenv  SU_CMD  "sh -c"

# Make sure the systemdefault make.conf is not read
setenv  __MAKE_CONF ${LOCALBASE}/etc/make.conf

# Keep our own version of ldconfig hints
setenv  LDCONFIG    "/sbin/ldconfig -i -f ${LOCALBASE}/var/run/ld-elf.so.hints"
#setenv LDCONFIG    "/sbin/ldconfig -f=${LOCALBASE}/var/run/ld-elf.so.hints -i -R=${LOCALBASE}/etc/ld-elf.so.conf "
setenv  LD_LIBRARY_PATH ${LOCALBASE}/lib
setenv  LD_RUN_PATH ${LOCALBASE}/lib

setenv  PATH    ${LOCALBASE}/bin:${LOCALBASE}/sbin:${PATH}
setenv  MANPATH_MAP ${LOCALBASE}/bin:${LOCALBASE}/man

# Set application specific variables to make sure it doesn't pick up things from the main system
setenv  APXS    ${LOCALBASE}/sbin/apxs
setenv  PERL    ${LOCALBASE}/bin/perl
setenv  PERL5   ${PERL}
setenv  SITE_PERL   ${LOCALBASE}/lib/perl5/site_perl/5.8.8
setenv  SITE_PERL5  ${SITE_PERL}
setenv  PERL_VERSION    5.8.8
setenv  PERL_VER    ${PERL_VERSION}

setenv  SRCCONF     ~/local/ports/etc/src.conf

ファイルを保存したら、上記パスを通したディレクトリの作成と、libexecinfoの展開を手動で行います。

まずはportsからlibexecinfoをmake installします。
先に言っておくと、これはルート権限がないため失敗に終わりますが、その後手動でコピーするため問題ないです。

% cd ~/local/work/ports/devel/libexecinfo
% make install

実行はpermission deniedで失敗に終わりますが、~/local/ports/のincludeとlibには目的のファイルが生成されています。~/local/にユーザー領域内での参照用のディレクトリ、includeとlibを作成し、生成されたファイルをコピーします。

% cd ~/local/
% mkdir -p include lib
% cp ~/local/ports/include/execinfo.h ~/local/include/
% cp ~/local/ports/lib/libexecinfo.* ~/local/lib/


ここまで終わったのち、.cshrcを読み直します。

% source ~/.cshrc


node.jsのインストール

ここまでくればあと一歩ですが、実は大きな問題があります。

落としてくるソースのmksnapshotのコンパイルでlibexecinfoを利用するのですが、ライブラリの参照先が固定で-L/usr/local/libになっているのです。

execinfo.hのincludeはCPATHで対応できるのですが、v8エンジン系のコンパイルで使用しているgypのパラメータファイルに固定で記述された値が使用されており、ここを修正しないとコンパイルが成功しません。

ここで通常はソースからコンパイルを選択すると思いますが、僕はあえてnvmでやりたかったのでnvm.shを書き換え、makeが走る前に自作のシェルが動作するように変更しました。

関数nvm()内、case文の"install" | "i" )下、変数tmpdir、tarballの設定が終わった後のif文

      if (
        [ -n "$tarball" ] && \
        mkdir -p "$tmpdir" && \
        curl -L --progress-bar $tarball -o "$tmptarball" && \
        nvm_checksum "$tmptarball" $sum && \
        tar -xzf "$tmptarball" -C "$tmpdir" && \
        cd "$tmpdir/node-$VERSION" && \
        ./configure --prefix="$NVM_DIR/$VERSION" $ADDITIONAL_PARAMETERS && \
  +     source ~/.nvm/preinstall.add.sh && \
        $make $MAKE_CXX && \
        rm -f "$NVM_DIR/$VERSION" 2>/dev/null && \
        $make $MAKE_CXX install
        )
      then
        nvm use $VERSION
        ...


追加したシェルスクリプト~/.nvm/preinstall.add.shの内容は以下です。

#!/bin/sh

function vercomp () {
if [[ $1 == $2 ]]
then
return 0
fi
local IFS=.
local ver1=($1) ver2=($2)
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++))
do
if [[ -z ${ver2[i]} ]]
then
ver2[i]=0
fi
if (( 10#${ver1[i]} > 10#${ver2[i]} ))
then
return 1
fi
if (( 10#${ver1[i]} < 10#${ver2[i]} ))
then
return 2
fi
done
return 0
}

local_vsn=${VERSION/v/}

local -i check
`vercomp $local_vsn "0.10.28"`
check=$?

if [[ $check = 1 ]]
then
fileadd="host"
else
fileadd="target"
fi

sed -i".org" -e "685s/-L\/usr\/local\/lib/-L\/usr\/local\/lib -L$\{HOME\}\/local\/lib/" "$tmpdir/node-$VERSION"/deps/v8/tools/gyp/v8.gyp

sed -i".mid" -e "696s/-L\/usr\/local\/lib/-L\/usr\/local\/lib -L$\{HOME\}\/local\/lib/" "$tmpdir/node-$VERSION"/deps/v8/tools/gyp/v8.gyp

sed -i".mid" -e "707s/-L\/usr\/pkg\/lib -Wl,-R\/usr\/pkg\/lib/-L\/usr\/pkg\/lib -Wl,-R\/usr\/pkg\/lib -L$\{HOME\}\/local\/lib/" "$tmpdir/node-$VERSION"/deps/v8/tools/gyp/v8.gyp

sed -i".mid" -e "682s/{/\{'include_dirs+':['$\{HOME\}\/local\/include'],/" "$tmpdir/node-$VERSION"/deps/v8/tools/gyp/v8.gyp

sed -i".mid" -e "693s/{/\{'include_dirs+':['$\{HOME\}\/local\/include'],/" "$tmpdir/node-$VERSION"/deps/v8/tools/gyp/v8.gyp

sed -i".mid" -e "704s/{/\{'include_dirs+':['$\{HOME\}\/local\/include'],/" "$tmpdir/node-$VERSION"/deps/v8/tools/gyp/v8.gyp


sed -i"org" -e "117s/-L\/usr\/local\/lib/-L\/usr\/local\/lib -L$\{HOME\}\/local\/lib/" "$tmpdir/node-$VERSION"/out/deps/v8/tools/gyp/mksnapshot."$fileadd".mk

sed -i"org" -e "117s/-L\/usr\/local\/lib/-L\/usr\/local\/lib -L$\{HOME\}\/local\/lib/" "$tmpdir/node-$VERSION"/out/deps/v8/tools/gyp/v8_shell."$fileadd".mk

sed -i"org" -e "162s/-L\/usr\/local\/lib/-L\/usr\/local\/lib -L$\{HOME\}\/local\/lib/" "$tmpdir/node-$VERSION"/out/node.target.mk


恐らくFreeBSD部分だけ修正すればよいと思われますが、/usr/local/lib/を直接指定している部分はすべて変更してあります。

※異なる(特にv0.10.29以降)のバージョンをインストールする場合には、一度ダウンロードして変更対象ファイルの内容を確認し、sedの行数指定などを見直す必要があります。全面的な見直しも必要かもしれません。

このシェルスクリプトには作業当時の最新バージョンであるv0.10.29のgyp関連の設定ファイル名が変更されている事への対応が入っていますが、実際この作業をしている時点でv0.10.29のインストールは出来ませんでした。
uv.h内の変数addr, address6について'xxx' has incomplete typeのエラーが出ていたためで、これはこちらで対処する範囲外と判断し、v0.10.28のインストールを実施しています。


ここまでの修正を実施して、nvm install v0.10.28を実行すればnode.jsがインストールされるはずです。

% bash
$ source ~/.nvm/nvm.sh
$ nvm install v0.10.28

アプリケーションの準備、実行・確認

ここまで来れば後はアプリケーションを動作させるだけ!と思っていたのですが、実はここまで自分が全く考慮していなかった問題があることが解りました。

解放されているポートってあるのかな…?

さくらインターネットスタンダードに関して調べてみたところ、ポートはこれ以外は閉めてまっせ、とのこと。


正直、これを見る前に闇雲にやってみて他にも空いてそうなポートが無きにしも非ずだったのですが、とりあえず開けてまっせ、とのたもうておられるWebDAVの9800で起動してみたところ、アプリケーションは問題なく動作していることが確認できました。

本番稼働は別として、デモや研究などには利用できそうに思っています。



0 件のコメント:

コメントを投稿