VSCode内の統合ターミナルから、Docker内でアプリを実行するために使った力技

# 2019年8月21日 追記
この記事の内容は古く、大きく遠回りしています。
読む必要はありません。

VSCodeのリモートデベロップメントを使おう。
https://code.visualstudio.com/docs/remote/remote-overview

ボクはリモートデベロップメント（linux vm）を使っていますが、快適です。


# はじめに
Windows上にVMを立て、
VM上のDockerコンテナでアプリケーションを実行させているのですが、
・毎回dockerイメージをビルドするのも面倒くさい。
・Windows上で編集したファイルをLinuxにコピーするのも面倒くさい。
・Windows上のVMだから、F1からのタスクが定義できなくて実行が面倒くさい。
・毎回docker runとか叩きたくない。

といった悩みがありました。
私なりに解決策を考えてみたので、
誰かの役に立てばと思います。

# WindowsとLinuxのファイルコピーが面倒くさい。
WindowsとLinuxでファイル共有する方法は沢山あると思います。

```
WinSCPを使う。
　→いちいちSyncされているかを意識しなければいけないのが面倒かと思った
　（実際意識する必要はないかもです。あんまり触ってないです。いい加減ですね。。。）

Linux上にSambaを立てちゃう。
　→SambaはSambaで、ファイル作成時の権限の設定してあげないといけなかったり、
　 SambaのユーザとLinuxのユーザーをマッピングしなければいけなかったりと、
　 複雑化しそうなので手を出したくなくなった。

vagrantとVirtualBoxでファイル共有設定しちゃう。
  →guest additionが入らないことがよくあったので、避けた
```

色々理由をつけて避けましたが、
私が選んだのはコレでした。

**dokany+win-sshfs**
https://github.com/masaeedu/win-sshfs
https://github.com/dokan-dev/dokany
※Dokanのバージョンは。1.1.0.2000にすること。
　GUI版もあるので、その場合は、他の型のQiitaの記事を参考に、インストールするといいと思います。

なんとSSHの接続先に、ドライブレターを割り当て、
ファイルシステムとして操作することができます！
![sshfsでマウントしたあと.png](https://qiita-image-store.s3.amazonaws.com/0/228730/44ea8acc-bb2a-ab9c-66c3-1170e93ac798.png)

# dockerイメージを毎回ビルドしないとアプリが実行できない
pythonやruby等のインタプリタ言語を書いているとき、
dockerイメージをビルド→docker runで実行という流れでやってしまっており、
インタプリタ言語の利点を殺してしまっていると感じました。

そこで、

・dockerホストと、コンテナでディスク共有してしまえばいいじゃないか？
　コードの編集はdockerホスト上で、
　コードの実行は、コンテナの中から実行すればいいんじゃないのか？

・開発中のコンテナはアプリを包まずベースとして定義。
　リリース用のコンテナは、別で定義できないかな？

と考えました。

まず、**コンテナとdockerホストで、ディスク共有ですが、
-vオプションを使えば簡単にできます。
・・・が、そんな長いコマンドは打ってられないし、覚えてられないので、
makefileにタスクを切っておきます。**

```makefile:makefile抜粋
RELEASE_CONTAINER := hogehoge
BASE_CONTAINER := $(RELEASE_CONTAINER)-base
APP_ROOT := /app
CONTAINER_APP_ROOT := /app
MAIN_APPLICATION := entrypoint.sh

# ベースのコンテナは、頻繁に利用、更新されると思ったので、
# 先頭に定義して「make」だけで実行するようにした。
commit: var
	docker image build -t $(BASE_CONTAINER) \
	--target base \
	.

# 試行錯誤中、コンテナの中に入りたいときは沢山ある。
# なんで「make shell」でコンテナの中に入るタスクを定義
shell: var
	docker container run -ti \
	--network host \
	-v $(ROOT_DIR)$(APP_ROOT):$(CONTAINER_APP_ROOT) \
	--rm $(BASE_CONTAINER) \
	/bin/sh 

# いちいち /app/entorypoint.shをコンテナの中で実行するのは面倒なので、
# これも「make run」でタスクをていぎ
run: var
	docker container run -ti \
	--network host \
	-v $(ROOT_DIR)$(APP_ROOT):$(CONTAINER_APP_ROOT) \
	--rm $(BASE_CONTAINER) \
	/app/entrypoint.sh

# リリース用のコンテナを作る定義
release: var
	docker image build -t $(RELEASE_CONTAINER) \
	--target release \
	.

var:
	$(eval ROOT_DIR := $(shell pwd))

```

次に、**ベースのコンテナと、リリース用のコンテナを分けるため、
マルチステージビルドをDockerfile上に定義**

```docker:Dockerfile
FROM alpine:latest as base

RUN apk add python3
RUN pip3 install --upgrade pip
COPY /app/requirements.txt /requirements.txt
RUN pip3 install -r /requirements.txt

FROM base as release
COPY /app /app
ENTRYPOINT ["/app/entrypoint.sh"]
```
　
　
　
　
マルチステージビルドと、dockerの-vオプション、
makefileを駆使すれば、それなりに使いやすくなり、
以下のような形でコンテナへのアクセスが楽になった。

```shell_session
[root@localhost hogehoge]# make shell
docker container run -ti \
--network host \
-v /home/hoge_user/develop/hogehoge/app:/app \
--rm hogehoge-base \
/bin/sh
/ #
```

# VSCodeからmakefileで定義したタスクが実行できない。
SSH接続先のmakefileをいい感じに実行できる。
そんな楽なものは見つけることができなかった。


なので、VSCodeの拡張を導入し、
統合ターミナル上ですぐにSSHログインできるようにし、
makeを単純に実行することにした。

そこで利用したのが、
**SSHExtention**
https://github.com/VitalyKondratiev/vscode-sshextension


こんな感じでコンフィグを書いておくと、F1から簡単にSSHログインできる。

```
    "sshextension.serverList": [
        {
            "name": "hogehogevm",
            "host": "192.168.56.100",
            "port": 22,
            "username": "root",
            "privateKey": "C:\\Users\\hoge_user\\develop\\keys\\id_rsa",
            "path": "/develop"
        },
    ],
    "sshextension.openProjectCatalog": true
```

### 終わりに
ここまでやったことによって

```
①VSCodeからSSHFSでマウントした先をディレクトリとして開く
②コードを編集
③F1からSSHでVM接続へのショートカットを呼び出し→SSHでVMにログイン
④VMの中でmake run実行
```
という流れで編集～コード実行までできるようになった。