WindowsでもLinux上でVSCodeで開発したい！code-serverをカスタマイズしてDockerで立てる

※対象環境はWindows10 Profesional以降
## TL;DR
* WSL ではまだ動かない
* ネットワーク周りとSSHキー周りがめんどくさい
* volume でマウントしたディレクトリにシンボリックリンクが張れないのでこれまためんどい

## きっかけ
先日とある記事[^1] を読み、code-serverに興味が出ました。
ちょうど最近Windowsの開発バージョンを上げたところ、シンタックスチェック等が効かなくなってしまって、環境を変えたいなと思ってた矢先だったので環境構築してみようと思いました。
[^1]: [ブラウザでVS codeが使えるクラウド IDEの大本命「Coder」](https://qiita.com/MegaBlackLabel/items/bbec97db769667962bce)

## 成果物

[リポジトリ](https://github.com/Mushus/code-server-env)作りました
詳しくはこちらを見ていただけたらと思います。

## 予め試したこと

### WSLで動かしてみる

結論から言うとだめでした。[^2]
[^2]: [こちらのissue](https://github.com/codercom/code-server/issues/11)に書いてある
どうやらバイナリのパッケージ化方法に問題があるらしい？自分でビルドしてみたら動くかもしれないがそこまでの気力がなかったので待ち。
ならばDockerでやってみるかという運びに。

## 検証

[公式のリポジトリ](https://github.com/Mushus/code-server-env)を見るとすでにDockerでの立ち上げ方の記載がありますのでそれをベースとしてやっていきます。

こちらが公式の立ち上げ手順。

```bash:公式に記載されているDockerでの試用手順
docker run -p 127.0.0.1:8443:8443 -v "${PWD}:/root/project" codercom/code-server code-server --allow-http --no-auth
```

公式の方法はあくまでお試しの方法で、dockerコンテナを落とすと作業した内容が全て闇に葬り去られます。
例えば、

* ~~編集していたファイル~~ 【追記】ファイルにvオプションついてて問題なしです
* 導入したソフトウェア
* 導入した拡張機能

とか。

今回はそこを解消していこうと思います。

## 環境構築

code-server公式が出している[Dockerイメージ](https://hub.docker.com/r/codercom/code-server)をベースに拡張していきます。

以下の方針[^3]でDockerfile化します。

* 拡張機能は vscode で導入する
* 必要なソフトウェアは予めビルドしてイメージ化する

[^3]: こちらの記事の手順を参考にしました。[code-server で実現する Windows 上で Linux 向けの快適な Go 開発環境 - 誰かの役に立てばいいブログ](https://ymmt.hatenablog.com/entry/2019/03/07/183110)
解説するDockerfile:

``` Dockerfile:Dockerfile
FROM codercom/code-server

WORKDIR /root
# install dependency
RUN apt-get update \
 && apt-get install -y \
    libx11-xcb1 \
    libasound2 \
    curl \
    gnupg2 \
    git \
    python \
    g++ \
    gcc \
    libc6-dev \
    make \
    pkg-config \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

# install vscode
RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \
 && install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ \
 && rm microsoft.gpg \
 && sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' \
 && apt-get update \
 && apt-get install -y code \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

COPY scripts /usr/local/bin
COPY extensions.txt /root

...(中略)...

# Install vscode extensions
RUN install-extensions.sh

COPY settings.json /root/.code-server/User/settings.json

WORKDIR /root/project

CMD ["entrypoint.sh"]
```

ちなみに中略のところで Golang と Node を入れています。

### VSCodeを入れる


VSCode を導入していきます。
ベースにしたイメージでは `apt-get` が使用できますので、それを使ってインストールしていきます。[^4]

```Dockerfile:Dockerfileの一部
# install vscode
RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg \
 && install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ \
 && rm microsoft.gpg \
 && sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' \
 && apt-get update \
 && apt-get install -y code \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
```

[^4]: こちらの記事を参考にしました。[Ubuntu / DebianにコマンドでVSCode (Visual Studio Code) をインストールする方法 | カレリエ](https://www.karelie.net/ubuntu-debian-command-install-vscode/)
また、VSCode を立ち上げるのにいくつかライブラリが必要でしたので事前に入れておきます。

```Dockerfile:Dockerfileの一部
RUN apt-get update \
 && apt-get install -y \
    libx11-xcb1 \
    libasound2 \
```

これで code コマンドを使用する準備が整いました。
次に拡張機能のインストールをしていきます。

### VSCode の拡張機能をインストールする

拡張機能のインストールはコマンドで行います。

先程インストールした `code` コマンドで拡張機能をインストールできます。

```bash:拡張機能をインストールするコマンド
$ code --user-data-dir --extensions-dir /root/.code-server/extensions --install-extension [Extension-ID]
```

* `--user-data-dir` は root ユーザーで `code` コマンドを実行するとエラーが出るため入れています。
* `--extensions-dir /root/.code-server/extensions` は `code-server` の拡張機能のディレクトリに合わせています

Dockerfile では extension.txt に記載した拡張機能をインストールするように以下のコマンドを実行しています。管理を楽にしたいっていうちょっとしたオシャレです。

```sh:install-extensions.sh
#!/bin/sh

grep -v -e '^\s*#' -e '^\s*$' /root/extensions.txt | awk '{system("code --user-data-dir --extensions-dir /root/.code-server/extensions --install-extension "$1)}'

```

ちなみに extension.txt はこの様になっています。

```:extension.txt
# Editor View
akamud.vscode-theme-onedark
gruntfuggly.activitusbar
emmanuelbeziat.vscode-great-icons

# Edit field
shardulm94.trailing-spaces
coenraads.bracket-pair-colorizer
wayou.vscode-todo-highlight

# Input support
formulahendry.auto-close-tag
formulahendry.auto-rename-tag

# Node
dbaeumer.vscode-eslint

# Golang
ms-vscode.go

# Language pack
ms-ceintl.vscode-language-pack-ja

#
editorconfig.editorconfig
formulahendry.terminal

```

気になる拡張機能があればこちらからガンガン追加していきます。

### テーマを反映する

このままだとテーマが反映されません。
なので設定ファイル settings.json も Dockerfile で追加します。

```Dockerfile:Dockerfileの一部
COPY settings.json /root/.code-server/User/settings.json
```

```json:settings.json
{
    "workbench.iconTheme": "vscode-great-icons",
    "workbench.colorTheme": "Atom One Dark"
}
```

次に code-server　を立ち上げるよう追加します。

### code-server を立ち上げる

あとは code-server コマンドを実行すればいいだけなのですが、何もせずに `docker run` するだけだといくらか問題があります。

* 不正な証明書でブラウザにブロックされる
* パスワードをいちいち入力する必要がある

なので、code-server 公式に書いてあるものと同じオプションで立ち上げます。

```sh:ebtrypoint.sh
#!/bin/sh

code-server --allow-http --no-auth /root/project
```

まぁローカルで使う前提なら認証もhttpsも不要でしょう。

ちなみに `code-server` コマンドには以下のオプションが存在します。

```:code-serverのオプション
$ code-server --help
Start your own self-hosted browser-accessible VS Code

USAGE
  $ server [WORKDIR]

ARGUMENTS
  WORKDIR  [default: /root/project] Specify working dir

OPTIONS
  -d, --data-dir=data-dir
  -h, --host=host          [default: 0.0.0.0]
  -o, --open               Open in browser on startup
  -p, --port=port          [default: 8443] Port to bind on
  -v, --version            show CLI version
  --allow-http
  --cert=cert
  --cert-key=cert-key
  --help                   show CLI help
  --no-auth
  --password=password
```

### docker-compose.yml を書いて毎回長いコマンドを打たなくて良くする

`docker` コマンドの長ったらしい引数を毎回実行したくないです。省略したいです。
なのでサービスは一つしかありませんが、docker-compose を使用して立ち上げます。

```yml:docker-compose.yml
version: '2'
services:
  code-server:
    build: .
    container_name: code-server
    ports:
      - "8443:8443"
    volumes:
      - "./workspace:/root/project"
```

プロジェクトルートとして workspace をマウントするように設定しました。

とても簡潔です。
あとは docker-compose で立ち上がります。

### code-server を立ち上げる

以下のコマンドを実行します。

```bash
$ docker-compose up -d
```

その後、`http://localhost:8443` を確認します。
ということで立ち上がりました！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/42309/955ac08d-4e43-bbf3-e314-b8dff178c96b.png)

## 課題

いくらか問題点があります。どうしようか考え中です。

* sshキーは永続化してない。毎回設定しないと `git` が使えない。
    * リモートの url を `https://xxx.git` して逃げる？
* ポートを 8443 しか開けてないので開発が辛い。
    * IPアドレスでつないだりして軽く調べた感じやりようはありそう。
* volume でマウントした共有ディレクトリにシンボリックリンクが使用できない。nodeの開発で問題あり。
    * 名前付きボリュームで解消できなくはない。Windowsで使うならさらにSMBか…
* 一部右クリックでコンテキストメニュが出たりする。かなしい。
* 言語が日本語にできなかった。
    * `LANG=ja_JP.UTF-8` してもだめだった。VSCodeの言語を変えてみたがだめ、八方塞がり。

## おわりに

ということでカスタマイズする方法を解説させていただきました。
dotfileチックに設定を git にまとめられそうですね。

課題等でいい案がありましたら教えていただきたいです。