LoginSignup
43
39

More than 5 years have passed since last update.

Nuxt.jsのアプリケーションをinitd-foreverを使ってデーモン化、自動起動する

Last updated at Posted at 2018-05-31

概要

Nuxt.jsのアプリケーションをサーバー環境にデプロイする際、Nuxt.jsのプロセスをバックグラウンドで起動して永続化するために、一般的にforeverを使う。
加えて、foreverをデーモン化して、serviceコマンドで[start, stop, status, restart]したり、chkconfigで自動起動しようと思ったら、initd-foreverを使う。

initd-foreverの記事はいくつか存在したけど、Nuxt.jsでそれを扱うという記事は見たところ存在しなかったので、今回はNuxt.jsのアプリケーションでinitd-foreverを導入する例を示す。

最終的には以下のような状態となる。

  • Nuxt.jsアプリケーションがservice app_name startといった具合にserviceコマンドで起動、停止、状態確認、再起動できる
  • Nuxt.jsアプリケーションをchkconfigでOS起動時に自動起動できる

 環境

  • Amazonlinux 1

準備

  • nuxt.jsで作成したアプリケーションをサーバーにデプロイしておく

手順

foreverをインストール

# npm install -g -y forever

foreverでNuxt.jsを起動してみる

# cd /var/www/app_name/
# forever start -c "npm run start" ./

Nuxt.jsのアプリケーションの/(ルート)に移動してforever startを実行する。
-c はコマンドを指定するという意味で、ここではNuxt.jsの起動コマンドである、"npm run start"を指定している。これでforever経由でNuxt.jsの起動ができた。

initd-foreverをインストール

# npm install -g initd-forever

initd-foreverでデーモンファイルを生成

# cd /var/www/app_name/
# initd-forever -a /var/www/app_name/ -n app_name
Script daemon file saved to app_name
# ls
app_name

第一引数はNuxt.jsアプリケーションの/を指定、-n の引数はデーモンファイル名となる。カレントディレクトリにapp_nameというファイルが生成される。

ファイルの中身は以下のようになっている。


# cat /var/www/app_name/app_name

#!/bin/bash
### BEGIN INIT INFO
# If you wish the Daemon to be lauched at boot / stopped at shutdown :
#
#    On Debian-based distributions:
#      INSTALL : update-rc.d scriptname defaults
#      (UNINSTALL : update-rc.d -f  scriptname remove)
#
#    On RedHat-based distributions (CentOS, OpenSUSE...):
#      INSTALL : chkconfig --level 35 scriptname on
#      (UNINSTALL : chkconfig --level 35 scriptname off)
#
# chkconfig:         2345 90 60
# Provides:          /var/www/app_name/
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: forever running /var/www/app_name/
# Description:       /var/www/app_name/
### END INIT INFO
#
# initd a node app
# Based on a script posted by https://gist.github.com/jinze at https://gist.github.com/3748766
#

if [ -e /lib/lsb/init-functions ]; then
    # LSB source function library.
    . /lib/lsb/init-functions
fi;

pidFile="/var/run/app_name.pid"
logFile="/var/run/app_name.log"

command="node"
nodeApp="npm run start /var/www/app_name/"
foreverApp="forever"

start() {
    echo "Starting $nodeApp"

    # Notice that we change the PATH because on reboot
   # the PATH does not include the path to node.
   # Launching forever with a full path
   # does not work unless we set the PATH.
   PATH=/usr/local/bin:$PATH
    export NODE_ENV=production
   #PORT=80
   $foreverApp start --pidFile $pidFile -l $logFile -a -d -c "$command" $nodeApp
   RETVAL=$?
}

restart() {
    echo -n "Restarting $nodeApp"
    $foreverApp restart $nodeApp
    RETVAL=$?
}

stop() {
    echo -n "Shutting down $nodeApp"
   $foreverApp stop $nodeApp
   RETVAL=$?
}

status() {
   echo -n "Status $nodeApp"
   $foreverApp list
   RETVAL=$?
}

case "$1" in
   start)
        start
        ;;
    stop)
        stop
        ;;
   status)
        status
       ;;
   restart)
       restart
        ;;
    *)
       echo "Usage:  {start|stop|status|restart}"
       exit 1
        ;;
esac
exit $RETVAL

