はじめに
Spring Bootはバージョン1.3.0以降、Executable JarとしてJarファイルに固めるだけでなく、実行スクリプトがJarファイル内に埋め込まれたFully Executable Jarが作成できる。
サーバに常駐させるため、普通のJarファイルであれば起動スクリプトを書く必要があるが、Fully Executable Jarであれば不要となる。
通常のJarファイルの起動スクリプトが公式に提供されていない状況だが、Fully Executable Jarの登場によって、実質的に起動スクリプトが公式に提供されたことになる。
これによって、簡単にserviceコマンドでアプリをdeamon起動することができるようになった。
ここでは、ビルド方法と次の環境にリリースする場合の構築手順と解説を記載する。
※基本はhttp://docs.spring.io/spring-boot/docs/1.3.5.RELEASE/reference/htmlsingle/#deployment-installに書いてある通り。
環境
CentOS 6.8
Java8
Spring Boot 1.3.5
アプリ名:myapp.jar
アプリ用ユーザ名:myappusr
ビルド方法
pom.xmlにspring-boot-maven-pluginというbuildプラグインを追加し、executableをtrueにする。
falseを設定するとExecutable Jarファイルを作成し、trueを設定するとFully Executable Jarファイルを作成してくれる。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
構築手順
[root@host ~]# #アプリ用に任意のディレクトリを作成する。jarにworking directoryとして利用される。
[root@host ~]# mkdir /usr/local/bin/myapp
[root@host ~]# chown myappusr.myappusr /usr/local/bin/myapp
[root@host ~]#
[root@host ~]# #アプリを配置する。
[root@host ~]# cp /tmp/myapp.jar /usr/local/bin/myapp/
[root@host ~]# #myapp.jarの所有者がmyapp.jarの実行ユーザになるので、rootではなくアプリ用ユーザにする。※1
[root@host ~]# chown myappusr.myappusr /usr/local/bin/myapp/myapp.jar
[root@host ~]# #Fully Executable Jarはスクリプトが内蔵されているため、実行可能ファイルである必要があり、最低限、権限xを所有者につける。
[root@host ~]# chmod 500 /usr/local/bin/myapp/myapp.jar
[root@host ~]#
[root@host ~]# #jarファイルと同名のconfファイルを作成し、環境変数やJVMに渡すパラメータを設定する。※2
[root@host ~]# echo -e 'export LANG="ja_JP.UTF-8"\nJAVA_OPTS="-Dspring.profiles.active=development"' > /usr/local/bin/myapp/myapp.conf
[root@host ~]# #confファイルの中身確認
[root@host ~]# cat /usr/local/bin/myapp/myapp.conf
export LANG="ja_JP.UTF-8"
JAVA_OPTS="-Dspring.profiles.active=development"
[root@host ~]#
[root@host ~]# #deamon起動のため/etc/init.d/に登録
[root@host ~]# ln -s /usr/local/bin/myapp/myapp.jar /etc/init.d/myapp
[root@host ~]# #自動起動のためchkconfigに登録
[root@host ~]# chkconfig --add myapp
[root@host ~]# #起動
[root@host ~]# service myapp start
Started [3061]
[root@host ~]#
[root@host ~]# #起動確認
[root@host ~]# service myapp status
Running [3061]
[root@host ~]# #起動確認2
[root@host ~]# ps -ef | grep jar
myappusr 3061 1 3 11:58 ? 00:01:19 /usr/bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -Dspring.profiles.active=development -jar /usr/local/bin/myapp/myapp.jar
[root@host ~]#
[root@host ~]# #ログ確認※3
[root@host ~]# ll /var/log/myapp.log
-rw-r--r--. 1 myappusr root 402 6月 23 12:36 2016 /var/log/myapp.log
[root@host ~]# #PID確認※4
[root@host ~]# ll /var/run/myapp/ -d
drwxr-xr-x. 2 myappusr root 4096 6月 23 12:36 2016 /var/run/myapp/
[root@host ~]# ll /var/run/myapp/myapp.pid
-rw-r--r--. 1 myappusr root 5 6月 23 12:36 2016 /var/run/myapp/myapp.pid
解説
※1)myapp.jarの所有者がmyapp.jarの実行ユーザになるので、rootではなくアプリ用ユーザにする。
http://docs.spring.io/spring-boot/docs/1.3.5.RELEASE/reference/htmlsingle/#deployment-initd-service-securingにセキュリティ面を考慮した設定方法が列挙されている。
次の二点は、構築手順で達成できている。
- myapp.jarの所有者をrootからmyappusrに変更する
- myapp.jarの権限を500に変更する
- myapp.confの所有者をrootにする(rootで構築しているため、自動で所有者がrootになっている)
他は設定していないので、必要に応じてセキュリティを高めていく必要がある。
- myappusrのシェルを/usr/sbin/nologinにする
- jarファイルにchattr +i
- confファイルにchmod 400
※2)jarファイルと同名のconfファイルを作成し、環境変数やJVMに渡すパラメータを設定する。
jarファイルと同じディレクトリに同名のconfファイルを置くと、起動時に読み込んでくれる。
読み込む方法は、jarファイルの初めの部分がシェルスクリプトになっているので、jarファイルをlessして見るとわかる。
[myappusr@host myapp]$ less myapp.jar
#!/bin/bash
#
# . ____ _ __ _ _
# /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
# ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
# \\/ ___)| |_)| | | | | || (_| | ) ) ) )
# ' |____| .__|_| |_|_| |_\__, | / / / /
# =========|_|==============|___/=/_/_/_/
# :: Spring Boot Startup Script ::
#
中略
# Source any config file
configfile="$(basename "${jarfile%.*}.conf")"
# shellcheck source=/dev/null
[[ -r "${jarfolder}/${configfile}" ]] && source "${jarfolder}/${configfile}"
中略
# Build actual command to execute
command="$javaexe -Dsun.misc.URLClassPath.disableJarChecking=true $JAVA_OPTS -jar $jarfile $RUN_ARGS $*"
中略
if [ $USE_START_STOP_DAEMON = true ] && type start-stop-daemon > /dev/null 2>&1; then
arguments=(-Dsun.misc.URLClassPath.disableJarChecking=true $JAVA_OPTS -jar $jarfile $RUN_ARGS "$@")
start-stop-daemon --start --quiet \
--chuid "$run_user" \
--name "$identity" \
--make-pidfile --pidfile "$pid_file" \
--background --no-close \
--startas "$javaexe" \
--chdir "$working_dir" \
-- "${arguments[@]}" \
>> "$log_file" 2>&1
await_file "$pid_file"
else
su -s /bin/sh -c "$command >> \"$log_file\" 2>&1 & echo \$!" "$run_user" > "$pid_file"
fi
source "${jarfolder}/${configfile}"
となっているため、環境変数を設定したければexportを、JVMに渡す引数を設定したければJAVA_OPTSに値を設定すればいい。
今回は以下の二つを設定した。
export LANG="ja_JP.UTF-8"
JAVA_OPTS="-Dspring.profiles.active=development"
JAVA_OPTS="-Dspring.profiles.active=development"
Spring Bootの実行環境をJVM引数で渡すことができ、propertiesファイルの切り替え等ができるため、おそらくどのプロジェクトでも必要になる引数だろう。
開発環境であればdevelopment、ステージング環境であればstaging、本番環境であればproductionなどの引数を渡す。export LANG="ja_JP.UTF-8"
文字コードを設定した理由は、今回の環境がCentOSというところにある。
/etc/init.dにあるスクリプトを直接実行する場合と異なり、manによれば、serviceコマンドで実行するとプログラムを起動する際に環境変数LANGとTERM以外が引き継がれない。ENVIRONMENT
LANG, TERM
The only environment variables passed to the init scripts.しかし、CentOSではこの記述が当てはまらず、LANGも引き継がれない。
原因は/sbin/serviceスクリプトを見るとわかるが、env -iで環境変数をクリアしており、LANGを再設定してないから。
参考:http://heartbeats.jp/hbblog/2013/06/service-start-stop.htmlLANG="ja_JP.UTF-8"が設定されないと、Javaが日本語のファイルを扱う際に文字化けを起こしてしまうため、Red HatやFedoraも含めCentOS系のディストリを使用する場合は、confファイル内でLANG変数をexportしなければならない。
Ubuntu系を使用する場合でも、LANGの設定があることでバグを起こすわけではないので、一律この設定を入れてもいいかもしれない。
他にもconfファイルで設定できる項目はたくさんあるので、公式ドキュメントを確認してほしい。
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/deployment-install.html#deployment-script-customization
※3)ログ確認
ログファイルは所定の場所に出力される。
出力場所を変えたければconfファイルで設定ができる。
※4)PID確認
PIDファイルは所定の場所に出力される。あらかじめPIDファイルが格納されるディレクトリを作る必要はない。
出力場所を変えたければconfファイルで設定ができる。