リモートデバッグ可能なNginx, Spring Boot, MySQLの開発環境をDockerで作った

# 前置き
最近、WebサイトをSpring Bootで開発しています。以前に投稿した[記事](https://qiita.com/items/c068e499c43276c55a32)のような開発環境が欲しくなってきましたので調査しました。前回とほぼ同じ形式で執筆します。

# 動作環境
|　　　||
|---|---|
| OS | macOS Catalina 10.15.5 |
| Docker | docker desktop community 2.3.0.3 (45519) |
| Spring Tool Suite | Version: 4.5.1.RELEASE |

# Spring Bootプロジェクト
InteliJ + Kotlin + gradleとしたいところですが、現在携わっている環境に近い構成でやっていこうと思います。
モダンJavaだとこの組み合わせ減ってると思います:sob::sob:

* Spring Boot 2.2
* Java OpenJDK 11
* STS 4
* Maven 3.6.3

# 構築イメージ
まずは構築する環境を説明します。
<img alt="構成の図解.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/c2e8d279-665f-bf9f-6840-125f58a16816.png">

以下のコンテナを作成します。

* MySQL
  * ホストOSのMySQL Workbenchでアクセスできる(localhost:3306)
* Spring Boot
  * ホストOSのブラウザでアクセスできる(localhost:8080)
  * STS(Eclipse)からリモートデバッグできる(localhost:5005)
* Nginx
  * HTTPSでアクセスできる(https://devnokiyo.example.com)
  * ただし、GitHubにソースコードを公開する関係で自己署名SSL証明書)

もちろん、コンテナ間も通信を行います。

# 構成
[GitHub](https://github.com/devnokiyo/springboot-dev-docker-template)に公開しています。併せてご覧ください。
前述の記事同様にDocker周りだけを管理したいディレクトリと永続化だけを管理したいディレクトリに分けました。
以降、粛々とファイルとその説明が続きます。「とにかくGitHubのコードを動かしたい」方は[こちら](#実行してみましょう)まで飛んでください:airplane_departure::airplane_departure::airplane_departure:

```sh
$ tree
├── README.md
├── docker                          # DockerやDocker Compose
│   ├── containers                   # 各コンテナ(イメージ)
│   │   ├── mysql                     # MySQL 5.7
│   │   │   ├── Dockerfile             # MySQL 5.7のDockerファイル
│   │   │   ├── initialize_data.sql    # 初期セットアップでユーザとサンプルデータを作成するスプリプト
│   │   │   └── my.cnf                 # 初期セットアップで反映するmy.cnf
│   │   ├── nginx                     # Nginx　1.19.0
│   │   │   ├── Dockerfile             # NginxのDockerファイル
│   │   │   └── nginx.conf             # 初期セットアップで反映するnginx.conf
│   │   └── spring                    # OpenJDK 11 (Spring Boot構築用)
│   │       └── Dockerfile             # Spring Boot構築用のDockerファイル
│   ├── docker-compose.yml          # Docker Composeファイル
│   └── environments                # 環境変数定義 
│       ├── common.env               # 各コンテナ共通
│       └── db.env                   # DB接続用MySQL関連
└── volumes                         # 永続化するリソース
    ├── app                          # Spring Bootのプロジェクト (以下、特筆点するディレクトリ/ファイルのみコメント)
    │   ├── .m2                       # Mavenのローカルリポジトリ
    │   ├── mvnw                      # Maven Wrapper 今回はこれを使ってSpring Bootを起動する
    │   └── src                        # ソースコード
    │       └── main
    │           └── resources            # この配下にstaticディレクトリを作成しない (静的ファイルはNginxで返す)
    ├── db                           # MySQLのデータ このディレクトリは最初は無し
    └── web                          # Nginxのファイル
        ├── ssl                       # SSL証明書
        │   ├── privkey.pem            # 秘密鍵
        │   └── server.crt             # サーバー証明証
        └── static                    # 静的ファイル置き場
```

# Composeファイル
```yml:docker/docker-compose.yml
version: '3'
services:                                          # 各コンテナ(サービス)
  db:                                               # MySQLのコンテナ 「db」と命名
    build: containers/mysql                          # Dockerファイルのパス
    env_file:                                        # 環境変数
      - ./environments/common.env                     # 各コンテナ共通
      - ./environments/db.env                         # DB接続用MySQL関連
    volumes:                                         # 永続化
      - ../volumes/db/data:/var/lib/mysql             # MySQLのデータ
    ports:                                           # 開放ポート
      - 3306:3306                                     # ホストOSのWorkBenchでDBを参照する目的
  app:                                              # Spring Bootのコンテナ 「app」と命名
    build: containers/spring                         # Dockerファイルのパス
    env_file:                                        # 環境変数
      - ./environments/common.env                     # 各コンテナ共通
      - ./environments/db.env                         # DB接続用MySQL関連
    # 実行するコマンド(後述)
    command: ./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005"
    volumes:                                         # 永続化
      - ../volumes/app:/app                           # Spring Bootのプロジェクト
      - ../volumes/app/.m2:/root/.m2                  # Mavenのローカルリポジトリ
    ports:                                           # 開放ポート
      - 8080:8080                                     # ホストOSからNginxを通さずTomcatを直接参照する目的
      - 5005:5005                                     # IDEでリモートデバッグする目的
    depends_on:                                      # 起動する順番
      - db                                            # 「db」の後で起動
  web:                                              # Nginxのコンテナ 「web」と命名
    build: containers/nginx                          # Dockerファイルのパス
    env_file:                                       # 環境変数
      - ./environments/common.env                    # 各コンテナ共通
    volumes:                                        # 永続化
      - ../volumes/web/static:/usr/share/nginx/www/  # 静的ファイル (Spring Bootプロジェクトのresouce/staticには配置しない)
      - ../volumes/web/ssl:/etc/nginx/cert/          # SSL証明書
      - ../volumes/web/log:/var/log/nginx/           # Nginxのログ
    ports:                                          # 開放ポート
      - 443:443                                      # HTTPS この開発環境はHTTPSのみ想定
    depends_on:                                     # 起動する順番
      - app                                          # 「app」の後で起動

```

# db(MySQL)コンテナ
## Dockerファイル
```dockerfile:docker/containers/mysql/Dockerfile
# MySQL 5.7
FROM mysql:5.7

# 初期セットアップで利用するmy.cnfをイメージへコピー
# アーカイブを展開する必要などが無ければADDで無くてCOPYで良い。
COPY my.cnf /etc/mysql/conf.d

# 初期セットアップで実行したいスクリプトをイメージへコピー
COPY initialize_data.sql /docker-entrypoint-initdb.d
```
## コピーするファイルの概要
| ホスト | イメージ | 概要 |
|---|---|---|
| docker/containers/mysql/my.cnf | /etc/mysql/conf.d/ | 文字コード |
| docker/containers/mysql/initialize_data.sql | /docker-entrypoint-initdb.d/ | Spring Bootアプリ向けDBアカウント/サンプルデータ |

## Docker Comopseから設定される環境変数
```docker/environments/common.env
TZ=Asia/Tokyo
```
```docker/environments/db.env
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=spring
MYSQL_PASSWORD=spring
```
## Docker Comopseから設定される永続化
| ホスト | コンテナ | 概要 |
|---|---|---|
| volumes/db/data | /var/lib/mysql | MySQLのデータ |

# app(Spring Boot)コンテナ
## Dockerファイル
```dockerfile:docker/containers/spring/Dockerfile
FROM openjdk:11

# 永続化でマウントされるパスをワーキングディレクトリに指定
WORKDIR /app
```
## Docker Comopseから設定される環境変数
```docker/environments/common.env
TZ=Asia/Tokyo
```
```docker/environments/db.env
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=spring
MYSQL_PASSWORD=spring
```
## Docker Comopseから設定される永続化
| ホスト | コンテナ | 概要 |
|---|---|---|
| volumes/app/ | /app | Spring Bootのプロジェクト<br>GitHubに公開しているものは予めサンプルアプリが入っています) |
| volumes/app/.m2 | /root/.m2 | Mavenのローカルリポジトリ <br> ./mvnw cleanを実行するとプラグイン/ライブラリなどを毎回ダウンロードしてしまうことを防ぎます。 |
## Docker Comopseのcommand
こちらのコマンドについて少し補足します。

```bash
./mvnw clean spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:5005"
```

| コマンド | 概要 |
|---|---|
| ./mvnw | `Java -jar`による起動は開発中のコードが更新されたときの自動リロードが無効になってしまうので、Mavenで起動することにしました。Maven WrapperがあればMavenをインストールする必要がないので、`mvnw`を採用しました。|
| address=*:5005 | JDWPのポートを指定しますが、 ホストOSからコンテナへアクセスするには`*:5005`とする必要があります。ポート番号しか書いていないネット情報が多いのでご注意ください:skull_crossbones::skull_crossbones: |



# web(Nginx)コンテナ
## Dockerファイル
```dockerfile:docker/containers/nginx/Dockerfile
FROM nginx:1.19.0

# 初期セットアップで反映するファイルをコピー
COPY nginx.conf /etc/nginx/conf.d/app.conf
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
```

## コピーするファイルの概要
| ホスト | イメージ | 概要 |
|---|---|---|
| docker/containers/nginx/nginx.conf | /etc/nginx/conf.d/app.conf | 後述 |

## WEBサーバーの設定
トリッキーな設定は無いと思いますが簡単に補足します。
GitHubに公開しているものはSSL証明書については「*.example.com」の自己署名SSL証明書(所謂「オレオレ証明書」)を利用しています。筆者の環境ではLet's EncryptのSSL証明書を利用しています。

```nginx:docker/containers/nginx/nginx.conf
server {
  listen 443 ssl;
  server_name devnokiyo.example.com;

  ssl_certificate     /etc/nginx/cert/server.crt;
  ssl_certificate_key /etc/nginx/cert/privkey.pem;
  ssl_prefer_server_ciphers on;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /app/public;
  try_files $uri /;
  client_max_body_size 10m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_set_header X-CSRF-Token $http_x_csrf_token;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://app:8080;
  }

  # Spring Bootの静的ファイルはNginxで返す。
  location ~* .*\.(jpg|gif|png|css|js|ico|svg) {
      root /usr/share/nginx/www;
      access_log off;
  }
}
```

## Docker Comopseから設定される環境変数
```docker/environments/common.env
TZ=Asia/Tokyo
```

## Docker Comopseから設定される永続化

| ホスト | コンテナ | 概要 |
|---|---|---|
| volumes/web/static/ | /usr/share/nginx/www/ | 静的ファイル |
| volumes/web/ssl/ | /etc/nginx/cert/ | SSL証明書 |
| volumes/web/log/ | /var/log/nginx/ | ログ |

# 実行してみましょう！
## Docker Composeで起動
だいぶ簡単でしたが各ファイルの説明が終わりましたので実行して確認します。

1. [GitHub](https://github.com/devnokiyo/springboot-dev-docker-template)から一式ダウンロードします。
1. dockerディレクトリへ移動します。

    ```sh
    $ cd docker
    ```
1. ビルドします。(初回なので起動でも構いません)

    ```sh
    $ docker-compose build --no-cache
    Building db
    Step 1/3 : FROM mysql:5.7
     ---> 9cfcce23593a
    Step 2/3 : COPY my.cnf /etc/mysql/conf.d
     ---> 4af29808e20c
            :
            :
    Successfully built b074e2d8831d
    Successfully tagged docker_web:latest
    ```
1. 起動します。

    ```sh
    $ docker-compose up
    Creating network "docker_default" with the default driver
    Creating docker_db_1 ... done
    Creating docker_app_1 ... done
    Creating docker_web_1 ... done
    Attaching to docker_db_1, docker_app_1, docker_web_1
    db_1   | 2020-06-22 23:04:49+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.30-1debian10 started.
            :
            :
    db_1   | Version: '5.7.30'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL       Community Server (GPL)
            :
            :
    app_1  | [INFO] Scanning for projects...
    app_1  | Downloading from central:     https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-starter-parent/2.2.8.RELEASE/spring-boot-starter-parent-2.2.8.RELEASE.pom
    app_1  | Downloading from central: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-dependencies/2.2.8.RELEASE/spring-boot-dependencies-2.2.8.RELEASE.pom
            :
            :
    app_1  | [INFO] Attaching agents: []
    app_1  | Listening for transport dt_socket at address: 5005
    app_1  | 
    app_1  |   .   ____          _            __ _ _
    app_1  |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    app_1  | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    app_1  |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
    app_1  |   '  |____| .__|_| |_|_| |_\__, | / / / /
    app_1  |  =========|_|==============|___/=/_/_/_/
    app_1  |  :: Spring Boot ::        (v2.2.8.RELEASE)
    app_1  | 
    app_1  | 2020-06-22 23:07:31.526  INFO 74 --- [  restartedMain] com.example.demo.DemoApplication         : Starting DemoApplication on e5dd9a4954d8 with PID 74 (/app/target/classes started by root in /app)
            :
            :
    app_1  | 2020-06-22 23:07:37.683  INFO 74 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    app_1  | 2020-06-22 23:07:37.686  INFO 74 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 6.781 seconds (JVM running for 8.41)
    ```

## ブラウザからアクセス
hostsファイルにdevnokiyo.example.comをループバックIPで設定して`https://devnokiyo.example.com` にアクセスします。不正な証明書ということでエラーが出ると思いますが便宜上例外を許可してください。以下はChromeの例ですが表示自体はされています。

<img alt="ブラウザの警告.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/234199b2-eabb-f2b8-b868-468e5d9f2fd0.png">
<img alt="nginxへアクセス.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/aca51f1a-c179-c088-344c-a4862e58868d.png">
Nginxを経由でWebサイトにアクセスできています:thumbsup:
なお、ポポデザイン様の[テンプレート](https://popo-design.net/template/)を利用させて頂きました。感謝申し上げます。

前述のとおり筆者専用環境ではLet's EncryptのSSL証明書を利用しています。ご参考までに正常な証明書扱いの画像も載せておきます。独自ドメインを所有しておりhoge.devnokiyo.comで取得した例になります。
<img width="2061" alt="スクリーンショット 2020-06-23 1.32.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/c75e31d0-2d04-1a72-f098-ce4259b4e3e2.png">


## Tomcatへアクセス
Nginxの設定の誤りで動作不良になることもあると思いますので、Tomcatへの直接アクセスも許可しています。念のためアクセスできるか確認します。
`http://localhost:8080` にアクセスします。レイアウトが崩れています:thermometer_face::thermometer_face::thermometer_face:
しかし、静的ファイルはNginxから返されるように設定しているので問題ありません:bangbang:
<img alt="Tomcatにアクセス.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/c771c75b-c115-4437-d468-3519241d8d9c.png">

## ホストOSからMySQLへ接続を確認
ホストOSのMySQL Workbenchから以下にアクセスします。

|||
|---|---|
|ホスト名|127.0.0.1|
|ポート|3306|
|ユーザー|spring|
|パスワード|spring|

無事できていますね:thumbsup:
<img alt="DB_確認_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/8a0f19a5-3af6-8ee5-1d23-625d0633da90.png">

## TomcatからMySQLへ接続を確認
Docker Composeで定義したコンテナ間でMySQLへ接続できるか確認します。
`https://devnokiyo.example.com/form`へアクセスしてお問い合わせしてみます。
<img alt="お問い合わせ.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/2f1da9f2-943f-2483-c590-6decf298fbcb.png">
送信ボタンを押下します。
<img alt="お問い合わせ完了.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/63978e8d-4aac-5f19-06cb-77b58192701d.png">
再度MySQL Workbenchでテーブルを参照するとレコードが1行増えていますね:thumbsup:
<img alt="DB_確認_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/ef5a1093-6213-caa8-a673-fdc9802eac3f.png">

## リモートデバッグする
Spring BootをDockerでコンテナ化しましたが、ブレークポイントを利用できないと不便です。STS(Eclipse)からTomcatのコンテナをアタッチしてデバッグできるようにします。
### 準備
STS(Eclipse)のメニューから`Run` -> `Debug Configurations...`を選択します。`Remote Java Applicaion`で`demo`プロジェクトをDebugします。
<img alt="リモートデバッグの準備.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/ee53165f-0dc4-84e1-5beb-9b3cb560e9dc.png">

### ブレークポイントを設定
RootControllerの29行目にブレークポイントを設定しました。
<img alt="ブレークポイントを設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/692caf15-c557-57f8-0aeb-9253dda68371.png">
`http://devnokiyo.example.com/form`へアクセスするとブレークポイントで処理が止まります。
<img alt="ブレークポイントで停止中.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/d160b31e-3ba0-9c34-389e-c5bd84412bdf.png">

## 自動リロード
ソースコードを修正したときに毎回ビルドするのは面倒なので、Spring Boot Devtoolsの自動リロードを利用します。前述のとおり`Java -jar`による起動は開発中のコードが更新されたときの自動リロードが無効になってしまいますが、Maven WrapperでSpring Bootを起動しているので自動リロードできます。

### ソースコード修正
以下のアクションメソッドを追加してみます。コントローラークラスのファイルを保存するとリロードされます。

```java:RootController.java
@GetMapping("/hoge")
public String hoge() {
	return "root/index";
}
```

<img alt="ソースコード修正" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/6422a42e-f4eb-6ef9-2454-781eada4f876.png">

### 自動リロード中
コンソールをみるとリロードの状況がわかります。1行目が初回起動時の日時で2行目以降が自動リロードの挙動になります。


```bash
app_1  | 2020-06-23 00:09:00.911  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 6.459 seconds (JVM running for 8.092)
app_1  | 2020-06-23 00:21:51.379  INFO 40 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
app_1  | 2020-06-23 00:21:51.379  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
app_1  | 2020-06-23 00:21:51.389  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 9 ms
app_1  | 2020-06-23 00:36:13.585  INFO 40 --- [       Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
app_1  | 2020-06-23 00:36:13.588  INFO 40 --- [       Thread-5] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
app_1  | 2020-06-23 00:36:13.651  INFO 40 --- [       Thread-5] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
app_1  | 2020-06-23 00:36:13.755  INFO 40 --- [       Thread-5] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
app_1  | 
app_1  |   .   ____          _            __ _ _
app_1  |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
app_1  | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
app_1  |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
app_1  |   '  |____| .__|_| |_|_| |_\__, | / / / /
app_1  |  =========|_|==============|___/=/_/_/_/
app_1  |  :: Spring Boot ::        (v2.2.8.RELEASE)
app_1  | 
app_1  | 2020-06-23 00:36:14.036  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : Starting DemoApplication on e5dd9a4954d8 with PID 40 (/app/target/classes started by root in /app)
app_1  | 2020-06-23 00:36:14.037  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
app_1  | 2020-06-23 00:36:14.500  INFO 40 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
        :
        :
app_1  | 2020-06-23 00:36:15.884  INFO 40 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
app_1  | 2020-06-23 00:36:15.907  INFO 40 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
app_1  | 2020-06-23 00:36:15.908  INFO 40 --- [  restartedMain] com.example.demo.DemoApplication         : Started DemoApplication in 1.965 seconds (JVM running for 1644.96)
app_1  | 2020-06-23 00:36:15.911  INFO 40 --- [  restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
app_1  | 2020-06-23 00:36:30.177  INFO 40 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
app_1  | 2020-06-23 00:36:30.178  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
app_1  | 2020-06-23 00:36:30.183  INFO 40 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 5 ms

```

### 修正後の確認
`https://devnokiyo.example.com/hoge`にアクセスしてトップページと同じページが表示されることを確認します。
<img alt="自動リロード済み" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/4d74ea35-d33c-c1ad-fa2b-f28fee1d80e2.png">



# 終わりに
前回同様に基礎的なコマンドの説明よりは「筆者はこうやった」的なことをメインに記事を書いてみました。JVM系はRubyやGoと比較するとDocker周りの情報が少ない印象です。(点々とした情報はあるのですが、線になっている情報は少ない雰囲気です。)
ひととおりの手順を習得できたので、どのくらい開発環境として使っていけるか運用してみようと思います。