[start, stop, status, restart]のいずれかの引数を1つ受け取るシェルスクリプトになっている。

デーモンファイルを再配置・権限を付与

# mv app_name /etc/init.d/
# chmod +x /etc/init.d/app_name

他のデーモンと同様、/etc/init.d/に配置し、実行権限を付与した。
Nuxt.jsの場合、このままでは実行してもエラーになってしまうので、デーモンファイル(/etc/init.d/app_name)をNuxt.js用に編集する。

デーモンファイルをNuxt.js用に編集

編集後のファイル


# cat /etc/init.d/app_name

#!/bin/bash
### BEGIN INIT INFO
# If you wish the Daemon to be lauched at boot / stopped at shutdown :
#
#    On Debian-based distributions:
#      INSTALL : update-rc.d scriptname defaults
#      (UNINSTALL : update-rc.d -f  scriptname remove)
#
#    On RedHat-based distributions (CentOS, OpenSUSE...):
#      INSTALL : chkconfig --level 35 scriptname on
#      (UNINSTALL : chkconfig --level 35 scriptname off)
#
# chkconfig:         2345 90 60
# Provides:          /var/www/app_name/
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: forever running /var/www/app_name/
# Description:       /var/www/app_name/
### END INIT INFO
#
# initd a node app
# Based on a script posted by https://gist.github.com/jinze at https://gist.github.com/3748766
#

if [ -e /lib/lsb/init-functions ]; then
    # LSB source function library.
    . /lib/lsb/init-functions
fi;

pidFile="/var/run/app_name.pid"
logFile="/var/run/app_name.log"

command="node"
nodeApp="/usr/bin/npm --prefix /var/www/app_name/ run start"
foreverApp="forever"
appName="app_name"

start() {
    echo -e "Starting $appName\n"
    # Notice that we change the PATH because on reboot
    # the PATH does not include the path to node.
    # Launching forever with a full path
    # does not work unless we set the PATH.
    PATH=/usr/local/bin:$PATH
    export NODE_ENV=production
    #PORT=80
    $foreverApp start --pidFile $pidFile -l $logFile -a -d -c "$command" $nodeApp
    RETVAL=$?
}

restart() {
    stop
    start
    RETVAL=$?
}

stop() {
    if [ -e $pidFile ]; then
        echo -e -n "Shutting down $appName\n"
        cat $pidFile | xargs $foreverApp stop
    fi;
    RETVAL=$?
}

status() {
    if [ -e $pidFile ]; then
        pid=$(cat $pidFile)
        echo -e -n "$appName (pid $pid) is running...\n"
    else
        echo -e -n "$appName is stopped\n"
    fi;
    RETVAL=$?
}

case "$1" in
   start)
        start
        ;;
    stop)
        stop
        ;;
   status)
        status
       ;;
   restart)
       restart
        ;;
    *)
       echo "Usage:  {start|stop|status|restart}"
       exit 1
        ;;
esac
exit $RETVAL

[start, stop, status,restart]を実行できるようにした。

差分ファイル


# cat /etc/init.d/app_name

#!/bin/bash
### BEGIN INIT INFO
# If you wish the Daemon to be lauched at boot / stopped at shutdown :
#
#    On Debian-based distributions:
#      INSTALL : update-rc.d scriptname defaults
#      (UNINSTALL : update-rc.d -f  scriptname remove)
#
#    On RedHat-based distributions (CentOS, OpenSUSE...):
#      INSTALL : chkconfig --level 35 scriptname on
#      (UNINSTALL : chkconfig --level 35 scriptname off)
#
# chkconfig:         2345 90 60
# Provides:          /var/www/app_name/
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: forever running /var/www/app_name/
# Description:       /var/www/app_name/
### END INIT INFO
#
# initd a node app
# Based on a script posted by https://gist.github.com/jinze at https://gist.github.com/3748766
#

 if [ -e /lib/lsb/init-functions ]; then
    # LSB source function library.
    . /lib/lsb/init-functions
 fi;

 pidFile="/var/run/app_name.pid"
 logFile="/var/run/app_name.log"

 command="node"
-nodeApp="npm run start /var/www/app_name/"
+nodeApp="/usr/bin/npm --prefix /var/www/app_name/ run start"    # 起動のコマンドを変更
 foreverApp="forever"
