BLOG

ブログ

VScode × Docker × SpringBootでホットデプロイ環境構築

こんにちわ、将来の夢はジェダイマスターのカリーです。

今回はMacで、Dockerを使用したJavaのホットデプロイ環境を構築してみたので、ご紹介したいと思います。

Javaの環境構築するのは久しぶりで、以前はEclipseやNetBeansを使用していたのですが、極力開発環境は統一したいなと思い、普段使いしているVSCodeで試してみました。

動作環境

  • M1 Mac(macOS Ventura)
  • Docker Desktop for Mac(4.x)
  • Spring Boot(3.1.3)

ディレクトリ構成

こちらが、完成系のディレクトリ構成です。(所々省略しています)

├── .vscode
│   └── launch.json
├── demo
│   ├── .gradle
│   ├── bin
│   ├── build
│   ├── gradle
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com
│   │   │   │       └── example
│   │   │   │           └── demo
│   │   │   │               └── DemoApplication.java
│   │   │   └── resources
│   │   └── test
│   ├── .gitignore
│   ├── build.gradle
│   ├── gradlew
│   ├── gradlew.bat
│   ├── HELP.md
│   └── settings.gradle
└── docker-compose.yaml

環境構築

Docker環境を用意

プロジェクトディレクトリを作成し、ディレクトリ直下にdocker-compose.yamlを作成します。

version: "3.6"
services:
  java:
    image: openjdk:17-oracle
    container_name: demo-java
    tty: true
    working_dir: /app
    volumes:
      - ./demo:/app
    ports:
      - 8080:8080 # 通常実行用
      - 5050:5050 # デバッグ用

拡張機能の導入

VSCodeの拡張機能で「Extension Pack for Java」を入れます。

Extension Pack for JavaはVSCode環境でJavaアプリケーションの作成、テスト、デバッグを進めるための拡張機能パックとなっており、インストールすることで以下6つの拡張機能がインストールされます。

  • Language Support for Java(TM) by Red Hat
  • Debugger for Java
  • Test Runner for Java
  • Maven for Java
  • Project Manager for Java
  • IntelliCode

Spring Bootプロジェクトを作成

他にもSpringプロジェクトを用意する方法があるのですが、今回はSpring InitializerでSpring Bootプロジェクトの雛形を作成します。
Spring Initializerを使用することで、GUIベースで簡単にSpring Bootプロジェクトを作成することができます。

今回は、以下のような設定で作成しました。

作成してダウンロードしたSpring Bootプロジェクトを、プロジェクトディレクトリ直下に配置し、

その後、build.gradleファイルの中の末尾に以下を追記します。

jar {
	enabled = false
}

bootJar {
	archiveBaseName = "sample"
	version = "0.0.1"
	archiveClassifier = 'SNAPSHOT'
	archiveExtension = 'jar'
}

bootRun {
	systemProperties = System.properties
	jvmArgs=["-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5050"]
}

VSCodeの設定

次に、プロジェクトディレクトリ直下に.vscode/launch.jsonを作成します。

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "java", // 言語を指定
      "name": "java (Attach)", // デバッグ実行名
      "request": "attach", // 起動中のプログラムにアタッチ
      "hostName": "localhost",
      "port": 5050 // 接続するポートを指定
    }
  ]
}

コンテナ上でビルド実行

まずはターミナル上で以下のコマンドを叩き、Javaコンテナを起動します。

$ docker-compose up -d

[+] Building 0.0s (0/0)
[+] Running 2/2
 ✔ Network demoapp_default  Created
 ✔ Container demo-java      Started

コンテナを作成・起動したら、javaコンテナ内に入ります。

$ docker exec -it demo-java /bin/bash
bash-4.4#

コンテナ内に入れたら、pwdコマンドでappディレクトリにいることを確認し、ビルドしていきます。

bash-4.4# pwd
/app

# ビルド開始
bash-4.4# microdnf install findutils
bash-4.4# sh gradlew build --continuous

BUILD SUCCESSFUL in 3s
6 actionable tasks: 4 executed, 2 up-to-date

Waiting for changes to input files... (ctrl-d to exit)
<=============> 100% EXECUTING [1s]
> IDLE
> IDLE

sh gradlew buildに–continuousオプションを付けておくことで、一度ビルドしたのちに変更監視状態となり、ソース修正を行うたびに再ビルドされます。
終了しない限りは常に変更監視状態となるので、Springを起動する際は別のターミナルから再度コンテナ内に入って起動します。

# 別のターミナルから再度コンテナ内に入る
$ docker exec -it demo-java /bin/bash
bash-4.4#

# Spring起動
bash-4.4# sh gradlew bootRun
Starting a Gradle Daemon, 1 busy Daemon could not be reused, use --status for details

Springを起動したら、最後にVSCodeのデバッグモードで起動します。
VSCodeのデバッグビューを開いて、サイドバーの[実行とデバッグ]ビューを確認すると、「java(Attach)」と表示されているプルダウンがあると思います。
(これが、先ほどlaunch.jsonのconfigurations → nameに記載されていたデバッグ実行名です)

この状態で開始ボタンを押すことで、launch.jsonで定義した設定を元に、デバッグモードが起動されます。

ホットデプロイ動作確認

では、ちゃんとホットデプロイがされているのか確認します。
demo/src/main/java/com/example/demo/DemoApplication.javaに一部コードを追加します。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping; // 追加
import org.springframework.web.bind.annotation.RestController; // 追加

@SpringBootApplication
@RestController // 追加
public class DemoApplication {

	@RequestMapping("/") // 追加
    public String home() { // 追加
        return "Hello World"; // 追加
    } // 追加

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

}

まずはこの状態でlocalhost:8080にアクセスすると、Hello Worldが表示されるかと思います。

次に、”Hello World”の部分を、別の文字に修正して、再度localhost:8080にアクセスしてみます。

	@RequestMapping("/")
    public String home() {
        return "Hello Mavs";
    }

正常にホットデプロイが行われ、修正した文字が表示されます!

まとめ

今回はVSCodeでSpring Bootのホットデプロイ環境の構築についてご紹介しました。

この環境を試すまでは修正するたび毎回Jarファイル生成 → Boot Runをしていたのですが、手間に耐えきれず「ホットデプロイって可能なのか?」と思い構築に至りました。

sh gradlew build –continuousの処理までをDockerfileに入れたら立ち上げ時楽になると試してみると、2度目以降は良かったのですが、初回が–continuousでDockerfileの処理が終わらず、コンテナが出来上がらなかったので断念しました。。

今回はこのような構成になりましたが、もっと良い方法(特にターミナルを一つで済ます方法)が見つかりましたら、この記事を更新したいなと思います。