この記事では、Kotlin、Spring Boot、Gradle、MySQLのアプリをDockerコンテナ化する方法を解説します。
初心者も理解できるように、
- プロジェクト作成
- DockerでMySQLコンテナ作成
- Spring Bootアプリのコンテナ作成
- 2と3のコンテナ連携
までの手順をステップバイステップで説明します。
完成モジュールのGithubリポジトリも公開しているので、参考にしてください。
目次
- 利用PC
- Spring Initializrでプロジェクト作成
- プロジェクト全体のモジュール作成
- DockerでMySQL起動
- IntelliJでMySQLに接続
- Spring BootでMySQLのデータを画面表示するための設定
- Spring BootのDockerコンテナ化
- DockerでSpring BootとMySQLの連携
利用PC
使っているPCはIntel CPUのMacでOSはmacOS Montereyです。
Spring Initializrでプロジェクト作成
Spring InitializrでSpring Bootプロジェクトを作成します。
各設定は上記の画像と同じように入力します。
- Project:Gradle - Kotlin
- Language:Kotlin
- Spring Boot:3.2.5
- Group:com.test-project
- Artifact:backend
- Name:backend
- Description:DockerでKotlin、Spring BootとMySQL連携デモプロジェクト
- Package name:com.test-project.backend
- Packaging:Jar
- Java:21
設定の補足
- Spring Boot:より新しいLTSバージョンがあれば、3.2.5以上でもOK
- Group:Groupにはアプリの逆ドメインを指定するのが慣例。例えばgithub.comなら
com.github
。Groupの設定値はパッケージ名に使われる - Artifact、Name:Spring Bootプロジェクトのルートディレクトリ名、パッケージ名、ビルド時のjarファイル名、設定ファイルなどに使われる
- Java:最新のLTSバージョンを選択
追加するDependencies
- MySQL Driver:Spring BootからMySQLへ接続するためのDriver
- Spring Web:Spring BootでREST APIを作成するためのライブラリ
- Spring Data JPA:Spring BootでSQLを扱いやすくするためのライブラリ
設定ができたらGENERATE
ボタンでモジュールをダウンロードしてください。入力が面倒な場合は設定済リンクからダウンロードも可能です。
プロジェクト全体のモジュール作成
docker-spring-mysql-app/
├── backend/
├── db/
└── compose.yaml
まず上記のディレクトリ、ファイルを作成します。
各ディレクトリの中身は
- backend:Spring Initializrでダウンロードしたモジュール
- db:MySQLのDockerコンテナに必要なファイル
です。詳細は後で説明します。
docker-spring-mysql-app/compose.yaml
でSpring BootとMySQLのDockerコンテナを連携させる構成です。
DockerでMySQL起動
MacでDockerを使うため、公式サイトにそってDocker Desktopをインストールしておきます。
MySQLのDockerコンテナを作成するため、docker-spring-mysql-app/compose.yaml
に以下を入力します。
services:
db:
image: mysql:8.1.0
restart: always
healthcheck:
test:
[
'CMD-SHELL',
'mysqladmin ping -h 127.0.0.1 --password="$$(cat /run/secrets/db-password)" --silent',
]
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
- ./db/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
ports:
- '3307:3306' # ホストの3306が既に使用されているため3307にマッピング
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
- TZ=Asia/Tokyo
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
上記設定はDocker公式が出しているawsome-composeのnginx-golang-mysqlリポジトリを参考にしています。
設定の補足
- image: mysql:8.1.0:データベースのバージョン管理にFlywayを使うため、Flywayで扱えるMySQL最新バージョンの8.1を使う
- restart:alwaysでDocker再起動時、コンテナ停止、クラッシュ時にコンテナを常に再起動する
- healthcheck:dbの稼働チェック。healthcheck結果を使って後ほどSpring Bootのコンテナと連携
- secrets:db-passwordで定義しているファイルの内容がコンテナの/run/secrets/db-passwordにファイルとしてマウントされる
- volumes:MySQLのデータ永続化と、コンテナ起動時にinit-db.sqlを実行する
- ports:ホストの3307ポートをコンテナの3306ポートにマッピング
- environment:MySQLで初期作成するデータベース名とルートパスワード、タイムゾーンを設定
- logging:logファイルを10MB×3ファイルまでしか作成しない。3ファイルを超えると最古のファイルが削除される
.envの作成
docker-spring-mysql-app/.env
を作成し、compose.yaml
の環境変数${MYSQL_DATABASE}
を定義します。
MYSQL_DATABASE=test_db
password.txtの作成
docker-spring-mysql-app/db/password.txt
でMySQLのルートパスワードを定義します。
testPassword
init-db.sqlの作成
docker-spring-mysql-app/db/init-db.sql
でコンテナ初期起動時にSpring Bootから使うユーザ作成をし、権限を与えます。
create user 'app_user'@'%' identified by 'appUserPassword';
grant select,insert,update,delete on test_db.* to 'app_user'@'%';
.gitignoreの作成
docker-spring-mysql-app/.gitignore
を作成し、パスワードなどが設定されたファイルをgitの管理対象から外します。
.env
password.txt
init-db.sql
ここまでできたら、DockerでMySQLのコンテナを起動してみます。
Docker Desktopを起動し、ターミナルでdocker-spring-mysql-app
ディレクトリに移動してdocker compose up -d
を実行しましょう。Docker DesktopのContainersメニューでMySQLのコンテナの起動が確認できるはずです。
IntelliJでMySQLに接続
IntelliJのファイル
> 開く
でdocker-spring-mysql-app
ディレクトリを開きます。
画面右のデータベースアイコンからメニューを開き+
> データソース
> MySQL
> MySQL
をクリック。
- 名前:任意の値
- ホスト:localhost
- ポート:3307
- ユーザー:root
- パスワード:testPassword
- データベース:test_db
を入力して接続のテストをクリックし、成功するか確かめましょう。
成功したら適用とOKをクリック。データベースメニューからtest_db
とapp_user
が作成されていることが確認できます。
Spring BootとMySQLの連携時に使うためのテーブルとデータを作成しておきます。
CREATE TABLE test_table (id int unsigned AUTO_INCREMENT primary key , value varchar(50));
INSERT INTO test_table (value) VALUES ('テスト');
IntelliJのクエリコンソールから上記SQLを実行しても良いですが、データベースバージョン管理のためにFlywayを使うのがおすすめです。
IntelliJでFlywayを設定する方法は以下の記事を参照してください。
(後日公開予定)
Spring BootでMySQLのデータを画面表示するための設定
Spring Boot実行時にMySQLのデータを画面に表示するための設定をします。
docker-spring-mysql-app/backend/src/main/resources/application.properties
をより可読性の高いapplication.yaml
にリネームし、以下設定を入力します。
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${DATABASE_URL}
username: ${APP_DATABASE_USER}
password: ${APP_DATABASE_PASSWORD}
jpa:
show-sql: true
hibernate:
ddl-auto: none
properties:
hibernate:
jdbc:
time_zone: Asia/Tokyo
format_sql: true
設定の補足
- show-sql: true:実行されるSQLがコンソール表示されるようになる
- ddl-auto: none:jpaがスキーマの自動生成、更新をしない
- format_sql: true:コンソール表示されるSQLが整形される
.envの追記
docker-spring-mysql-app/.env
環境変数ファイルにapplication.yaml
で使う環境変数を追記します。
MYSQL_DATABASE=test_db
DATABASE_URL=jdbc:mysql://db:3306/test_db
APP_DATABASE_USER=app_user
APP_DATABASE_PASSWORD=appUserPassword
MySQLデータを画面表示するための設定
MySQLデータを画面表示するためのコードを書いていきます。
docker-spring-mysql-app/backend/src/main/kotlin
のcom.testproject.backend
パッケージにentry
パッケージを作成し、その中にTestTable.kt
を作成。
package com.testproject.backend.entity
import jakarta.persistence.*
@Entity
@Table(name = "test_table")
class TestTable(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(nullable = false)
val id: Int,
@Column(length = 50)
val value: String?
)
同じくcom.testproject.backend
パッケージにrepository
パッケージを作成し、その中にTestRepository.kt
を作成。
package com.testproject.backend.repository
import com.testproject.backend.entity.TestTable
import org.springframework.data.repository.CrudRepository
interface TestRepository : CrudRepository<TestTable, Int>
そしてcom.testproject.backend
パッケージにcontroller
パッケージを作成し、その中にTestController.kt
を作成。
package com.testproject.backend.controller
import com.testproject.backend.repository.TestRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class TestController {
@Autowired
lateinit var testRepository: TestRepository
@GetMapping("/")
fun index(): String {
val testTable = testRepository.findById(1)
return testTable.get().value!!
}
}
これでSpring Bootアプリを起動した状態でlocalHost:8080
にアクセスするとテスト
が表示されるよう設定できました。
Spring BootのDockerコンテナ化
作成したSpring BootアプリをDockerコンテナ上で起動できるようにします。
docker-spring-mysql-app/backend/Dockerfile
を作成しましょう。
# ステップ 1: ビルドステージ
FROM gradle:8.3.0-jdk17 AS build
# 作業ディレクトリを設定
WORKDIR /app
# 必要なファイルのみコピーしてDockerキャッシュを活用
COPY build.gradle.kts settings.gradle.kts /app/
COPY gradle /app/gradle
# 依存関係をダウンロード(Dockerキャッシュを活用)
RUN gradle build -x test --parallel --no-daemon || return 0
# 残りのソースコードをコピーしてアプリケーションをビルド
COPY src /app/src
RUN gradle build -x test --no-daemon
# ステップ 2: 実行ステージ
FROM eclipse-temurin:21-jdk
# アプリケーションを実行するユーザーを作成
RUN useradd -m -u 1001 spring
# 作業ディレクトリを設定
WORKDIR /app
# ビルドステージからビルド済みのアプリケーションをコピー
COPY --from=build /app/build/libs/*.jar app.jar
# アプリケーションファイルの所有権を変更
RUN chown -R spring:spring /app
# 作成したユーザーとしてアプリケーションを実行
USER spring
# アプリケーションを実行するコマンドを指定
ENTRYPOINT ["java", "-jar", "app.jar"]
# アプリケーションポートを公開
EXPOSE 8080
上記のDockerfileはChatGPT 4oにkotlin、spring boot、gradleのアプリをdockerコンテナ化するDockerfileのベストプラクティスを教えてください
と指示して作成してもらいました。
Dockerイメージのバージョンが古かったり、存在しないイメージを使ったりしていましたが、それ以外の修正はしていません。
RUN gradle build
を2回している理由は、1回目で依存関係をビルドして2回目でソースコードのビルドをするためです。依存関係とソースコードのビルドを分けることで、ソースコードのみ変更した場合、依存関係のビルドをDockerキャッシュで省略できます。
DockerでSpring BootとMySQLの連携
docker-spring-mysql-app/compose.yaml
に先ほどのDockerfileを使ってDockerコンテナを立ち上げるよう設定を追記します。
services:
backend:
build:
context: backend
ports:
- '8080:8080'
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=${DATABASE_URL}
- APP_DATABASE_USER=${APP_DATABASE_USER}
- APP_DATABASE_PASSWORD=${APP_DATABASE_PASSWORD}
restart: always
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
db:
image: mysql:8.1.0
restart: always
healthcheck:
test:
[
'CMD-SHELL',
'mysqladmin ping -h 127.0.0.1 --password="$$(cat /run/secrets/db-password)" --silent',
]
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
- ./db/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
# 本当は3306にマッピングしたいが、ホストがすでに使っているため3307
ports:
- '3307:3306'
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
- TZ=Asia/Tokyo
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
これでMySQL、Spring BootのDockerコンテナを立てて連携する準備完了です。
docker compose up --build -d
でコンテナを立ち上げ、ブラウザからlocalhost:8080
にアクセスするとテスト
が画面に表示されます。
ただ、docker compose up
でアプリを起動するとIntelliJでデバックができません。デバックしたいときは以下のIntelliJ公式ドキュメントの設定をすればIntelliJからDockerコンテナを立ち上げられるようになります。
以下の記事では、このアプリをVPS環境にデプロイして独自ドメイン、SSL設定をする手順を解説しています。
(後日公開予定)