Proxy環境で VS Code Remote Development + Java開発をさせてくれ

こん**は。

突然ですが、VS Code で しかも実行環境はコンテナで Java、開発したいですよね。
でも邪魔してくるやつが居ますよね。そう Proxy です。

社内Proxyの場合企業ごとに状況が異なると思いますが、うまくいった例としてすこしでもあなた様の参考になれば……。

# :muscle: モチベーション

- Proxy 環境下で Docker を利用した VS Code の Remote Development をしたい！
- いろんなレイヤからプロキシの設定を求められる……:japanese_ogre:
- プロキシに悩める人に、少しでもヒントとなれば！

# :computer: 動作確認環境（ホスト）

- OS
    * Windows 10
- Docker
    * Docker for Windows
- VS Code
    * 1.46.0

# :hand_splayed: 前提

* VS Code と Docker for Windows がインストールされていること
* Docker for Windows のプロキシ設定は既に完了していること

# :file_folder: 用意するファイルたち

## Dockerfile

Remote Development 環境の `Dockerfile` はこちら。

```Dockerfile:${workspaceFolder}/.devcontainer/Dockerfile
FROM adoptopenjdk/openjdk11:jdk-11.0.7_10-centos

# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
# will be updated to match your local UID/GID (when using the dockerFile property).
# See https://aka.ms/vscode-remote/containers/non-root-user for details.
ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=${USER_UID}

ARG MAVEN_VERSION=3.6.1
ARG MAVEN_SHA=b4880fb7a3d81edd190a029440cdf17f308621af68475a4fe976296e71ff4a4b546dd6d8a58aaafba334d309cc11e638c52808a4b0e818fc0fd544226d952544

# プロキシ設定
# devcontainer.json で指定する
# see https://code.visualstudio.com/docs/remote/containers-advanced#_option-2-use-an-env-file
ARG PROXY=${PROXY}
ENV http_proxy=${PROXY}
ENV https_proxy=${PROXY}
ENV HTTP_PROXY=${PROXY}
ENV HTTPS_PROXY=${PROXY}

RUN echo "building..." \
    #
    # Create a non-root user to use if preferred
    # see https://aka.ms/vscode-remote/containers/non-root-user.
    && groupadd --gid ${USER_GID} ${USERNAME} \
    && useradd -s /bin/bash --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME} \
    #
    # Install Maven
    && mkdir -p /usr/share/maven /usr/share/maven/ref \
    && curl -fsSL -o /tmp/apache-maven.tar.gz https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
    && echo "${MAVEN_SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \
    && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
    && rm -f /tmp/apache-maven.tar.gz \
    && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn \
    #
    # Maven User Settings
    # /home/vscode/.m2/ を作成し、vscode ユーザに所有者変更
    && mkdir /home/${USERNAME}/.m2 \
    && chown -R ${USERNAME}:${USERNAME} /home/${USERNAME}/.m2

# Maven パス設定
ENV MAVEN_HOME /usr/share/maven
```

開発に `Maven` を利用しているので、 `Maven` をインストールしています。
また、本番実行環境が `CentOS 7` 系のため、Remote Development 環境も `CentOS 7` 系 + Java をベースイメージとして使っています。

`${PROXY}` とありますが、こちらは後述する `devcontainer.json` からイメージビルド時に渡してしまいます。
ビルド時にイメージに埋め込むのはちょっと…とは思いましたが、まあ各人の開発環境でイメージを直接共有する予定もないので、この状態でも問題ないと判断しました。

## devcontainer.json

続いて、Remote Development 環境の設定ファイルである `devcontainer.json` です。

```json-doc:${workspaceFolder}/.devcontainer/devcontainer.json
{
  "name": "Sample Project",
  "dockerFile": "Dockerfile",

  // docker build（イメージ作成）時の設定
  // see - https://github.com/microsoft/vscode-remote-release/issues/46
  "build": {
    "args": {
      // TODO: 環境に合わせて記載
      "PROXY": "http://USER:PASS@HOST:PORT"
    }
  },

  // コンテナ作成時の VS Code のデフォルト設定値（ワークスペースの設定が勝つため注意）
  "settings": { 
    "terminal.integrated.shell.linux": "/bin/bash",
    "java.home": "/opt/java/openjdk",
    // Language Server
    // see - https://github.com/redhat-developer/vscode-java/wiki/Using-a-Proxy
    // TODO: 環境に合わせて記載
    "java.jdt.ls.vmargs": "-Dhttp.proxyHost=HOST -Dhttp.proxyPort=PORT -Dhttp.proxyUser=USER -Dhttp.proxyPassword=PASS -Dhttps.proxyHost=HOST -Dhttps.proxyPort=PORT -Dhttps.proxyUser=USER -Dhttps.proxyPassword=PASS",
    // see - https://github.com/redhat-developer/vscode-java/issues/399#issuecomment-355113311
    "java.import.gradle.enabled": false
  },

  // コンテナ作成時にインストールされる VS Code 拡張（IDで指定）
  "extensions": [
    // Java
    "vscjava.vscode-java-pack",  // Java Extension Pack
  ],

  // コンテナ作成後に実行されるコマンド
  "postCreateCommand": "./.devcontainer/postCreateCommand.sh",

  // Use 'forwardPorts' to make a list of ports inside the container available locally.
  "forwardPorts": [
    8090 // app
  ],

  // Dockerコンテナログインユーザ
  "remoteUser": "vscode",
}
```

