Spring Bootで簡単なWebアプリを作ってみたい！【Dockerで環境構築】

# 【経緯】
こちらの記事は前記事の[Spring Bootで簡単なWebアプリを作ってみたい！【CRUD処理を実装】](https://qiita.com/takuch/items/1a29111c97a6929baff1)の続きになります。
前記事で作成したTodoアプリを簡単にデプロイできるように、Dockerで環境を構築してみようと思います。
前記事のコードをもとに進めて行きますが、構成が同じであれば同様に環境構築できるようになっていると思います。

# 【この記事でやること】
DockerでSpring BootとMySQLを使ったアプリケーション環境を構築します。
ビルド環境はmavenですが、gradleの場合の解説も補足として解説しています。

# 【開発環境】
- PC: MacBook Pro(2019)
- プロセッサ: 1.4 GHz クアッドコアIntel Core i5
- OS: macOS 12.2.1
- IDE: IntelliJ IDEA 2021.2.3(Community Edition)
- Java: openjdk 11.0.12 2021-07-20 LTS
- Spring Boot: 2.6.1
- maven: 3.8.4
- MySQL: 8.0.28
- Docker Desktop: 4.7.0
    - Docker: 20.10.14
    - docer-compose: 1.29.2  

(今回からmacを使用しているのでご注意ください)

# 【準備】
## ■Docker Desktopのインストール
Mac版もWindows版も以下からインストーラーをDLできます。
https://www.docker.com/products/docker-desktop/
## ■ローカルのMySQLの停止
前記事でローカルにMySQLをインストールしているので、起動している場合は停止させておいたほうが良いかもしれません。
前回参考にしたサイトに停止方法も記載されています。

Windows: https://prog-8.com/docs/mysql-env-win

Mac: https://prog-8.com/docs/mysql-env
# 【環境設定】
## ■ディレクトリ構成
ディレクトリ構成は下記のようにしました。
```
TodoApp
|-- SpringBootTodo
|   |-- src
|   |-- pom.xml
|   `-- Dockerfile
|-- mysql
|   |-- Dockerfile
|   |-- data
|   `-- settings
|       `-- setting.cnf
`-- docker-compose.yml
```
- SpringBootTodo
    - 前回作成したアプリのディレクトリ
    - 他のアプリへの差し替え可能
- mysql
    - data: DBのデータを格納する
    - settings: MySQLの設定ファイルを格納する

## ■pom.xmlの修正
```xml:TodoApp/SpringBootTodo/pom.xml
<!--省略-->
	<build>
		<finalName>app</finalName> <!--追加-->
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
<!--省略-->
```
build後のファイル名をappにするために`<finalName>app</finalName>`を追加しています。
好きな名前で問題ないですが、次に説明するDockerfileも変更する必要があります。

## ■Spring BootのDockerfileを作成
```Dockerfile:TodoApp/SpringBootTodo/Dockerfile
FROM maven:3.8.4-jdk-11 AS builder
WORKDIR /tmp
COPY ./src ./src
COPY ./pom.xml .
RUN mvn package

FROM openjdk:11.0.14.1-oracle
COPY --from=builder /tmp/target/app.jar /app/app.jar
EXPOSE 8080
```
Spring BootのDockerfileは[こちら](https://qiita.com/saitoshi/items/a931399e81e63e8e4f1e)の記事を参考にしました。
ここではビルドとアプリケーション実行に分かれています。
- ビルド
    - mavenのビルド環境を用意
    - 作業ディレクトリを/tmpにする
    - ./srcをコピー
    - ./pom.xmlをコピー
    - mavenのビルドコマンドを実行
- アプリケーション実行
    - Javaの実行環境を用意
    - ビルドして作成したapp.jarファイルをコピー
    - コンテナのポートを8080に指定



## ■MySQLのDockerfileを作成
```Dockerfile:TodoApp/mysql/Dockerfile
FROM mysql:8.0.28-debian

EXPOSE 3306
```
MySQLのDockerfileは[こちら](https://qiita.com/2san/items/662a2b90fc8a94fa9a62)の同僚の記事を参考にしました。(いつもわかりやすい記事感謝です)

- mysqlの環境を用意
- コンテナのポートを3306に指定

## ■MySQLの設定ファイルを作成
```cnf:TodoApp/mysql/settings/setting.cnf
[mysqld]
character-set-server=utf8mb4

[client]
default-character-set=utf8mb4
```
最低限文字コードだけ設定します。

## ■docker-compose.ymlを作成
compose側でその他の設定をしていきます。
```yml:TodoApp/docker-compose.yml
version: "3"
services:
  spring-boot:
    build:
      context: ./SpringBootTodo
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      mysql:
        condition: service_started
    entrypoint: "java -jar /app/app.jar"
    networks:
      - app-net
  mysql:
    build:
      context: ./mysql
      dockerfile: Dockerfile
    ports:
      - "3306:3306"
    volumes:
      - ./mysql/settings:/etc/mysql/conf.d/
      - ./mysql/data/:/var/lib/mysql/
    environment:
      MYSQL_DATABASE: spring_boot_todo
      MYSQL_ROOT_PASSWORD: password
    networks:
      - app-net
networks:
  app-net:
    driver: bridge
```
- services
    - Spring Boot
        - Dockerfileを指定
        - コンテナのポート8080と実行環境のポート8080をつなぐ
        - MySQLの起動後に実行するように指定
        - 実行コマンド
        - ネットワークを指定
    - MySQL
        - Dockerfileを指定
        - コンテナのポート3306と実行環境のポート3306をつなぐ
        - ローカルの設定とdataディレクトリをコンテナ内のディレクトリに紐付ける
        - 作成するDB名を指定(好きな値に変更)
        - root権限のpasswordを指定(好きな値に変更)
        - ネットワークを指定
- networks
    - アプリケーションのネットワークをbridgeで構築
    - networkを構築しないとうまく動かないので要注意([こちら](https://qiita.com/YuitoSato/items/4a4b46f5670b45739a37)参照)
## ■Spring Bootのpropertiesファイルの修正
```properties:TodoApp/SpringBootTodo/src/main/resources/application.properties
## ■DBの接続先情報
spring.datasource.url=jdbc:mysql://todoapp-mysql-1:3306/spring_boot_todo
spring.datasource.username=root
spring.datasource.password=password

spring.jpa.hibernate.ddl-auto=update
```
- `todoapp_mysql_1`はMySQLのコンテナ名を入れる
- `spring_boot_todo`はdocker-compose.ymlで指定したDB名を入れる
- `password`はdocker-compose.ymlで指定したMySQLのroot権限のpasswordを入れる

# 【動作確認】
ターミナルを開きdocker-compose.ymlがあるディレクトリに移動し、以下を実行します。
```bash:
sudo docker-compose up -d
```
ブラウザを立ち上げて`localhost:8080`にアクセスしアプリ画面が表示されれば完了です！
![スクリーンショット 2022-04-11 23.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157900/a2cd3dbf-1624-c746-38e9-87acab6c3288.png)

# 【リポジトリ】
参考にリポジトリを載せておきます。

https://github.com/t-takumi-h/spring_boot_todo_app

# 【補足 (gradleの場合)】
ビルド環境がmavenではなくgradleを使用した場合についてもまとめておきます。
(ビルド環境だけが違う状態を想定して記載しています)
## ■build.gradleの修正
```gradle:TodoApp/SpringBootTodo/build.gradle
// 省略
bootJar{
	archiveFileName = 'app.jar'
}
// 省略
```
上記によりファイル名をapp.jarに固定しています。

## ■Spring BootのDockerfileを作成(gradle版)
```Dockerfile:TodoApp/SpringBootTodo/Dockerfile
FROM gradle:7.4.1-jdk11 AS builder
WORKDIR /tmp
COPY ./src ./src
COPY ./build.gradle .
RUN gradle build

FROM openjdk:11.0.14.1-oracle
COPY --from=builder /tmp/build/libs/app.jar /app/app.jar
EXPOSE 8080
```
mavenとほとんど同じですが、ファイル名やコマンド、出力先などをgradleに合わせています。
mavenとの違いはこれだけです！



# 【まとめ】
今回はDockerでSpring BootとMySQLを使ったアプリケーション環境を構築しました。
Dockerを使えば、開発やデプロイが効率化されるので、有効に使っていきたいですね。


記事に間違いなどありましたら遠慮なくご指摘ください。

この記事が皆さんの参考になれば幸いです。

# 【参考文献】
- [Spring Bootアプリケーションのコンテナ化を試してみた](https://qiita.com/saitoshi/items/a931399e81e63e8e4f1e)
- [DockerでPHPとMySQLのシンプルすぎる環境構築を行う](https://qiita.com/2san/items/662a2b90fc8a94fa9a62)
- [他のDockerコンテナからコンテナ内のMySQLに接続する](https://qiita.com/YuitoSato/items/4a4b46f5670b45739a37)