docker composeとVSCodeでJava開発環境のコンテナ化

Java言語での開発から3～4年程離れていました。
過去のjavaの開発環境では、IDEはEclipseやSTS、IDEA等を使ってきました。
また、javaではdocker環境も利用したことはありませんでした。

ここ数年、他の言語でVSCodeやdockerを触ってきたので、
それらを使ってJava環境を整えてみました。


## 今回やること
- java開発環境のコンテナ化（dockerを使って開発メンバー皆同じ環境を簡単に）。
- 今回はSpringBootでRESTapiのサンプルを動かすところまで。


## 前提

- 私がWindowsユーザのため、Windows前提で記載してますので、適宜読みかえてください。
- 以下無ければ準備しておいてください。
  - WSL2 ※Windowsユーザのみ
https://learn.microsoft.com/ja-jp/windows/wsl/install
  - Docker Engine
https://matsuand.github.io/docs.docker.jp.onthefly/engine/install/ubuntu/
  - VSCode
https://code.visualstudio.com/download
    - VSCode拡張機能「[Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)」インストール

## コンテナ作成

### プロジェクトディレクトリを作成してVSコードで開く

※WSL上で行ってください。

```
$ mkdir spring-boot-rest-api-sample
$ cd spring-boot-rest-api-sample/
$ code .
```

### フォルダ/ファイル構成

作成するフォルダやファイルの配置は以下の通りです。

```
spring-boot-rest-api-sample
　　└─.devcontainer/
　　　　├─devcontainer.json
　　　　├─docker-compose.yml
　　　　└─docker/
  　　　　└─api/
     　　　　└─Dockerfile
```

後続の手順で作成していきます。

### devcontainer.json 作成
devcontainer.jsonは、VSCodeのリモートコンテナ開発環境用の設定ファイルです。

```.devcontainer/devcontainer.json
{
    "name": "My Dev Container",
    "dockerComposeFile": "docker-compose.yml",
    "service": "spring-boot-rest-api",
    "workspaceFolder": "/home/vscode/workspace",
    "shutdownAction": "stopCompose",
    "customizations": {
        "vscode": {
            "extensions": [
                "vscjava.vscode-java-pack",
                "vscjava.vscode-spring-initializr",
                "vscjava.vscode-gradle"
            ]
        }
    },
    "remoteUser": "vscode"
}
```

### docker-compose.yml 作成

```.devcontainer/docker-compose.yml
version: '3.9'

services:
  spring-boot-rest-api:
    container_name: rest-api
    build:
      context: ./docker/api
    tty: true
    volumes:
      - ../:/home/vscode/workspace:cache
    ports:
      - 8080:8080
```

※docker-compose.ymlでは、.envを利用したり args: を書いたりすると思いますが、できるだけ分かり易くするため利用していません。

### Dockerfile 作成

```.devcontainer/docker/api/Dockerfile
FROM ubuntu:22.04

SHELL ["/bin/bash", "-c"]

RUN apt-get update \
    && apt-get install -y sudo unzip zip vim tar less iputils-ping curl jq git

ARG USER_NAME=vscode
ARG USER_GROUP_NAME=vscode
ARG USER_UID=1000
ARG USER_GID=1000

RUN groupadd --gid ${USER_GID} ${USER_GROUP_NAME} \
    && useradd --uid ${USER_UID} --gid ${USER_GID} --shell /bin/bash --create-home -m ${USER_NAME} \
    && echo "${USER_GROUP_NAME}	ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers.d/${USER_GROUP_NAME} \
    && chmod 0440 /etc/sudoers.d/${USER_GROUP_NAME}

ARG JAVA_VERSION=17.0.9-amzn
ARG GRADLE_VERSION=7.5

ARG SDKMAN_DIR=/home/vscode/.sdkman

USER vscode
RUN curl -s "https://get.sdkman.io" | bash \
    && source ${SDKMAN_DIR}/bin/sdkman-init.sh \
    && sdk install java ${JAVA_VERSION} \
    && sdk install gradle ${GRADLE_VERSION}
```