+appName="app_name"    # アプリケーション名を定義、echo出力用

 start() {
-    echo "Starting $nodeApp"
+    echo -e "Starting $appName\n"    # echo出力に改行コードを追加
     # Notice that we change the PATH because on reboot
     # the PATH does not include the path to node.
     # Launching forever with a full path
     # does not work unless we set the PATH.
     PATH=/usr/local/bin:$PATH
     export NODE_ENV=production
     #PORT=80
     $foreverApp start --pidFile $pidFile -l $logFile -a -d -c "$command" $nodeApp
    RETVAL=$?
 }

 restart() {
-    echo -n "Restarting $nodeApp"
-    $foreverApp restart $nodeApp
+    stop     # stopを呼び出す
+    start    # startを呼び出す
     RETVAL=$?
 }

 stop() {
-    echo -n "Shutting down $nodeApp"
-    $foreverApp stop $nodeApp
+    if [ -e $pidFile ]; then    # $pidFileが存在した場合、serviceが起動中であると見なす
+        echo -e -n "Shutting down $appName\n"    # echo出力に改行コードを追加
+        cat $pidFile | xargs $foreverApp stop    # $pidFileにpidをもとにforeverの該当プロセスを停止する
+    fi;
     RETVAL=$?
 }

 status() {
-    echo -n "Status $nodeApp"
-    $foreverApp list
+    if [ -e $pidFile ]; then    # $pidFileが存在した場合、serviceが起動中であると見なす
+        pid=$(cat $pidFile)    # pidを変数に代入する
+        echo -e -n "$appName (pid $pid) is running...\n"    # 起動中ステータスをユーザーに通知する
+    else    # $pidFileが存在しなかった場合、serviceが停止中であると見なす
+        echo -e -n "$appName is stopped\n"    # 停止中ステータスをユーザーに通知する
+    fi;
     RETVAL=$?
 }

 case "$1" in
    start)
         start
         ;;
     stop)
         stop
         ;;
    status)
         status
        ;;
    restart)
        restart
         ;;
     *)
        echo "Usage:  {start|stop|status|restart}"
        exit 1
         ;;
 esac
 exit $RETVAL

ちょっと解説

# forever start --pidFile /var/run/app_name.pid -l /var/run/app_name.log -a -d -c "node" /usr/bin/npm --prefix /var/www/app_name/ run start

これが実行されるコマンド。

  • 非カレントディレクトリにあるnpm scriptは--prefix /var/www/app_name/ run startという感じで呼び出す。
  • npmの指定は、/usr/bin/npmといった具合にフルパスで指定する。コマンド名のみで指定すると$PATH変数を読み込む前にinitで起動されて、npm does not exist.となり実行できない。

serviceコマンドで実行してみる

# service app_name status
app_name is stopped
# service app_name start
Starting app_name

warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: /usr/bin/npm
# service app_name status
app_name (pid 11019) is running...
# service app_name restart
Shutting down app_name
info:    Forever stopped process:
    uid  command script                                                     forever pid   id logfile                  uptime
[0] 74Ci node    /usr/bin/npm --prefix /var/www/html/app_name/ run start 10973   11308    /var/run/app_name.log 0:0:0:0.582
Starting app_name

warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: /usr/bin/npm
# service app_name stop
Shutting down app_name
info:    Forever stopped process:
    uid  command script                                                     forever pid   id logfile                  uptime
[0] eqhV node    /usr/bin/npm --prefix /var/www/html/app_name/ run start 11354   11444    /var/run/app_name.log 0:0:0:0.850
# service app_name restart
Starting app_name

warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: /usr/bin/npm

start, stop, status, restartが実行できている。
statusは起動時、停止時に想定した挙動となっていて、restartも起動時、停止時に想定した挙動となっている。

chkconfigで自動起動を設定してみる

# chkconfig app_name --add
# chkconfig app_name on
# chkconfig app_name --list
app_name    0:off   1:off   2:on    3:on    4:on    5:on    6:off

これでrunlevelが[2, 3, 4, 5]でOSが起動する際にNuxt.jsアプリケーションが自動起動されるようになった。

参考リンク

まとめ

シェルスクリプトを読み書きできる人なら問題なくできるっぽい。
このスクリプトを改造したら、foreverじゃなくても、いろいろ使えそう。

43
39
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
39