KCF Labo Blog

KDDI Commerce Forwardの開発ブログ

Spring Boot 2 アプリケーションのデーモン化

KCF Laboの紹介

はじめまして。エンジニアの土田です。

本日からKCF Laboメンバーの知見やLaboの様子などを、ブログを通してお伝えしていきますので、お付き合いいただけると幸いです!

ちなみに、KCFは私達が所属する会社であるKDDIコマースフォワードの略称で、

Laboは2018年2月にできた、開発部隊の拠点のことを指しています。

Spring Boot 2 アプリケーションの起動

現在、私のチームではSpring Boot 2を利用して、現行システムのリプレイスを進めています。

ローカルでの開発環境は以下のようになっており、プロジェクトの構成はGradleで管理しているため、動作を確認する場合はgradle bootRunでサーバを起動して実施しています。

f:id:seri_wb:20180413161556p:plain

しかし、アプリケーションをサーバで動作させるには、アプリケーションをデーモンプロセスとして起動する必要があるので、 ローカルと同じように、というわけにはいかなくなります。

今回はそのSpring Boot 2 アプリケーションのデーモン化方法についてお話したいと思います。

sample-appの環境情報

今回の話に関連する環境情報は、以下になります。

  • CentOS: 7系
  • Spring Boot: 2.0.1.RELEASE
  • Gradle: 4.6
  • Kotlin: 1.2.31
  • Java: 1.8.0.161

また、アプリケーションの名前は「sample-app」として進めていきます。

デーモン化可能なjarを作成

Spring BootのGradleプロジェクトでbuildコマンドを実施すると、java -jarでアプリケーションとして起動可能なjarファイルが作成されますが、デーモン化も可能なjarにするには、以下の記述をbuild.gradleに追記して、ビルドする必要があります。

bootJar {
    launchScript()
}

ちなみにbuild.gradleは、Spring Initializrをベースに作成するのがおすすめです

アプリケーションの配置

jarファイルを作成したら、アプリケーションを起動させるサーバに配置します。

ここでは/var/lib/app/sample-app/currentディレクトリ配下に配置するものとします。

jarファイルを配置したら、jarファイル名と同じ名前のconfファイルを作成します。

sample-app.jarという名前ならば、sample-app.confという名前になります

confファイルにはアプリケーションを起動させるオプションを記述します。 Spring Profilesを使って環境毎に設定を切り替えている場合は、RUN_ARGSに--spring.profiles.active=環境名を渡すと指定の環境で起動することができます。

  • sample-app.conf
JAVA_OPTS="-Xms4096M -Xmx4096M -Xloggc:/var/log/app/sample-app/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/app/sample-app/heap/dump.log -XX:ErrorFile=/var/log/app/sample-app/java_error%p.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M"
RUN_ARGS="--spring.profiles.active=prd"

JAVA_OPTSに書いている各種オプションは必須ではないのですが、このようなオプションを付けておくと障害時の解析に役立つと思います。

1点気をつけるところがあるとすれば、LOG_FOLDERというログファイルの出力先オプションがあるのですが、 これはアプリケーション内のLogback等の設定に負けるので、Logger使用時にはLoggerの設定でログ出力先を指定するようにしてください。

アプリケーションのサービス登録

次に、アプリケーションをCentOSサーバにサービス登録するため、serviceファイルを作成します。

  • /etc/systemd/system/sample-app.service
[Unit]
Description = Sample SpringBoot WebApplication daemon
After = syslog.target

[Service]
ExecStart = /var/lib/app/sample-app/current/sample-app.jar
Restart = always
Type = simple
User = webapp
Group = webapp
SuccessExitStatus = 143

[Install]
WantedBy = multi-user.target

各項目の内容は任意ですが、UserとGroupにはアプリケーションを動作させるユーザの情報を記載してください。

アプリケーションの管理

ここまでの作業を終えれば、systemctlでアプリケーションを管理することができるようになります。 systemctl start サービス名でアプリケーションを起動すると、アプリケーションはデーモンプロセスとして実行されます。

■ 起動
sudo systemctl start sample-app
■ 停止
sudo systemctl stop sample-app
■ 状態確認
sudo systemctl status sample-app
■ 再起動
sudo systemctl restart sample-app

以上でデーモン化完了です。

Ansibleでのサービス登録

これまでの内容を各サーバに手動で実施するのは面倒なので、実際には以下のようなAnsibleのRoleを作成して利用しています。

  • roles/app/sample-app/tasks/main.yml
---
- name: check and create application directory
  file: path="{{ application_dir }}/sample-app" state=directory recurse=yes owner={{ app_user }} group={{ app_user }} mode=0777
  become: yes
  tags:
    - app
    - sample-app

- name: add sample-app service at system
  template: src=sample-app.service.j2 dest=/etc/systemd/system/sample-app.service owner=root group=root mode=0755
  become: yes
  tags:
    - app
    - sample-app

- name: check and create application log directory
  file: path="{{ app_log_dir }}/sample-app" state=directory recurse=yes owner={{ app_user }} group={{ app_user }} mode=0755
  become: yes
  tags:
    - app
    - sample-app
    - log

- name: check and create heap dump log directory
  file: path="{{ app_log_dir }}/sample-app/heap" state=directory recurse=yes owner={{ app_user }} group={{ app_user }} mode=0755
  become: yes
  tags:
    - app
    - sample-app
    - log

- name: enable automatically start sample-app.service
  systemd:
    name: sample-app.service
    enabled: yes
  become: yes
  tags:
    - app
    - sample-app
    - systemd
  • roles/app/sample-app/temlates/sample-app.service.j2
[Unit]
Description = Sample SpringBoot WebApplication daemon
After = syslog.target

[Service]
ExecStart = {{ application_dir }}/sample-app/current/sample-app.jar
Restart = always
Type = simple
User = {{ app_user }}
Group = {{ app_user }}
SuccessExitStatus = 143

[Install]
WantedBy = multi-user.target

パラメータ値はgroup_varsに環境毎のファイルを作成し、以下のように定義しています。

application_dir: /var/lib/app
app_log_dir: /var/log/app
app_user: webapp

デーモン化完了の次は

これでSpring Boot 2のアプリケーションをサーバで起動することができましたね!お疲れ様です。

バージョン2からデーモン化の方法が少し変わっていたので、記事の話題にしてみました。 まだまだリリースされたばかりで2系の情報は少ないですが、Java界隈では使い勝手の良いフレームワークなので、KCFでもネタにして盛り上げていきたいです。

次は本稿ではさらっと流したデプロイの話を書く予定ですので、そちらもよろしくお願いします。