systemd で Spring Boot アプリケーションのプロセス管理をする

## 概要

- シンプルな Spring Boot アプリケーションを systemd でプロセス管理する
- systemd によって起動・停止・OS再起動時の自動起動などが可能になる
- 今回の環境: Ubuntu 19.10 Eoan Ermine + Java 11 + Spting Boot 2.2.6

## Spring Boot アプリケーションを用意

サンプルとしてシンプルな Spring Boot アプリケーションを用意する。

### ファイル一覧

```
├── build.gradle
├── settings.gradle
└── src
    └── main
        └── java
            └── com
                └── example
                    └── MyApp.java
```

### build.gradle

Gradle のビルド設定ファイル。

```groovy
plugins {
  id 'org.springframework.boot' version '2.2.6.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
}

group = 'com.example'
version = '0.0.1'
sourceCompatibility = '11'

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web'
}
```

### settings.gradle

Gradle のビルド設定ファイル。

```groovy
rootProject.name = 'myapp'
```

### src/main/java/com/example/MyApp.java

サンプルとなる Spring Boot アプリケーションのソースコード。
HTTP レスポンスとして JSON を返す。

```java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@SpringBootApplication
@RestController
public class MyApp {

  public static void main(String[] args) {
    SpringApplication.run(MyApp.class, args);
  }

  @GetMapping("/")
  public Map index() {
    return Map.of("message", "Hello, world.");
  }
}
```

### Gradle でビルドして JAR ファイルを作成

```
$ gradle bootJar
```

```
$ ls build/libs/myapp-0.0.1.jar
build/libs/myapp-0.0.1.jar
```

## 起動用シェルスクリプトを用意

今回は起動時に柔軟に設定ができるように起動用のシェルスクリプトを用意する。
任意のファイル名 startup.sh で以下ような内容を保存しておく。

```sh
#!/bin/sh

# 同じディレクトリ内の JAR ファイル
java -jar `dirname $0`/myapp-0.0.1.jar --server.port=8888
```

Spring Boot ではシェルスクリプトが不要な JAR を使用することも可能なので、必要に応じてこちらを使うのも良い。

[Spring Boot アプリケーションのデプロイ \- ドキュメント](https://spring.pleiades.io/spring-boot/docs/2.2.6.RELEASE/reference/html/deployment.html#deployment-install)

> 完全に実行可能な jar は、ファイルの先頭に追加のスクリプトを埋め込むことで機能します。

## systemd の設定

Spring Boot の公式ドキュメントに具体的な設定方法が載っているので参考になる。

[Spring Boot アプリケーションのデプロイ \- ドキュメント](https://spring.pleiades.io/spring-boot/docs/2.2.6.RELEASE/reference/html/deployment.html#deployment-systemd-service)

> systemd は System V init システムの後継であり、現在多くの最新の Linux ディストリビューションで使用されています。init.d スクリプトを systemd で引き続き使用できますが、systemd の「サービス」スクリプトを使用して Spring Boot アプリケーションを起動することもできます。

### 設定ファイルを設置

サービスユニット用の設定ファイル myapp.service を作成。

```
[Unit]
Description=This is my application.
After=syslog.target

[Service]
User=foo
ExecStart=/home/foo/myapp/startup.sh
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target
```

設定ファイルを /etc/systemd/system に置く。
今回はファイル自体は home ディレクトリ以下に置き、シンボリックリンクを張っている。

```
$ sudo ln -s /home/foo/myapp/myapp.service /etc/systemd/system/myapp.service
```

systemctl list-unit-files コマンドで設定できていることを確認。

```
$ systemctl list-unit-files --type=service | grep myapp
myapp.service                          linked
```

### サービスを有効にする

systemctl enable コマンドでサービスを有効にする。
これで systemctl コマンドによる起動・停止や、OS再起動時の自動起動などが可能になる。

```
$ sudo systemctl enable myapp
Created symlink /etc/systemd/system/multi-user.target.wants/myapp.service → /home/foo/myapp/myapp.service.
```

### 起動確認

systemctl start コマンドでサービスを起動。

```
$ sudo systemctl start myapp
```

systemctl status コマンドでサービスの状態を確認する。ログも表示される。

```
$ sudo systemctl status myapp
● myapp.service - My Application
   Loaded: loaded (/home/foo/myapp/myapp.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2020-04-24 05:19:49 JST; 2s ago
 Main PID: 3822 (startup.sh)
    Tasks: 20 (limit: 2320)
   Memory: 150.3M
   CGroup: /system.slice/myapp.service
           ├─3822 /bin/sh /home/foo/myapp/startup.sh
           └─3825 java -jar /home/foo/myapp/myapp-0.0.1.jar --server.port=8888

 4月 24 05:19:49 my-foo-host systemd[1]: Started My Application.
 4月 24 05:19:50 my-foo-host startup.sh[3822]:   .   ____          _            __ _ _
 4月 24 05:19:50 my-foo-host startup.sh[3822]:  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
 4月 24 05:19:50 my-foo-host startup.sh[3822]: ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 4月 24 05:19:50 my-foo-host startup.sh[3822]:  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
 4月 24 05:19:50 my-foo-host startup.sh[3822]:   '  |____| .__|_| |_|_| |_\__, | / / / /
 4月 24 05:19:50 my-foo-host startup.sh[3822]:  =========|_|==============|___/=/_/_/_/
 4月 24 05:19:50 my-foo-host startup.sh[3822]:  :: Spring Boot ::        (v2.2.6.RELEASE)
```

Spring Boot アプリケーションが動作していることを確認。

```
$ curl http://localhost:8888/
{"message":"Hello, world."}
```

## 参考資料

- [Spring Boot アプリケーションのデプロイ \- ドキュメント](https://spring.pleiades.io/spring-boot/docs/2.2.6.RELEASE/reference/html/deployment.html)
- [Ubuntu – eoan の systemd パッケージに関する詳細](https://packages.ubuntu.com/eoan/systemd)
- [systemctl](https://www.freedesktop.org/software/systemd/man/systemctl.html)
- [systemd\.service](https://www.freedesktop.org/software/systemd/man/systemd.service.html)