こんにちは、かつコーチです。
ローカル環境で./gradlew bootRunを使って動作確認できるようになると、次に気になるのが「このアプリをどうやって本番のサーバーで動かすのか」という疑問です。
筆者も最初は、Spring Bootのアプリはどこかにアップロードしてサーバー側で特別な環境を整えないと動かないものだと思い込んでいました。
実際にはSpring Bootには、アプリケーションと実行に必要なライブラリをすべて1つにまとめる「Fat JAR」という仕組みがあり、Javaさえ動くサーバーであればそのまま実行できます。
この記事では、jarファイルのビルドからサーバーでの起動までの一連の流れを解説します。
jarファイルとは?
Fat JAR(実行可能jar)とは何か
通常のJavaのjarファイルは、自分のプロジェクトのクラスファイルだけをまとめたものです。
これを実行するには、依存しているライブラリ(Spring本体やJPAなど)を別途クラスパスに指定する必要があります。
Spring BootのbootJarタスクで作られるjarは、依存ライブラリもすべて内部に含んだ「Fat JAR(実行可能jar)」と呼ばれる形式です。
このjarファイル1つと、Javaの実行環境(JRE)さえあれば、他に何も用意せずアプリケーションを起動できます。
なぜjarへのビルドが必要なのか
開発中に使うbootRunは、ソースコードから直接アプリケーションを起動する開発用のコマンドです。
本番サーバーにはソースコード一式やGradleの実行環境を持ち込む必要はなく、ビルド済みのjarファイル1つだけを配置すれば十分です。
- ビルド成果物(jar)は1ファイルにまとまっているため、サーバーへの転送や管理がシンプル
- ソースコードを本番サーバーに置かずに済むため、セキュリティ上も望ましい
- CI/CDパイプラインで「ビルド」と「デプロイ」を明確に分離できる
基本の書き方・実装手順
bootJarタスクでjarをビルドする
Gradleプロジェクトの場合、以下のコマンドでjarファイルをビルドできます。
./gradlew bootJar
ビルドが成功すると、build/libs/ディレクトリにアプリ名-バージョン.jarという名前でファイルが生成されます。
build/libs/blog-0.0.1-SNAPSHOT.jar
Mavenの場合は以下のコマンドです。
./mvnw clean package
target/ディレクトリに同様のjarファイルが生成されます。
ビルドしたjarをローカルで起動して確認する
サーバーに転送する前に、ローカル環境でjarファイルが正常に起動するかを必ず確認します。
java -jar build/libs/blog-0.0.1-SNAPSHOT.jar
bootRunと同じようにアプリケーションが起動し、http://localhost:8080でアクセスできれば成功です。
このステップを飛ばしていきなり本番サーバーにデプロイすると、環境依存の問題なのかビルド自体の問題なのか切り分けが難しくなるため、必ずローカルでの起動確認を挟みましょう。
サーバーにjarを転送して起動する
scpなどでjarファイルをサーバーに転送し、サーバー側でJavaコマンドを実行します。
# ローカルからサーバーへ転送
scp build/libs/blog-0.0.1-SNAPSHOT.jar user@example.com:/opt/blog/
# サーバー側で起動
ssh user@example.com
cd /opt/blog
java -jar blog-0.0.1-SNAPSHOT.jar
このままだとSSHセッションを切ると同時にプロセスも終了してしまうため、実運用では次に説明するバックグラウンド実行の仕組みが必要になります。
よくあるつまずきポイント・エラー対処
❌ Before:SSHを切断するとアプリが止まってしまう
筆者が初めて手動デプロイを試したとき、java -jarコマンドを実行したままSSHのターミナルを閉じてしまい、アプリケーションが強制終了してしまうという失敗をしました。
Connection to example.com closed.
SSHセッションに紐づいたフォアグラウンドプロセスとしてJavaを起動していたため、親プロセスの終了と同時に子プロセスも終了してしまったのが原因でした。
✅ After:systemdでサービスとして常駐させる
Linuxサーバーでは、systemd(サービスの起動・停止・自動再起動を管理する仕組み)を使ってjarをサービス化するのが定番です。
# /etc/systemd/system/blog.service
[Unit]
Description=Blog Spring Boot Application
After=network.target
[Service]
User=blog
ExecStart=/usr/bin/java -jar /opt/blog/blog-0.0.1-SNAPSHOT.jar
SuccessExitStatus=143
Restart=on-failure
[Install]
WantedBy=multi-user.target
このファイルを配置したあと、以下のコマンドでサービスとして起動・自動起動設定ができます。
sudo systemctl daemon-reload
sudo systemctl enable blog
sudo systemctl start blog
sudo systemctl status blog
systemd管理下であれば、SSHセッションが切れてもアプリケーションは動き続けます。
サーバーの再起動時にもenableしておいたサービスは自動的に立ち上がるため、手動での起動作業も不要になります。
応用・一歩先の使い方
ログをファイルに出力する
systemd経由の起動では、標準出力のログはjournalctlで確認できますが、専用のログファイルに出力する設定も併用すると管理しやすくなります。
# application.properties
logging.file.name=/var/log/blog/application.log
logging.file.max-size=10MB
logging.file.max-history=7
logging.file.max-sizeとmax-historyを設定しておくと、ログファイルが無限に肥大化するのを防げます。
ビルド番号やGitのコミットハッシュを埋め込む
「今サーバーで動いているのはどのバージョンのアプリか」を確認できるようにしておくと、障害対応の際に役立ちます。
// build.gradle
springBoot {
buildInfo()
}
buildInfo()を有効にすると、/actuator/infoエンドポイント(spring-boot-starter-actuatorが必要)でビルド時刻やGitのコミット情報を確認できるようになります。
実際に本番障害の切り分けをしていた際、この情報のおかげで「デプロイ漏れではなくロジック側のバグだった」とすぐに判断できたことがあります。
まとめ
この記事のポイント
bootJar(Gradle)やmvnw package(Maven)で、依存ライブラリを含むFat JARをビルドできる- サーバーには
java -jarさえ実行できる環境があれば、アプリを動かせる - SSHセッションに紐づいたフォアグラウンド実行では、切断時にアプリも停止してしまう
systemdでサービス化すると、SSH切断後もアプリが動き続け、再起動時の自動起動も設定できるspringBoot { buildInfo() }でビルド情報を埋め込むと、障害対応時にバージョンを特定しやすくなる
次に読むべき記事
本番・開発でDBの接続先などを切り替えたい場合は、次の「環境ごとにapplication.propertiesを切り替える」で解説します。
タグ: Spring Boot, 初心者向け, デプロイ