ポイントは `settings` の `java.jdt.ls.vmargs` です。
↓ のページにあるとおり、 `Java Language Server` に対して PROXY を設定してあげる必要があるようです。

[Using a Proxy - redhat-developer/vscode-java - GitHub](https://github.com/redhat-developer/vscode-java/wiki/Using-a-Proxy)

## Maven 設定ファイル

Maven は Maven で Proxy の設定を行います。

自分はこれらのファイルを `.devcontainer` フォルダ内に置きました。
後述するシェルで `vscode` ユーザホーム直下の `.m2 フォルダ`（`/home/vscode/.m2`）にコピーします。

```xml:settings.xml
<proxies>
  <proxy>
    <!-- TODO: 環境に合わせて記載 -->
    <id>sample</id>
    <active>true</active>
    <protocol>http</protocol>
    <host>proxy.sample.com</host>
    <port>1234</port>
    <username>user</username>
    <password>{encrypted-password=}</password>
    <nonProxyHosts>localhost</nonProxyHosts>
  </proxy>
</proxies>
```

```xml:settings-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<settingsSecurity>
    <!-- TODO: 環境に合わせて記載 -->
    <master>{encrypted-master-password=}</master>
</settingsSecurity>
```

参考：[Password Encryption - Maven](https://maven.apache.org/guides/mini/guide-encryption.html)

※ ここはもう少しなんとかしたかった…ができませんでした。環境依存でうまくパスワード類を埋めてやりたかったのですが……。うまい方法をご存じの方はぜひコメントでご指摘いただけると……。

## シェル

```sh:${workspaceFolder}/.devcontainer/postCreateCommand.sh
#!/usr/bin/bash

# 初期処理
echo ''
echo '--------------------------------------------'
echo ' Init'
echo '--------------------------------------------'
# 設定・基本情報
MAVEN_SETTING_DEST=`realpath ~/.m2/`
echo '基本情報'
echo "作業ディレクトリ: `pwd`"
echo "maven: `mvn --version`"

# Mavenの設定ファイルをコピー
echo ''
echo '--------------------------------------------'
echo ' Copy Maven settings files'
echo '--------------------------------------------'
echo 'コピーを開始します。'
cp ./.devcontainer/settings.xml ./.devcontainer/settings-security.xml ${MAVEN_SETTING_DEST}
echo 'コピーが完了しました。'
ls -la ${MAVEN_SETTING_DEST}

# 終了処理
echo ''
echo '--------------------------------------------'
echo ' Exit'
echo '--------------------------------------------'
echo '処理を終了します。'
exit 0
```

`.devcontainer/devcontainer.json` の `postCreateCommand` で指定しているシェルです。コンテナ作成後に叩かれます。

内容としては、Maven 設定ファイルたちを `vscode` ユーザホーム直下の `.m2 フォルダ`（`/home/vscode/.m2`）にコピーして差し上げております。
これだけだったらシェルに切り出さずに `devcontainer.json` の `postCreateCommand` に直接書けばいいと思いますが……:angel: 

# :rocket: 起動する

あとは普通に起動してあげるだけ！
本筋とはズレるので詳細は割愛しますが、ざっくりと…

- VS Code の [Remote - Containers](vscode:extension/ms-vscode-remote.remote-containers) 拡張をインストールし、
- Docker を起動して
- VS Codeが「ここコンテナで開けそうだよ？」って聞いてくるので `Reopen in Container`

ですね！

このとき `.devcontainer` フォルダが VS Code ワークスペースのルートフォルダ直下にある必要がありそうです。

# :end: 終わりに

ちなみに…自分はマシンのスペックが足らず、最終的にこの方式での開発は諦めました :angel:
が、環境構築が一気にしやすくなりめっちゃ便利だと思うので、スペックに問題なければぜひ前向きに検討すべきと思います！

Proxy 環境下 + VS Code Remote Development + Java な人に、少しでも力なっていれば幸いです。

それでは！

# :link: リンク

- [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview)
- [Using a Proxy - redhat-developer/vscode-java - GitHub](https://github.com/redhat-developer/vscode-java/wiki/Using-a-Proxy)
- [Password Encryption - Maven](https://maven.apache.org/guides/mini/guide-encryption.html)
- [【2020年1月】令和だし本格的にVSCodeのRemote Containerで、爆速の"開発コンテナ"始めよう](https://qiita.com/koinori/items/084a0770c1f9e72e0c14)