※sdkmanの使い方については以下参照
https://sdkman.io/

### コンテナーでビルドして開く

コマンドパレット（Ctrl + Shift + P）から「Dev Containers: Rebuild and Reopen in Container」を実行してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/5f14dc3b-d656-bae3-502a-4fdda0350486.png)

### コンテナ起動したらjavaとgradleを確認
コンテナが無事起動すると以下イメージのようになるはずです。
新しいターミナルを開いて、`java -version`や`gradle -version`を実行して、インストールが成功していることを確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/d7c45b8f-faa7-6cc9-8914-4af5e6a7c259.png)

## Javaプロジェクト作成

コマンドパレット（Ctrl + Shift + P）から以下選択

### → Create Java Project を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/99d44567-345a-0a31-f196-cff7316245b4.png)

### → Spring Boot を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/40f90509-cb51-e0bc-d4bf-83322ae5743d.png)

### → Gradle Project を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/8038a15e-8157-eb38-5002-f01756731697.png)

### → Spring Bootのバージョン を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/987fcd1e-68ee-9123-02f7-762ff8cfb3ee.png)

### → Java を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/be07503b-0dbc-e254-1aee-6bf8ea987925.png)

### → リバースドメインネーム構造を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/961fe2c0-567f-50c4-8e86-d8ac2812313c.png)

### → プロジェクト名を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/d4a59ca8-701e-58a6-a1df-95d81352141d.png)

### → Jar を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/7ba89576-3206-cef1-b338-ef8afac80448.png)

### → Javaのバージョン を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/a03a8388-e97e-0836-5051-f021c9fab300.png)

### → 依存関係を選択 してEnter
- Spring Boot DevTools：開発時の便利なツール（ライブリロード、デバッグ支援など）
- Spring Web：RESTfulアプリケーションやWebアプリケーションの開発に必要

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/d42d3231-c1dd-ece1-c4af-c980e69c10de.png)

### → どこに作成するか場所を選択してEnter
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/3685e447-efb4-09be-4837-3eca56a1ee4b.png)

### 選択してきた通りに作成されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/4f46d567-bf2a-fcb2-d2b5-29666bb74ed2.png)

### ※左下の「JAVA PROJECTS」に作成したプロジェクトが表示されていなければ リロード
コマンドパレット（Ctrl + Shift + P）から「Developer: Reload Window」を実行してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/81ba1fc9-736f-b3d3-cded-088f3ed62ef0.png)

### Spring起動テスト

以下を参考にmain()メソッドがあるクラスを実行してSpringを起動してください。
Springのバナーが表示されたら成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/c420c7ea-1e0e-4b94-936b-126d744e4283.png)


## REST API のサンプルを作成して実行

コントローラを作成してcurlでアクセスしてみましょう。

### コントローラを作成してエンドポイント準備


```controllers/DemoController.java
package com.example.demo.controllers;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class DemoController {

    @GetMapping("/demodemo")
    public Map<String, String> getDemo() {
        return Map.of("msg", "こんにちは。");
    }
}

```

コントローラが書けたら、右上のあたりの「再起動」や「実行」をクリックしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620310/5a9e3156-b07e-321d-ea67-018b70b70d3a.png)

### curlで作成したAPIへアクセス

ターミナルからcurlでアクセスして、json形式のレスポンスが返ってきたら成功です。

```
vscode@0be55cf0621f:~/workspace$ curl -s -X GET http://localhost:8080/demodemo | jq .
{
  "msg": "こんにちは。"
}
```

## 最後に

お疲れさまでした！
Javaの開発環境もdockerを使って簡単にコンテナ化することが出来ました。

昔は人によってプログラムの動きが違ったり、なかなか動いてくれなかったり多々ありましたが、
便利な環境になりましたね。

以上で終わりです。誰かの一助となれれば幸いです。