Docker環境にて、Spring Bootを利用できるようにします。
Spring Initializrで作成したプロジェクトを、Docker上でビルド、起動します。
IDEはVS Codeを利用して、デバッグもできるようにします。
ビルドには、Gradle を使用します。
環境
- Java:17
- Spring Boot:3.0.1
- MySQL:8.0
ディレクトリ構成
以下のディレクトリ構成としています。
.
├── docker-compose.yml
├── infra
│ ├── mysql
│ │ ├── Dockerfile
│ │ └── my.cnf
└── workspace (Spring Bootプロジェクトのディレクトリ)
Docker環境
まず、Docker環境を作成します。
構築するサーバーはアプリケーションサーバー(app)、データベースサーバー(db)の2つになります。
docker-compose.yml を作成します。
version: "3.9"
services:
app:
image: eclipse-temurin:17
ports:
- 8080:8080
volumes:
- ./workspace:/workspace
working_dir: /workspace
tty: true
db:
build: ./infra/mysql
volumes:
- db-store:/var/lib/mysql
ports:
- 3306:3306
volumes:
db-store:
アプリケーションサーバー(app)コンテナ
アプリケーションサーバーについては、Docker HubがOpenJDKイメージの廃止を決定したそうなので、Eclipse Temurinの公式イメージを使用しています。
▼廃止について参考
▼Eclipse Temurinの公式イメージ
https://hub.docker.com/_/eclipse-temurin
データベースサーバー(db)コンテナ
データベースサーバーについては、Dockerfileを作成します。
FROM mysql/mysql-server:8.0
ENV MYSQL_DATABASE=spring \
MYSQL_USER=spring \
MYSQL_PASSWORD=secret \
MYSQL_ROOT_PASSWORD=secret \
TZ=Asia/Tokyo
COPY ./my.cnf /etc/my.cnf
RUN chmod 644 /etc/my.cnf
設定は以下のようにしています。
[mysqld]
# default
skip-host-cache
skip-name-resolve
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
secure-file-priv = /var/lib/mysql-files
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
# character set / collation
character_set_server = utf8mb4
collation_server = utf8mb4_ja_0900_as_cs_ks
# timezone
default-time-zone = SYSTEM
log_timestamps = SYSTEM
# Error Log
log-error = mysql-error.log
# Slow Query Log
slow_query_log = 1
slow_query_log_file = mysql-slow.log
long_query_time = 1.0
log_queries_not_using_indexes = 0
# General Log
general_log = 1
general_log_file = mysql-general.log
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
コンテナの起動
各ファイルが作成できたら、各コンテナを起動します。
ここでは、まだ動かすものがないので、コンテナが正常に起動できていればOKとします。
Spring Bootのプロジェクトを作成
Spring Initializrを利用すると、簡単にSpring Bootのプロジェクトを作成することができるので、利用します。
以下のようにしました。

依存関係は以下を選択しました。
- Spring Boot DevTools
- Lombok
- Spring Web
- Thymeleaf
- Spring Data JPA
- MySQL Driver
「GENERATE」ボタンをクリックすることで、ダウンロードできるので、展開したものをworkspace配下に配置します。
コンテナ上でビルド
コンテナ上でビルドを行います。
アプリケーションサーバーコンテナに入り、実行します。
$ pwd
/workspace
$ ll
total 36
drwxr-xr-x 11 root root 352 Jan 7 06:21 ./
drwxr-xr-x 1 root root 4096 Jan 7 06:22 ../
-rw-r--r-- 1 root root 857 Jan 6 21:06 build.gradle
drwxr-xr-x 6 root root 192 Jan 7 05:38 .gradle/
drwxr-xr-x 3 root root 96 Jan 6 21:06 gradle/
-rwxr-xr-x 1 root root 8188 Jan 6 21:06 gradlew*
-rw-r--r-- 1 root root 2838 Jan 6 21:06 gradlew.bat
-rw-r--r-- 1 root root 1508 Jan 6 21:06 HELP.md
-rw-r--r-- 1 root root 26 Jan 6 21:06 settings.gradle
drwxr-xr-x 4 root root 128 Jan 6 21:06 src/
$ ./gradlew build
ビルドしたところ、testタスクでエラーが発生しました。
> Task :test
DemoApplicationTests > contextLoads() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:142
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:798
Caused by: org.springframework.beans.factory.BeanCreationException at ConstructorResolver.java:657
Caused by: org.springframework.beans.BeanInstantiationException at SimpleInstantiationStrategy.java:171
Caused by: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties$DataSourceBeanCreationException at DataSourceProperties.java:182
1 test completed, 1 failed
> Task :test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///workspace/build/reports/tests/test/index.html
JPAを使用しているため、DBの接続設定が必要です。
src/main/resources/application.properties にDBの接続情報を追加します。
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://db:3306/${db.url:spring}
spring.datasource.username=${db.username:spring}
spring.datasource.password=${db.password:secret}
spring.jpa.hibernate.ddl-auto=update
DBの接続情報を追加することで、ビルドが成功になりました。
DB検索機能を作成する
JPAを利用して、DB検索機能を実装してみます。
モデルの実装
まず、モデルの実装です。
ユーザーを管理するusersテーブルとしています。
package com.example.demo.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Data;
@Entity
@Data
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String name;
}
コントローラーの実装
続いて、コントローラーの実装です。
データを取得する処理にはサービスクラスに実装しているので、コントローラーはリクエストの処理のみとしています。
package com.example.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public String index(Model model) {
List<User> users = userService.getUsers();
model.addAttribute("users", users);
return "users/index";
}
}
サービスクラスの実装
続いて、サービスクラスの実装です。
サービスクラスでは、リポジトリクラスを通じて、DBからデータを取得しています。
package com.example.demo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> getUsers() {
return userRepository.findAll();
}
}
リポジトリクラスの実装
続いて、リポジトリクラスの実装です。
リポジトリクラスでは、JpaRepositoryを継承するだけで、取得するロジックを実装する必要はありません。
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.entity.User;
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {}
ビューの実装
最後にビューの実装です。
HTMLは必要最低限にしていますが、取得したデータを一覧表示する実装にしています。
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
</head>
<body>
<table>
<thead>
<tr>
<th>ID</th>
<th>メールアドレス</th>
<th>名前</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}" th:object="${user}">
<td th:text="*{id}"></td>
<td th:text="*{email}"></td>
<td th:text="*{name}"></td>
</tr>
</tbody>
</table>
</body>
</html>
ビルドと起動
実装が完了したら、ビルドとサーバーの起動を行います。
$ ./gradlew build
$ java -jar build/libs/demo-0.0.1-SNAPSHOT.jar
起動が完了したら動作確認をしますが、最初はデータが入っていないので、insert文で挿入しておきます。
INSERT INTO `spring`.`users`
(`id`,
`email`,
`name`,
`password`)
VALUES
(1,
'test@test.jp',
'テスト太郎',
'password');
URLは以下となります。
http://localhost:8080/users
以下のように、データが表示されることが確認できました。

コンテナに接続する
ここまでで実行する環境ができたので、続いて、Dockerのコンテナに接続します。
コンテナに接続することで、ライブラリの参照やコード補完ができるようになり、デバッグが行えるようになります。
本記事ではVSCode のDev Containers を使用します。
▼公式ドキュメント
https://code.visualstudio.com/docs/devcontainers/containers
▼参考
コンテナに接続して、VSCodeのデバッグモードで起動することで、デバッグが行えます。