【Docker + Java】開発環境事始め【暖かい部屋で作業したい】

まだまだ寒い冬が続きます。
高性能なデスクトップPCが自室にあるけど寒すぎる！暖かいリビングで開発したい！でもノートPCはオンボロ！
…ということでデスクトップPCに開発環境を用意して、ノートPCからアクセスして開発する方法を書き記します。

# 取り扱うこと
- Dockerを用いたJava開発用サーバの構築
- SSHサーバの構築とクライアント端末からの接続

# 開発環境
サーバPCのOSは Windows11で、DockerDesktopを使っています。
クライアントPCのOSはmacOS13で、VSCodeを使用します。
サーバPCとクライアントPCは同一ネットワークにあることを前提とします。

# 事前準備
## Docker Imageの用意
開発する言語のパッケージを含むDockerイメージを選定します。
私の場合、Springbootを使いたかったのでDockerHubから `gradle:8.12.0-jdk23` を選択しました。
- `gradle:8.12.0-jdk23` の[Dockerfile](https://github.com/keeganwitt/docker-gradle/blob/85f69576482f57c9f9ef203a16059f4fafc0f33f/jdk23/Dockerfile) を見てみと `eclipse-temurin:23-jdk-noble` をベースとしており、さらに `eclipse-temurin:23-jdk-noble` の[Dockerfile](https://github.com/adoptium/containers/blob/d7a5038edcd8ab08b0babaeae09d0c097453a023/23/jdk/ubuntu/noble/Dockerfile)を見てみると `ubuntu`をベースとしていることがわかります
- Amazon Linuxをベースとした `8.12.0-jdk23-corretto` も用意されているようなので、RedHat系のディストリビューションが好きな方はこちらを選ぶのもいいと思います

## SSH公開鍵の譲渡
クライアント端末でSSH用の公開鍵を生成します。
`ssh-keygen -t rsa` を実行すると、特に名前を変えない限り `id_rsa.pub` と `id_rsa` が生成されるので、ファイルサーバなりUSBメモリなり使って `id_rsa.pub` をサーバ側に渡しておきます。

## ディレクトリ構成
サーバ側のディレクトリ構成は以下の通りです。
app以下のものについては[Spring Initializr](https://start.spring.io/)で生成されたものを丸ごとコピペしています。
上記で受け取った公開鍵はDockerfileと同じ階層に配置しておくと後々便利です。
```
プロジェクトルート/
├── app/ # 以下、Spring Initializrで生成されたもの
│   ├── build/
│   ├── gradle/
│   ├── src/
│   ├── build.gradle
│   ├── gradlew
│   ├── gradle.bat
│   ├── HELP.md
│   └── setting.gradle
├── Dockerfile # 下記で説明します
├── id_rsa.pub # 上記手順で受け取ったもの
└── .gitignore
```

# サーバ側の設定
## Dockerfile
Dockerfileは次の通りです。
```Dockerfile
FROM gradle:8.12.0-jdk23

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:root123' | chpasswd # パスワードを設定していますが下で無効化しています

# パスワードログインを禁止します
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
# ポートを2222に変更します
RUN sed -i 's/#Port 22/Port 2222/' /etc/ssh/sshd_config
# 公開鍵を登録します
COPY ./id_rsa.pub /root/.ssh/authorized_keys

EXPOSE 2222

CMD ["/usr/sbin/sshd", "-D"]
```

## コンテナ起動
以下の手順でコンテナを起動します。docker-composeを作ってしまってもいいですが、それほどオプションが多くなかったのでコマンドにしました。
PowerShellでプロジェクトルートまで移動し、次のコマンドを実行します。
```bash
$ docker build ./ -t java-sandbox-gradle
$ docker run -p 2222:2222 -v /<プロジェクトルートまでの絶対パス>/app:/app -itd java-sandbox-gradle
```

## IPの取得
クライアントから接続するためにipconfigなどでローカルIPを確認しておきます。

# クライアント側の設定
## VSCode拡張のインストール
VSCodeを開いて、拡張機能から `Remote-SSH` をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193782/0cc9d00f-fa35-6976-0074-bd057f36650a.png)


## SSHで接続
画面左下の「><」のようなアイコンをクリックすると、モーダルが降りてくるので、「ホストに接続」（または「Connect to Host...」）をクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193782/4dc2b168-fef1-d2de-821c-9a289f2b758a.png)

「新規SSHホストを追加する...」をクリックすると入力欄が出てくるので、先ほど取得したサーバ端末のIPを以下の通り入力します
```bash
ssh root@<サーバ端末のIP> -p 2222
```

すると接続シーケンスが開始されて、しばらくすると「SSHキーのパスフレーズを入力してください」と出るので、`ssh-keygen`で登録したパスフレーズを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193782/ef6538b8-a9ff-9dea-60cd-ea9b05ada11f.png)

接続が完了するとこのような画面になり、「フォルダーを開く」を押すとマウントされたサーバ側の開発環境（/app配下）が表示されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193782/903dfa6e-2436-94bf-a586-4f4845b877f0.png)


以上です！


次は外部ネットワークからアクセスするのもやりたいなぁ