VSCodeとリモートDockerを利用した、シンクライアントな開発環境の構築

この記事は[SFC-RG Advent Calendar 2019][0]の11日目です。

##Docker使っていますか？

Docker便利ですよね。仮想環境より遥かに低コストで、プロジェクト単位で開発環境を用意できるので、ホスト環境が次第に汚れていく不快感から永遠にオサラバすることができます。

一方、DockerデーモンはLinuxでしか動かない為、macやWindowsでDockerを使う場合はDockerデーモンを動かす為に仮想環境が必要となり、意外とリソースを消費してしまいます。

Visual Studio Code(以降VSCode)では、拡張機能の一つであるRemote Developmentを使うことで、コンテナを開発環境として利用することが可能です。

これにはdockerコマンドを用いているため、Docker Remote APIを使ってリモートのコンテナも開発環境として利用することが出来ます。

##Dockerをサーバーで動かす

- メリット
    - 非力なノートパソコンでもDockerを快適に利用可能
    - クライアントが変わっても作業を継続可能
    - **自宅で暇しているサーバーに仕事を与えられる**
    - ~~話題のシンクライアント~~
- デメリット
    - 最初の準備がやや大変
    - オフラインでは作業不可
    - **自宅にサーバーが無い場合は別途用意する必要がある**

##検証に用いた環境

- サーバー
    - Ubuntu 19.04
        - Docker Engine - Community version 19.03.4
- クライアント
    - Windows 10 Pro version 1909
        - Docker Client version 19.09.0-dev (自分でソースからビルド)
    - macOS Catalina version 10.15.1

他ソフトウェア、拡張機能は2019年12月時点での最新安定板を利用

##必要なもの

###サーバー側

- Docker

###クライアント側

- Docker client
- Visual Studio Code

##サーバーでの準備
サーバーでDockerデーモンを動かし、これをDocker Remote APIでクライアントから扱うには、Dockerデーモンのソケットをネットワークに露出させる必要があります。

Dockerデーモンへのアクセス権はroot権限を意味する為、セキュリティの観点からTLSを用いた認証、暗号化が必須です。

[別記事][1]を用意したのでそちらに従うか、[公式ドキュメント][2]を参考にDockerデーモンにTLSを使ったTCP接続が出来るようにしてください。

##クライアントでの準備

###dockerコマンドのインストールと設定

クライアントにはDockerデーモンを入れる必要はありませんが、Dockerクライアントはインストールし、接続先を指定する必要があります。

UbuntuやmacOSではパッケージマネージャーを用いてDockerクライアントのみのインストールが可能です。

Windowsの場合は[公式からの安定版のバイナリ配布][5]が17.09.0で止まっており、これはVSCodeでは動かない為、自分で公式ソースからバイナリをビルドして適当な場所に配置し、パスを通す必要があります。

詳細手順はこちらも[別記事][3]を用意したのでこちらに従ってください。

###Visual Studio Codeのインストールと設定

リモートコンテナへの接続は[VSCode公式][4]でも言及がなされています。

VSCodeをインストールした後、Remote Development拡張機能を追加します。
また、Docker拡張機能も、リモートのコンテナを直接管理出来て便利なので追加します。

Docker拡張機能はそれ自体がDocker Remote APIを利用するため、VSCodeの設定ファイルに下記1行を追記してください。

```json:settings.json
{
	"~省略~",
	"docker.certPath": "~Dockerデーモンへの接続に必要な認証ファイルを置いたディレクトリへの絶対パス~"
}
```

VSCodeのDockerタブからリモートのコンテナやイメージ等が見れるようになれば準備完了です。

##使用例

以降クライアントでVSCodeのみを操作します。サーバーでの操作は一切必要ありません。

###作業ディレクトリを開く

適当な場所に作業ディレクトリを作って開きます。ディレクトリ名はDockerイメージ名に使われるので、プロジェクト名にでもしておくと便利です。

###開発コンテナ設定ファイルを作る

VSCodeではdevcontainer.jsonという独自のファイルで開発環境とするコンテナの設定を記述します。

公式で既に非常に多くのテンプレートが用意されているので、これにリモート用の設定を追記するのが簡単です。

ウィンドウ左下の緑のボタンから```Remote-Containers: Add Development Container Configuration Files...```を選ぶことでdevcontainer.jsonが生成されるので、これに下記2行を追記します。

```json:devcontainer.json
{
	"~省略~",
	"workspaceMount": "src=remote-workspace,dst=/workspace,type=volume,volume-driver=local",
	"workspaceFolder": "/workspace"
}
```

上記の設定文中の```remote-workspace```はプロジェクトファイルを保存することになるボリューム名ですので、プロジェクト名に置き換えるなど、一意性を保てるように適宜変更してください。

コンテナは永続性の必要なデータを置く場所ではない[^1]ので、上記設定を追加することでボリュームに保存するようにします。

勿論ボリュームも通常のディレクトリと同じく、絶対的な永続性を保証する機能ではない事には注意してください。

###開発コンテナに接続する

設定ファイルが用意出来たら後は接続するだけです。

ウィンドウ左下の緑のボタンから```Remote-Containers: Reopen in Container```を選べば、VSCodeが設定ファイルを元にコンテナの作成、実行、接続を自動で行ってくれます。

初回実行時はイメージのビルドも行うため暫く時間がかかりますが、2回目以降はより高速に接続が完了します。

接続後はローカルでの開発と変わらない使い勝手でリモート上にプロジェクトファイルを展開していくことができます。

###他のクライアントから接続する

設定ファイルのある作業ディレクトリを丸ごとコピーしてきて、```Remote-Containers: Open Folder in Container...```を実行するだけです。

##参考文献

DockerデーモンへTCP接続をする方法
[Protect the Docker daemon socket][2]
VSCodeからリモートのコンテナを利用する方法
[Developing inside a container on a remote Docker host][4]

[^1]: コンテナとボリュームの関係についての概要は[こちらの記事][6]がわかりやすいです。この記事で作るボリュームはDockerの管理するボリュームの事です。

[0]:https://qiita.com/advent-calendar/2019/sfc-rg
[1]:https://qiita.com/negineri/items/0978f5e72e46570c8be0
[2]:https://docs.docker.com/engine/security/https/
[3]:https://qiita.com/negineri/items/7947eda8a0ad6b8668a1
[4]:https://code.visualstudio.com/docs/remote/containers-advanced#_developing-inside-a-container-on-a-remote-docker-host
[5]:https://download.docker.com/win/static/stable/x86_64/
[6]:https://qiita.com/gounx2/items/23b0dc8b8b95cc629f32